Skip to content

Commit bb1f6a9

Browse files
Rob Strykerrgrunber
authored andcommitted
[DOM Search] implement matching on wildcards, extends, super, and other bugs
Signed-off-by: Rob Stryker <[email protected]>
1 parent 83c79ae commit bb1f6a9

File tree

4 files changed

+173
-29
lines changed

4 files changed

+173
-29
lines changed

org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacBindingResolver.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Map;
2020
import java.util.Objects;
2121
import java.util.function.Function;
22+
import java.util.stream.Collectors;
2223
import java.util.stream.Stream;
2324

2425
import javax.lang.model.element.Element;
@@ -541,6 +542,10 @@ public ASTNode findDeclaringNode(IBinding binding) {
541542
return findNode(getJavacSymbol(binding));
542543
}
543544

545+
public IBinding findBinding(String bindingKey) {
546+
return this.bindings.getBinding(bindingKey);
547+
}
548+
544549
@Override
545550
public ASTNode findDeclaringNode(String bindingKey) {
546551
resolve();

org.eclipse.jdt.core.javac/src/org/eclipse/jdt/core/dom/JavacCompilationUnitResolver.java

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,8 @@ public void accept(ISourceType[] sourceType, PackageBinding packageBinding,
257257
if (bindingResolver[0] == null && (JavacBindingResolver)b.ast.getBindingResolver() != null) {
258258
bindingResolver[0] = (JavacBindingResolver)b.ast.getBindingResolver();
259259
}
260-
requestor.acceptAST(a,b);
261260
resolveBindings(b, bindingMap, apiLevel);
261+
requestor.acceptAST(a,b);
262262
});
263263

264264
resolveRequestedBindingKeys(bindingResolver[0], bindingKeys,
@@ -464,6 +464,26 @@ private void resolveBindings(CompilationUnit unit, Map<String, IBinding> binding
464464
bindingMap.put(pb.getKey(), pb);
465465
}
466466
}
467+
if( apiLevel >= AST.JLS9_INTERNAL) {
468+
if (unit.getModule() != null) {
469+
IModuleBinding mb = unit.getModule().resolveBinding();
470+
if (mb != null) {
471+
bindingMap.put(mb.getKey(), mb);
472+
}
473+
}
474+
}
475+
unit.accept(new ASTVisitor() {
476+
@Override
477+
public void preVisit(ASTNode node) {
478+
if( node instanceof Type t) {
479+
ITypeBinding tb = t.resolveBinding();
480+
if (tb != null) {
481+
bindingMap.put(tb.getKey(), tb);
482+
}
483+
}
484+
}
485+
});
486+
467487
if (!unit.types().isEmpty()) {
468488
List<AbstractTypeDeclaration> types = unit.types();
469489
for( int i = 0; i < types.size(); i++ ) {
@@ -473,14 +493,7 @@ private void resolveBindings(CompilationUnit unit, Map<String, IBinding> binding
473493
}
474494
}
475495
}
476-
if( apiLevel >= AST.JLS9_INTERNAL) {
477-
if (unit.getModule() != null) {
478-
IModuleBinding mb = unit.getModule().resolveBinding();
479-
if (mb != null) {
480-
bindingMap.put(mb.getKey(), mb);
481-
}
482-
}
483-
}
496+
484497
} catch (Exception e) {
485498
ILog.get().warn("Failed to resolve binding", e);
486499
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.eclipse.jdt.core.dom;
2+
3+
public class JdtCoreDomPackagePrivateUtility {
4+
public static BindingResolver getBindingResolver(ASTNode node) {
5+
return node.getAST().getBindingResolver();
6+
}
7+
8+
public static JavacBindingResolver getJavacBindingResolverOrNull(ASTNode node) {
9+
BindingResolver br = getBindingResolver(node);
10+
return br instanceof JavacBindingResolver br2 ? br2 : null;
11+
}
12+
13+
public static IBinding findBindingForType(ASTNode node, String signature) {
14+
JavacBindingResolver jcbr = getJavacBindingResolverOrNull(node);
15+
IBinding ret1 = jcbr instanceof JavacBindingResolver br2 ? br2.findBinding(signature) : null;
16+
if( ret1 == null ) {
17+
String sig2 = signature.replaceAll("\\.", "/");
18+
ret1 = jcbr instanceof JavacBindingResolver br2 ? br2.findBinding(sig2) : null;
19+
}
20+
return ret1;
21+
}
22+
23+
}

org.eclipse.jdt.core.javac/src/org/eclipse/jdt/internal/core/search/matching/DOMTypeReferenceLocator.java

Lines changed: 123 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.eclipse.jdt.core.dom.ITypeBinding;
3535
import org.eclipse.jdt.core.dom.ImportDeclaration;
3636
import org.eclipse.jdt.core.dom.InstanceofExpression;
37+
import org.eclipse.jdt.core.dom.JdtCoreDomPackagePrivateUtility;
3738
import org.eclipse.jdt.core.dom.LabeledStatement;
3839
import org.eclipse.jdt.core.dom.Name;
3940
import org.eclipse.jdt.core.dom.PackageDeclaration;
@@ -58,6 +59,7 @@ public class DOMTypeReferenceLocator extends DOMPatternLocator {
5859
private TypeReferenceLocator locator;
5960
private List<IJavaElement> foundElements = new ArrayList<>();
6061
private Set<org.eclipse.jdt.core.dom.Name> imports = new HashSet<>();
62+
private MatchLocator matchLocator = null;
6163

6264
public DOMTypeReferenceLocator(TypeReferenceLocator locator) {
6365
super(locator.pattern);
@@ -76,6 +78,7 @@ public LocatorResponse match(org.eclipse.jdt.core.dom.Annotation node, NodeSetWr
7678
}
7779
@Override
7880
public LocatorResponse match(Name name, NodeSetWrapper nodeSet, MatchLocator locator) {
81+
this.matchLocator = locator;
7982
if (name.getParent() instanceof AbstractTypeDeclaration) {
8083
return toResponse(IMPOSSIBLE_MATCH);
8184
}
@@ -124,6 +127,7 @@ public LocatorResponse match(Name name, NodeSetWrapper nodeSet, MatchLocator loc
124127
}
125128
@Override
126129
public LocatorResponse match(org.eclipse.jdt.core.dom.ASTNode node, NodeSetWrapper nodeSet, MatchLocator locator) {
130+
this.matchLocator = locator;
127131
if (failsFineGrain(node, this.locator.fineGrain())) {
128132
return toResponse(IMPOSSIBLE_MATCH);
129133
}
@@ -169,6 +173,7 @@ private LocatorResponse matchTypeNodeReturnComponent(Type node, String qualified
169173

170174
@Override
171175
public LocatorResponse match(Type node, NodeSetWrapper nodeSet, MatchLocator locator) {
176+
this.matchLocator = locator;
172177
if (failsFineGrain(node, this.locator.fineGrain())) {
173178
return toResponse(IMPOSSIBLE_MATCH);
174179
}
@@ -204,6 +209,15 @@ public LocatorResponse match(Type node, NodeSetWrapper nodeSet, MatchLocator loc
204209
r1 = matchTypeNodeReturnComponent(node, patternQualifiedString, fqqn, defaultLevel);
205210
if( r1 != null ) return r1;
206211
}
212+
// } else {
213+
// String[] qualifiedNameFromNodeSegments = qualifiedNameFromNode.split("\\.");
214+
// String first = qualifiedNameFromNodeSegments == null ? null : qualifiedNameFromNodeSegments.length == 0 ? null : qualifiedNameFromNodeSegments[0];
215+
// String fqqnImport = fqqnFromImport(first);
216+
// if( fqqnImport != null ) {
217+
// String fqqn = fqqnImport + qualifiedNameFromNode.substring(first.length());
218+
// r1 = matchTypeNodeReturnComponent(node, qualifiedNameFromNode, fqqn, defaultLevel);
219+
// if( r1 != null ) return r1;
220+
// }
207221
}
208222
} else if (simpleNameFromNode != null ) {
209223
if( this.locator.matchesName(this.locator.pattern.simpleName, simpleNameFromNode.toCharArray()) ) {
@@ -284,22 +298,18 @@ private int validateTypeParameters(Type node) {
284298
}
285299
for( int j = 0; j < thisLevelTypeParams.length; j++ ) {
286300
String typeFromPattern = new String(thisLevelTypeParams[j]);
301+
IBinding patternTypeBinding = JdtCoreDomPackagePrivateUtility.findBindingForType(node, typeFromPattern);
287302
IBinding b = DOMASTNodeUtils.getBinding((ASTNode)typeArgs.get(j));
288303
String sig = b == null ? null : b instanceof JavacTypeBinding jctb ? jctb.getGenericTypeSignature(false) : b.getKey();
289304
if( sig.startsWith("+") && b instanceof ITypeBinding tb) {
290-
boolean isQuestionMark = "+Ljava/lang/Object;".equals(sig);
291-
if( isQuestionMark ) {
292-
// TODO - if pattern is <Unresolved1,Unresolved2> we must return no_match
293-
continue;
305+
boolean canContinue = validateOneTypeParameterExtends(typeFromPattern, sig, tb, patternTypeBinding);
306+
if( !canContinue) {
307+
return TYPE_PARAMS_COUNT_MATCH;
294308
}
295-
String remaining = sig.substring(1);
296-
ITypeBinding[] bounds = tb.getTypeBounds();
297-
if( bounds != null && bounds.length == 1 && bounds[0] != null ) {
298-
ITypeBinding b1 = bounds[0];
299-
String boundSig = b1 == null ? null : b1 instanceof JavacTypeBinding jctb ? jctb.getGenericTypeSignature(false) : b1.getKey();
300-
if( !typeFromPattern.equals(boundSig)) {
301-
return TYPE_PARAMS_COUNT_MATCH;
302-
}
309+
} else if( sig.startsWith("-") && b instanceof ITypeBinding tb) {
310+
boolean canContinue = validateOneTypeParameterSuper(typeFromPattern, sig, tb, patternTypeBinding);
311+
if( !canContinue) {
312+
return TYPE_PARAMS_COUNT_MATCH;
303313
}
304314
} else if( !typeFromPattern.equals(sig)) {
305315
return TYPE_PARAMS_COUNT_MATCH;
@@ -322,6 +332,69 @@ private int validateTypeParameters(Type node) {
322332
}
323333
return TYPE_PARAMS_MATCH;
324334
}
335+
336+
private boolean validateOneTypeParameterExtends(String typeFromPattern, String sig, ITypeBinding tb, IBinding patternTypeBinding) {
337+
boolean isQuestionMark = "+Ljava/lang/Object;".equals(sig);
338+
if( isQuestionMark ) {
339+
// TODO - if pattern is <Unresolved1,Unresolved2> we must return no_match
340+
return true;
341+
}
342+
String remaining = sig.substring(1);
343+
ITypeBinding[] bounds = tb.getTypeBounds();
344+
if( bounds != null && bounds.length == 1 && bounds[0] != null ) {
345+
ITypeBinding b1 = bounds[0];
346+
String boundSig = b1 == null ? null : b1 instanceof JavacTypeBinding jctb ? jctb.getGenericTypeSignature(false) : b1.getKey();
347+
if( typeFromPattern.equals(boundSig)) {
348+
return true;
349+
}
350+
if( patternTypeBinding instanceof ITypeBinding itb) {
351+
ITypeBinding working = itb;
352+
while(working != null) {
353+
ITypeBinding superClaz = working.getSuperclass();
354+
if( superClaz != null ) {
355+
String superClazKey = b1 == null ? null : superClaz instanceof JavacTypeBinding jctb ? jctb.getGenericTypeSignature(false) : superClaz.getKey();
356+
if( superClazKey.equals(boundSig)) {
357+
return true;
358+
}
359+
}
360+
working = superClaz;
361+
}
362+
return false;
363+
} else {
364+
return false;
365+
}
366+
}
367+
return true;
368+
}
369+
370+
private boolean validateOneTypeParameterSuper(String typeFromPattern, String sig, ITypeBinding tb, IBinding patternTypeBinding) {
371+
String remaining = sig.substring(1);
372+
ITypeBinding b1 = tb.getBound();
373+
if( b1 != null ) {
374+
String boundSig = b1 == null ? null : b1 instanceof JavacTypeBinding jctb ? jctb.getGenericTypeSignature(false) : b1.getKey();
375+
if( typeFromPattern.equals(boundSig)) {
376+
return true;
377+
}
378+
if( patternTypeBinding instanceof ITypeBinding itb) {
379+
ITypeBinding working = b1;
380+
while(working != null) {
381+
ITypeBinding superClaz = working.getSuperclass();
382+
if( superClaz != null ) {
383+
String superClazKey = b1 == null ? null : superClaz instanceof JavacTypeBinding jctb ? jctb.getGenericTypeSignature(false) : superClaz.getKey();
384+
if( superClazKey.equals(typeFromPattern)) {
385+
return true;
386+
}
387+
}
388+
working = superClaz;
389+
}
390+
return false;
391+
} else {
392+
return false;
393+
}
394+
}
395+
return true;
396+
}
397+
325398
private String getQualifiedNameFromType(Type query) {
326399
if( query instanceof QualifiedType qtt) {
327400
String qualString = getQualifiedNameFromType(qtt.getQualifier());
@@ -426,16 +499,21 @@ public LocatorResponse resolveLevel(org.eclipse.jdt.core.dom.ASTNode node, IBind
426499
int v = resolveLevelForTypeBinding(node, typeBinding, locator);
427500
boolean patternHasTypeArgs = this.locator.pattern.hasTypeArguments();
428501
boolean patternHasTypeParameters = this.locator.pattern.hasTypeParameters();
502+
boolean patternHasSignatures = this.locator.pattern.hasSignatures();
429503
boolean erasureMatch = isPatternErasureMatch();
430504
boolean equivMatch = isPatternEquivalentMatch();
431-
if( patternHasTypeArgs && !(erasureMatch || equivMatch)) {
505+
if( (patternHasTypeArgs && !(erasureMatch || equivMatch))) {
432506
return toResponse(IMPOSSIBLE_MATCH);
433507
}
434-
435508
if( node instanceof ParameterizedType pt) {
436509
ASTNode n = preferParamaterizedNode() ? pt : pt.getType();
437510
return new LocatorResponse(v, n != pt, n, false, false);
438511
}
512+
if( patternHasTypeArgs && !patternHasSignatures && !erasureMatch) {
513+
// the search doesn't have type args in it, but the type does
514+
return toResponse(IMPOSSIBLE_MATCH);
515+
}
516+
439517
return toResponse(v);
440518
}
441519
if( binding instanceof IPackageBinding && node instanceof SimpleName sn) {
@@ -544,14 +622,17 @@ public String findImportForString(String s) {
544622
}
545623
}
546624
if( newLevel == ACCURATE_MATCH && this.locator.pattern.hasTypeArguments() ) {
547-
return resolveLevelForTypeBindingWithTypeArguments(typeBinding, node, newLevel, locator);
625+
return resolveLevelForTypeBindingWithTypeArguments(typeBinding, node, locator);
548626
}
549627
return newLevel;
550628
}
551629

552-
private int resolveLevelForTypeBindingWithTypeArguments(ITypeBinding typeBinding, ASTNode node, int newLevel,
630+
private int resolveLevelForTypeBindingWithTypeArguments(ITypeBinding typeBinding, ASTNode node,
553631
MatchLocator locator2) {
554632
boolean patternHasTypeArgs = this.locator.pattern.hasTypeArguments();
633+
boolean patternHasTypeParams = this.locator.pattern.hasTypeParameters();
634+
boolean patternHasTypeSignatures = !(patternHasTypeArgs && patternHasTypeParams);
635+
555636
char[][][] patternTypeArgArray = this.locator.pattern.getTypeArguments();
556637
int patternTypeArgsLength = patternTypeArgArray == null ? -1 :
557638
patternTypeArgArray[0] == null ? -1 :
@@ -568,14 +649,30 @@ private int resolveLevelForTypeBindingWithTypeArguments(ITypeBinding typeBinding
568649
int bindingTypeArgsLength = bindingArgs == null ? -1 : bindingArgs.length;
569650
// Compare arguments lengths
570651
if (patternTypeArgsLength == bindingTypeArgsLength) {
652+
Type t = node instanceof Type ? (Type)node : null;
653+
if( t != null ) {
654+
int typeArgsValidation = validateTypeParameters(t);
655+
if( typeArgsValidation == TYPE_PARAMS_MATCH) {
656+
if( !patternHasTypeSignatures) {
657+
return ERASURE_MATCH;
658+
}
659+
return ACCURATE_MATCH;
660+
}
661+
if( typeArgsValidation == TYPE_PARAMS_COUNT_MATCH) {
662+
return ERASURE_MATCH;
663+
}
664+
if( typeArgsValidation == TYPE_PARAMS_NO_MATCH) {
665+
return ERASURE_MATCH;
666+
}
667+
}
571668
if (!bindingIsRaw && patternHasTypeArgs) {
572669
// generic patterns are always not compatible match
573670
return ERASURE_MATCH;
574671
}
575-
return newLevel;
672+
return ACCURATE_MATCH;
576673
} else {
577674
if (patternTypeArgsLength==0) {
578-
return newLevel;
675+
return ACCURATE_MATCH;
579676
} else if (bindingTypeArgsLength==0) {
580677
// If this is an import, we have to treat it differently
581678

@@ -585,13 +682,13 @@ private int resolveLevelForTypeBindingWithTypeArguments(ITypeBinding typeBinding
585682
// ITypeBinding[] declParams = decl.getTypeParameters();
586683
// raw binding is always compatible
587684
if( patternIsEquivMatch && bindingIsRaw) {
588-
return IMPOSSIBLE_MATCH;
685+
return ACCURATE_MATCH;
589686
}
590687
if( !bindingIsRaw && !(patternIsEquivMatch || patternIsErasureMatch)) {
591688
return IMPOSSIBLE_MATCH;
592689
}
593690
if( !patternIsEquivMatch || bindingIsRaw)
594-
return newLevel;
691+
return ACCURATE_MATCH;
595692
}
596693
}
597694
return IMPOSSIBLE_MATCH;
@@ -712,6 +809,12 @@ public void reportSearchMatch(MatchLocator locator, ASTNode node, SearchMatch ma
712809
match.setLength(newLength);
713810
}
714811

812+
// boolean matchIsEr = match.isErasure();
813+
// boolean matchIsEq = match.isEquivalent();
814+
// boolean matchIsEx = match.isExact();
815+
// boolean report = (this.isErasureMatch && match.isErasure())
816+
// || ((this.isErasureMatch || this.isEquivalentMatch) && match.isEquivalent())
817+
// || match.isExact();
715818
boolean report = (this.isErasureMatch && match.isErasure()) || (this.isEquivalentMatch && match.isEquivalent()) || match.isExact();
716819
if (!report) return;
717820

0 commit comments

Comments
 (0)