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 all 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-2017 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 Down Expand Up @@ -200,7 +200,8 @@ public void updateReplacement(CompletionProposal proposal, CompletionItem item,
item.setTextEdit(Either.forLeft(new org.eclipse.lsp4j.TextEdit(insertReplaceEdit.getInsert(), text)));
}

if (!isImportCompletion(proposal) && (!client.isResolveAdditionalTextEditsSupport() || isResolvingRequest)) {
if (!CompletionProposalUtils.isImportCompletion(proposal) && (!client.isResolveAdditionalTextEditsSupport() ||
isResolvingRequest)) {
addImports(additionalTextEdits);
if(!additionalTextEdits.isEmpty()){
item.setAdditionalTextEdits(additionalTextEdits);
Expand Down Expand Up @@ -959,7 +960,7 @@ private String computeJavaTypeReplacementString(CompletionProposal proposal) {
String replacement = String.valueOf(proposal.getCompletion());

/* No import rewriting ever from within the import section. */
if (isImportCompletion(proposal)) {
if (CompletionProposalUtils.isImportCompletion(proposal)) {
return replacement;
}

Expand Down Expand Up @@ -1057,19 +1058,4 @@ private String computeJavaTypeReplacementString(CompletionProposal proposal) {
return qualifiedTypeName;
}

private boolean isImportCompletion(CompletionProposal proposal) {
char[] completion = proposal.getCompletion();
if (completion.length == 0) {
return false;
}

char last = completion[completion.length - 1];
/*
* Proposals end in a semicolon when completing types in normal imports
* or when completing static members, in a period when completing types
* in static imports.
*/
return last == SEMICOLON || last == '.';
}

}
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 @@ -502,7 +479,6 @@ protected boolean isFiltered(CompletionProposal proposal) {
case CompletionProposal.CONSTRUCTOR_INVOCATION:
case CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION:
case CompletionProposal.JAVADOC_TYPE_REF:
case CompletionProposal.PACKAGE_REF:
case CompletionProposal.TYPE_REF:
return isTypeFiltered(proposal);
case CompletionProposal.METHOD_REF:
Expand All @@ -517,8 +493,12 @@ protected boolean isFiltered(CompletionProposal proposal) {
}

protected boolean isTypeFiltered(CompletionProposal proposal) {
// always includes type completions for import declarations.
if (CompletionProposalUtils.isImportCompletion(proposal)) {
return false;
}
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 +551,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 +581,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,38 @@
/*******************************************************************************
* 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.core.CompletionProposal;

public class CompletionProposalUtils {

private static final char SEMICOLON = ';';

private CompletionProposalUtils() {}

public static boolean isImportCompletion(CompletionProposal proposal) {
char[] completion = proposal.getCompletion();
if (completion.length == 0) {
return false;
}

char last = completion[completion.length - 1];
/*
* Proposals end in a semicolon when completing types in normal imports
* or when completing static members, in a period when completing types
* in static imports.
*/
return last == SEMICOLON || last == '.';
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2012 IBM Corporation and others.
* Copyright (c) 2000-2023 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -13,6 +13,8 @@
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.contentassist;

import java.util.Arrays;
import java.util.Collection;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.preferences.DefaultScope;
Expand Down Expand Up @@ -74,6 +76,25 @@ public static boolean isFiltered(TypeNameMatch match) {
}
}

/**
* Remove the type filter if any of the imported element matches.
*/
public synchronized void removeFilterIfMatched(Collection<String> importedElements) {
if (importedElements == null || importedElements.isEmpty()) {
return;
}

StringMatcher[] matchers = getStringMatchers();
this.fStringMatchers = Arrays.stream(matchers).filter(m -> {
for (String importedElement : importedElements) {
if (m.match(importedElement)) {
return false;
}
}
return true;
}).toArray(size -> new StringMatcher[size]);
}

private StringMatcher[] fStringMatchers;

public TypeFilter() {
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);
}

}
Loading