Skip to content

Commit

Permalink
[DOM][Completion] Improve filtering
Browse files Browse the repository at this point in the history
Honor the search pattern settings.
  • Loading branch information
mickaelistria committed Jul 2, 2024
1 parent abf77a3 commit c75eb64
Showing 1 changed file with 44 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.TypeNameMatchRequestor;
import org.eclipse.jdt.internal.codeassist.impl.AssistOptions;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.core.JavaProject;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
Expand All @@ -64,6 +65,8 @@ public class DOMCompletionEngine implements Runnable {
private final CompletionRequestor requestor;
private final ICompilationUnit modelUnit;
private final SearchableEnvironment nameEnvironment;
private final AssistOptions assistOptions;
private final SearchPattern pattern;

private static class Bindings {
private HashSet<IMethodBinding> methods = new HashSet<>();
Expand Down Expand Up @@ -108,6 +111,18 @@ public DOMCompletionEngine(int offset, CompilationUnit domUnit, ICompilationUnit
}
}
this.nameEnvironment = env;
this.assistOptions = new AssistOptions(this.modelUnit.getOptions(true));
this.pattern = new SearchPattern(SearchPattern.R_PREFIX_MATCH |
(this.assistOptions.camelCaseMatch ? SearchPattern.R_CAMELCASE_MATCH : 0) |
(this.assistOptions.substringMatch ? SearchPattern.R_SUBSTRING_MATCH : 0) |
(this.assistOptions.subwordMatch ? SearchPattern.R_SUBWORD_MATCH :0)) {
@Override
public SearchPattern getBlankPattern() { return null; }
};
// TODO also honor assistOptions.checkVisibility!
// TODO also honor requestor.ignore*
// TODO sorting/relevance: closest/prefix match should go first
// ...
}

private static Collection<? extends IBinding> visibleBindings(ASTNode node, int offset) {
Expand Down Expand Up @@ -137,11 +152,15 @@ public void run() {
context = toComplete.getParent();
}
}
final String prefix = completeAfter;
Bindings scope = new Bindings();
if (context instanceof FieldAccess fieldAccess) {
processMembers(fieldAccess.getExpression().resolveTypeBinding(), scope);
if (scope.stream().findAny().isPresent()) {
scope.stream().map(binding -> toProposal(binding, toComplete)).forEach(this.requestor::accept);
scope.stream()
.filter(binding -> this.pattern.matchesName(prefix.toCharArray(), binding.getName().toCharArray()))
.map(binding -> toProposal(binding, toComplete))
.forEach(this.requestor::accept);
this.requestor.endReporting();
return;
}
Expand All @@ -153,11 +172,10 @@ public void run() {
&& name.resolveBinding() instanceof IPackageBinding packageBinding) {
packageName = packageBinding.getName();
}
List<IType> types = findTypes(completeAfter, packageName);
if (!types.isEmpty()) {
types.stream().map(type -> toProposal(type, toComplete)).forEach(this.requestor::accept);
return;
}
findTypes(completeAfter, packageName)
.filter(type -> this.pattern.matchesName(prefix.toCharArray(), type.getElementName().toCharArray()))
.map(type -> toProposal(type, toComplete))
.forEach(this.requestor::accept);
List<String> packageNames = new ArrayList<>();
try {
this.nameEnvironment.findPackages(this.modelUnit.getSource().substring(fieldAccess.getStartPosition(), this.offset).toCharArray(), new ISearchRequestor() {
Expand All @@ -182,6 +200,7 @@ public void acceptConstructor(int modifiers, char[] simpleTypeName, int paramete
} catch (JavaModelException ex) {
ILog.get().error(ex.getMessage(), ex);
}
packageNames.removeIf(name -> !this.pattern.matchesName(prefix.toCharArray(), name.toCharArray()));
if (!packageNames.isEmpty()) {
packageNames.stream().distinct().map(pack -> toPackageProposal(pack, fieldAccess)).forEach(this.requestor::accept);
return;
Expand All @@ -190,7 +209,11 @@ public void acceptConstructor(int modifiers, char[] simpleTypeName, int paramete
if (context instanceof MethodInvocation invocation) {
ITypeBinding type = invocation.getExpression().resolveTypeBinding();
processMembers(type, scope);
scope.stream().filter(IMethodBinding.class::isInstance).map(binding -> toProposal(binding, toComplete)).forEach(this.requestor::accept);
scope.stream()
.filter(binding -> this.pattern.matchesName(prefix.toCharArray(), binding.getName().toCharArray()))
.filter(IMethodBinding.class::isInstance)
.map(binding -> toProposal(binding, toComplete))
.forEach(this.requestor::accept);
return;
}

Expand All @@ -206,12 +229,19 @@ public void acceptConstructor(int modifiers, char[] simpleTypeName, int paramete
scope.addAll(visibleBindings(current, this.offset));
current = current.getParent();
}
scope.stream().map(binding -> toProposal(binding, toComplete)).forEach(this.requestor::accept);
findTypes(completeAfter, null).stream().map(type -> toProposal(type, toComplete)).forEach(this.requestor::accept);
scope.stream()
.filter(binding -> this.pattern.matchesName(prefix.toCharArray(), binding.getName().toCharArray()))
.map(binding -> toProposal(binding, toComplete))
.forEach(this.requestor::accept);
findTypes(completeAfter, null)
.filter(type -> this.pattern.matchesName(prefix.toCharArray(), type.getElementName().toCharArray()))
.map(type -> toProposal(type, toComplete))
.forEach(this.requestor::accept);
try {
Arrays.stream(this.modelUnit.getJavaProject().getPackageFragments())
.map(IPackageFragment::getElementName)
.distinct()
.filter(name -> this.pattern.matchesName(prefix.toCharArray(), name.toCharArray()))
.map(pack -> toPackageProposal(pack, toComplete))
.forEach(this.requestor::accept);
} catch (JavaModelException ex) {
Expand All @@ -220,7 +250,7 @@ public void acceptConstructor(int modifiers, char[] simpleTypeName, int paramete
this.requestor.endReporting();
}

private List<IType> findTypes(String namePrefix, String packageName) {
private Stream<IType> findTypes(String namePrefix, String packageName) {
if (namePrefix == null) {
namePrefix = ""; //$NON-NLS-1$
}
Expand All @@ -234,7 +264,7 @@ public void acceptTypeNameMatch(org.eclipse.jdt.core.search.TypeNameMatch match)
};
try {
new SearchEngine(this.modelUnit.getOwner()).searchAllTypeNames(packageName == null ? null : packageName.toCharArray(), SearchPattern.R_EXACT_MATCH,
namePrefix.toCharArray(), SearchPattern.R_PREFIX_MATCH | SearchPattern.R_SUBSTRING_MATCH,
namePrefix.toCharArray(), SearchPattern.R_PREFIX_MATCH | (this.assistOptions.substringMatch ? SearchPattern.R_SUBSTRING_MATCH : 0) | (this.assistOptions.subwordMatch ? SearchPattern.R_SUBWORD_MATCH : 0),
IJavaSearchConstants.TYPE,
searchScope,
typeRequestor,
Expand All @@ -244,7 +274,7 @@ public void acceptTypeNameMatch(org.eclipse.jdt.core.search.TypeNameMatch match)
} catch (JavaModelException ex) {
ILog.get().error(ex.getMessage(), ex);
}
return types;
return types.stream();
}

private void processMembers(ITypeBinding typeBinding, Bindings scope) {
Expand All @@ -269,6 +299,7 @@ private CompletionProposal toProposal(IBinding binding, ASTNode toComplete) {
binding instanceof IVariableBinding variableBinding ? CompletionProposal.LOCAL_VARIABLE_REF :
-1, this.offset);
res.setName(binding.getName().toCharArray());
// TODO: for methods, completion should also include potential args, not just name
res.setCompletion(binding.getName().toCharArray());
res.setSignature(
binding instanceof IMethodBinding methodBinding ?
Expand Down Expand Up @@ -301,6 +332,7 @@ private CompletionProposal toProposal(IBinding binding, ASTNode toComplete) {
}

private CompletionProposal toProposal(IType type, ASTNode toComplete) {
// TODO add import if necessary
InternalCompletionProposal res = new InternalCompletionProposal(CompletionProposal.TYPE_REF, this.offset);
res.setName(type.getElementName().toCharArray());
res.setCompletion(type.getElementName().toCharArray());
Expand Down

0 comments on commit c75eb64

Please sign in to comment.