Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update types filter according to import declarations #2474

Merged
merged 5 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2016-2022 Red Hat Inc. and others.
* Copyright (c) 2016-2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
Expand All @@ -13,9 +13,9 @@
package org.eclipse.jdt.ls.core.internal.contentassist;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand All @@ -32,7 +32,6 @@
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
Expand Down Expand Up @@ -69,22 +68,6 @@ public final class CompletionProposalRequestor extends CompletionRequestor {
private boolean isComplete = true;
private PreferenceManager preferenceManager;
private CompletionProposalReplacementProvider proposalProvider;
/**
* stores all the imported types from static imports and single type import declarations.
* For example:
* <ul>
* <li>import java.awt.List; -> java.awt.List</li>
* <li>import static java.awt.List.*; -> java.awt.List</li>
* <li>import static java.awt.List.ERROR; -> java.awt.List</li>
* </ul>
*/
private Set<String> importedTypes = new HashSet<>();
/**
* stores all the imported package or type names from an on demand import declaration.
* For example:
* import java.awt.*; -> java.awt
*/
private Set<String> onDemandImportedPackagesOrTypes = new HashSet<>();

static class ProposalComparator implements Comparator<CompletionProposal> {

Expand Down Expand Up @@ -168,16 +151,10 @@ public CompletionProposalRequestor(ICompilationUnit aUnit, int offset, Preferenc
fIsTestCodeExcluded = !isTestSource(unit.getJavaProject(), unit);
setRequireExtendedContext(true);
try {
for (IImportDeclaration importDeclaration : this.unit.getImports()) {
String elementName = importDeclaration.getElementName();
if (isStaticImport(importDeclaration)) {
importedTypes.add(elementName.substring(0, elementName.lastIndexOf('.')));
} else if (importDeclaration.isOnDemand()) {
onDemandImportedPackagesOrTypes.add(elementName.substring(0, elementName.lastIndexOf('.')));
} else {
importedTypes.add(elementName);
}
}
List<String> importedElements = Arrays.stream(this.unit.getImports())
.map(t -> t.getElementName())
.toList();
TypeFilter.getDefault().removeFilterIfMatched(importedElements);
} catch (JavaModelException e) {
JavaLanguageServerPlugin.logException("Failed to get imports during completion", e);
}
Expand Down Expand Up @@ -518,7 +495,7 @@ protected boolean isFiltered(CompletionProposal proposal) {

protected boolean isTypeFiltered(CompletionProposal proposal) {
char[] declaringType = getDeclaringType(proposal);
return declaringType != null && !this.isImported(declaringType) && TypeFilter.isFiltered(declaringType);
return declaringType != null && TypeFilter.isFiltered(declaringType);
jdneo marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -571,7 +548,7 @@ protected final char[] getDeclaringType(CompletionProposal proposal) {

@Override
public boolean isIgnored(char[] fullTypeName) {
return fullTypeName != null && !this.isImported(fullTypeName) && TypeFilter.isFiltered(fullTypeName);
return fullTypeName != null && TypeFilter.isFiltered(fullTypeName);
}

/**
Expand Down Expand Up @@ -601,33 +578,4 @@ private boolean matchCase(CompletionProposal proposal) {

return true;
}

private boolean isStaticImport(IImportDeclaration importElement) {
try {
return Flags.isStatic(importElement.getFlags());
} catch (JavaModelException e) {
JavaLanguageServerPlugin.log(e);
}
return false;
}

/**
* Check if the type appears in the import declarations.
*/
private boolean isImported(char[] fullyQualifiedName) {
String typeName = new String(fullyQualifiedName);
if (this.importedTypes.contains(typeName)) {
return true;
}

int lastDotIdx = typeName.lastIndexOf('.');
if (lastDotIdx >= 0) {
String typeParent = typeName.substring(0, lastDotIdx);
if (this.onDemandImportedPackagesOrTypes.contains(typeParent)) {
return true;
}
}

return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright (c) 2023 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package org.eclipse.jdt.ls.core.internal.contentassist;

import org.eclipse.jdt.internal.ui.util.StringMatcher;

public class StringMatcherEx extends StringMatcher {

public StringMatcherEx(String pattern, boolean ignoreCase, boolean ignoreWildCards) {
super(pattern, ignoreCase, ignoreWildCards);
}

public boolean endsWithWildcard() {
return fPattern.endsWith(".*") || fPattern.endsWith(".?");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.contentassist;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.preferences.DefaultScope;
Expand All @@ -23,7 +26,6 @@
import org.eclipse.jdt.core.manipulation.JavaManipulation;
import org.eclipse.jdt.core.search.TypeNameMatch;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.ui.util.StringMatcher;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;

/**
Expand Down Expand Up @@ -74,23 +76,47 @@ public static boolean isFiltered(TypeNameMatch match) {
}
}

private StringMatcher[] fStringMatchers;
public synchronized void removeFilterIfMatched(Collection<String> importedElements) {
if (importedElements == null || importedElements.isEmpty()) {
return;
}

StringMatcherEx[] matchers= getStringMatchers();
Set<StringMatcherEx> newMatchers = new HashSet<>();
for (String importedElement : importedElements) {
for (int i= 0; i < matchers.length; i++) {
StringMatcherEx cur= matchers[i];
if (cur.endsWithWildcard()) {
importedElement += ".";
}
if (!cur.match(importedElement)) {
newMatchers.add(cur);
}
}
}

if (this.fStringMatchers.length != newMatchers.size()) {
this.fStringMatchers = newMatchers.toArray(StringMatcherEx[]::new);
}
}

private StringMatcherEx[] fStringMatchers;

public TypeFilter() {
fStringMatchers= null;
}

private synchronized StringMatcher[] getStringMatchers() {
private synchronized StringMatcherEx[] getStringMatchers() {
if (fStringMatchers == null) {
String str = getPreference(TYPEFILTER_ENABLED);
StringTokenizer tok= new StringTokenizer(str, ";"); //$NON-NLS-1$
int nTokens= tok.countTokens();

fStringMatchers= new StringMatcher[nTokens];
fStringMatchers= new StringMatcherEx[nTokens];
for (int i= 0; i < nTokens; i++) {
String curr= tok.nextToken();
if (curr.length() > 0) {
fStringMatchers[i]= new StringMatcher(curr, false, false);
fStringMatchers[i]= new StringMatcherEx(curr, false, false);
}
}
}
Expand All @@ -106,9 +132,9 @@ public boolean hasFilters() {
* @return <code>true</code> iff the given type is filtered out
*/
public boolean filter(String fullTypeName) {
StringMatcher[] matchers= getStringMatchers();
StringMatcherEx[] matchers= getStringMatchers();
for (int i= 0; i < matchers.length; i++) {
StringMatcher curr= matchers[i];
StringMatcherEx curr= matchers[i];
if (curr.match(fullTypeName)) {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.corrections;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.CompletionProposal;
Expand Down Expand Up @@ -180,6 +182,10 @@ private void addResult(SimilarElement elem) {

private SimilarElement[] process(ICompilationUnit cu, int pos) throws JavaModelException {
try {
List<String> importedElements = Arrays.stream(cu.getImports())
.map(t -> t.getElementName())
.toList();
TypeFilter.getDefault().removeFilterIfMatched(importedElements);
cu.codeComplete(pos, this);
processKeywords();
return fResult.toArray(new SimilarElement[fResult.size()]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import org.eclipse.core.runtime.Path;
Expand Down Expand Up @@ -1576,4 +1575,31 @@ public void testMultipleAddAllMissingImports() throws Exception {
assertEquals(1, addAllMissingImportsActions.size());
}

@Test
public void testIgnoreTypeFilter() throws Exception {
IPackageFragment pack1 = fSourceFolder.createPackageFragment("test1", false, null);
String before = """
package test1;
import java.util.ArrayList;
public class E {
void foo() {
List v= new ArrayList();
}
}""";
ICompilationUnit cu = pack1.createCompilationUnit("E.java", before, false, null);

String after = """
package test1;
import java.util.ArrayList;
import java.util.List;
public class E {
void foo() {
List v= new ArrayList();
}
}""";
Expected e1 = new Expected("Import 'List' (java.util)", after);

assertCodeActions(cu, e1);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3166,7 +3166,7 @@ public void testCompletion_IgnoreTypeFilterWhenImported1() throws JavaModelExcep
ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java",
//@formatter:off
"package org.sample;\n"
+ "import java.util.List;"
+ "import java.util.List;"
+ "public class Test {\n\n"
+ " void test() {\n\n"
+ " List\n"
Expand All @@ -3191,7 +3191,7 @@ public void testCompletion_IgnoreTypeFilterWhenImported2() throws JavaModelExcep
ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java",
//@formatter:off
"package org.sample;\n"
+ "import java.util.*;"
+ "import java.util.*;"
+ "public class Test {\n\n"
+ " void test() {\n\n"
+ " List\n"
Expand All @@ -3216,7 +3216,7 @@ public void testCompletion_IgnoreTypeFilterWhenImported3() throws JavaModelExcep
ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java",
//@formatter:off
"package org.sample;\n"
+ "import static java.util.List.*;"
+ "import static java.util.List.*;"
+ "public class Test {\n\n"
+ " void test() {\n\n"
+ " List\n"
Expand All @@ -3241,7 +3241,7 @@ public void testCompletion_IgnoreTypeFilterWhenImported4() throws JavaModelExcep
ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java",
//@formatter:off
"package org.sample;\n"
+ "import static java.util.List.DUMMY;"
+ "import static java.util.List.DUMMY;"
+ "public class Test {\n\n"
+ " void test() {\n\n"
+ " List\n"
Expand All @@ -3261,6 +3261,27 @@ public void testCompletion_IgnoreTypeFilterWhenImported4() throws JavaModelExcep
}
}

@Test
public void testCompletion_IgnoreTypeFilterWhenImported5() throws JavaModelException {
ICompilationUnit unit = getWorkingCopy("src/org/sample/Test.java",
//@formatter:off
"package org.sample;\n"
+ "import java.util.List;"
+ "public class Test {\n\n"
+ "}\n");
//@formatter:on
jdneo marked this conversation as resolved.
Show resolved Hide resolved
try {
List<String> filteredTypes = new ArrayList<>();
filteredTypes.add("java.util.*");
PreferenceManager.getPrefs(null).setFilteredTypes(filteredTypes);

CompletionList list = requestCompletions(unit, "java.util.");
assertNotNull(list);
} finally {
PreferenceManager.getPrefs(null).setFilteredTypes(Collections.emptyList());
}
}

@Test
public void testCompletion_InvalidJavadoc() throws Exception {
importProjects("maven/aspose");
Expand Down