Lines 31-67
Link Here
|
31 |
this.pattern = pattern; |
31 |
this.pattern = pattern; |
32 |
this.isDeclarationOfReferencedTypesPattern = this.pattern instanceof DeclarationOfReferencedTypesPattern; |
32 |
this.isDeclarationOfReferencedTypesPattern = this.pattern instanceof DeclarationOfReferencedTypesPattern; |
33 |
} |
33 |
} |
34 |
/* SEARCH_15 |
|
|
35 |
* Modify PatternLocator.qualifiedPattern behavior: |
36 |
* do not add star before simple name pattern when qualification pattern is null. |
37 |
* This avoid to match p.X when pattern is X... |
38 |
*/ |
39 |
public static char[] qualifiedPattern(char[] simpleNamePattern, char[] qualificationPattern) { |
40 |
// NOTE: if case insensitive search then simpleNamePattern & qualificationPattern are assumed to be lowercase |
41 |
if (simpleNamePattern == null) { |
42 |
if (qualificationPattern == null) return null; |
43 |
return CharOperation.concat(qualificationPattern, ONE_STAR, '.'); |
44 |
} else if (qualificationPattern == null) { |
45 |
return simpleNamePattern; |
46 |
} else { |
47 |
return CharOperation.concat(qualificationPattern, simpleNamePattern, '.'); |
48 |
} |
49 |
} |
50 |
/* SEARCH_15 |
51 |
* Modify PatternLocator.qualifiedSourceName behavior: |
52 |
* concat enclosing type when type is a only a member type. |
53 |
*/ |
54 |
public static char[] qualifiedSourceName(TypeBinding binding) { |
55 |
if (binding instanceof ReferenceBinding) { |
56 |
ReferenceBinding type = (ReferenceBinding) binding; |
57 |
if (type.isLocalType()) { |
58 |
return CharOperation.concat(qualifiedSourceName(type.enclosingType()), new char[] {'.', '1', '.'}, type.sourceName()); |
59 |
} else if (type.isMemberType()) { |
60 |
return CharOperation.concat(qualifiedSourceName(type.enclosingType()), type.sourceName(), '.'); |
61 |
} |
62 |
} |
63 |
return binding != null ? binding.qualifiedSourceName() : null; |
64 |
} |
65 |
protected IJavaElement findElement(IJavaElement element, int accuracy) { |
34 |
protected IJavaElement findElement(IJavaElement element, int accuracy) { |
66 |
// need exact match to be able to open on type ref |
35 |
// need exact match to be able to open on type ref |
67 |
if (accuracy != SearchMatch.A_ACCURATE) return null; |
36 |
if (accuracy != SearchMatch.A_ACCURATE) return null; |
Lines 72-77
Link Here
|
72 |
element = element.getParent(); |
41 |
element = element.getParent(); |
73 |
return element; |
42 |
return element; |
74 |
} |
43 |
} |
|
|
44 |
/* |
45 |
* Get binding of type argument from an index position. |
46 |
* Delegate this search to the pattern which can cache results. |
47 |
*/ |
48 |
protected TypeBinding getTypeNameBinding(int index) { |
49 |
return this.pattern.getTypeNameBinding(this.unitScope, index); |
50 |
} |
75 |
public int match(ASTNode node, MatchingNodeSet nodeSet) { // interested in ImportReference |
51 |
public int match(ASTNode node, MatchingNodeSet nodeSet) { // interested in ImportReference |
76 |
if (!(node instanceof ImportReference)) return IMPOSSIBLE_MATCH; |
52 |
if (!(node instanceof ImportReference)) return IMPOSSIBLE_MATCH; |
77 |
|
53 |
|
Lines 144-150
Link Here
|
144 |
} |
120 |
} |
145 |
protected void matchReportImportRef(ImportReference importRef, Binding binding, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException { |
121 |
protected void matchReportImportRef(ImportReference importRef, Binding binding, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException { |
146 |
if (this.pattern.shouldExtendSelection()) { |
122 |
if (this.pattern.shouldExtendSelection()) { |
147 |
// SEARCH_15 do not report import ref for generic patterns... |
123 |
// do not report import ref for generic patterns... |
148 |
return; |
124 |
return; |
149 |
} |
125 |
} |
150 |
if (this.isDeclarationOfReferencedTypesPattern) { |
126 |
if (this.isDeclarationOfReferencedTypesPattern) { |
Lines 193-199
Link Here
|
193 |
locator.report(match); |
169 |
locator.report(match); |
194 |
} |
170 |
} |
195 |
} else if (this.pattern.shouldExtendSelection() && arrayRef.resolvedType.isParameterizedType() && ((ParameterizedTypeBinding)arrayRef.resolvedType).arguments != null) { |
171 |
} else if (this.pattern.shouldExtendSelection() && arrayRef.resolvedType.isParameterizedType() && ((ParameterizedTypeBinding)arrayRef.resolvedType).arguments != null) { |
196 |
// SEARCH_15 specific report accurate match for parameterized types |
172 |
// specific report accurate match for parameterized types |
197 |
locator.reportAccurateParameterizedTypeReference(arrayRef, this.pattern.simpleName, element, accuracy); |
173 |
locator.reportAccurateParameterizedTypeReference(arrayRef, this.pattern.simpleName, element, accuracy); |
198 |
} else |
174 |
} else |
199 |
locator.reportAccurateTypeReference(arrayRef, this.pattern.simpleName, element, accuracy); |
175 |
locator.reportAccurateTypeReference(arrayRef, this.pattern.simpleName, element, accuracy); |
Lines 287-293
Link Here
|
287 |
int start = (int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32); |
263 |
int start = (int) ((positions[this.pattern.qualification == null ? lastIndex : 0]) >>> 32); |
288 |
int end = (int) positions[lastIndex]; |
264 |
int end = (int) positions[lastIndex]; |
289 |
if (this.pattern.shouldExtendSelection() && refBinding.isParameterizedType() && ((ParameterizedTypeBinding)refBinding).arguments != null) { |
265 |
if (this.pattern.shouldExtendSelection() && refBinding.isParameterizedType() && ((ParameterizedTypeBinding)refBinding).arguments != null) { |
290 |
// SEARCH_15 specific report accurate match for parameterized types |
266 |
// specific report accurate match for parameterized types |
291 |
locator.reportAccurateParameterizedTypeReference(qTypeRef, this.pattern.simpleName, element, accuracy); |
267 |
locator.reportAccurateParameterizedTypeReference(qTypeRef, this.pattern.simpleName, element, accuracy); |
292 |
} else { |
268 |
} else { |
293 |
SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, start, end-start+1, qTypeRef); |
269 |
SearchMatch match = locator.newTypeReferenceMatch(element, accuracy, start, end-start+1, qTypeRef); |
Lines 480-486
Link Here
|
480 |
return resolveLevelForTypeOrEnclosingTypes(this.pattern.simpleName, this.pattern.qualification, typeBinding); |
456 |
return resolveLevelForTypeOrEnclosingTypes(this.pattern.simpleName, this.pattern.qualification, typeBinding); |
481 |
} |
457 |
} |
482 |
/* (non-Javadoc) |
458 |
/* (non-Javadoc) |
483 |
* SEARCH_15 |
|
|
484 |
* Resolve level for type with a given binding. |
459 |
* Resolve level for type with a given binding. |
485 |
* This is just an helper to avoid call of method with all parameters... |
460 |
* This is just an helper to avoid call of method with all parameters... |
486 |
*/ |
461 |
*/ |
Lines 489-677
Link Here
|
489 |
this.pattern.simpleName, |
464 |
this.pattern.simpleName, |
490 |
this.pattern.qualification, |
465 |
this.pattern.qualification, |
491 |
this.pattern.typeNames, |
466 |
this.pattern.typeNames, |
|
|
467 |
this.pattern.wildcards, |
492 |
((InternalSearchPattern)this.pattern).mustResolve, |
468 |
((InternalSearchPattern)this.pattern).mustResolve, |
493 |
this.pattern.declaration, |
469 |
this.pattern.declaration, |
494 |
typeBinding); |
470 |
typeBinding); |
495 |
} |
471 |
} |
496 |
/* (non-Javadoc) |
472 |
/* (non-Javadoc) |
497 |
* SEARCH_15 |
|
|
498 |
* Overrides PatternLocator method behavior in order to accept member pattern as X.Member |
473 |
* Overrides PatternLocator method behavior in order to accept member pattern as X.Member |
499 |
* @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#resolveLevelForType(char[], char[], org.eclipse.jdt.internal.compiler.lookup.TypeBinding) |
474 |
* @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#resolveLevelForType(char[], char[], org.eclipse.jdt.internal.compiler.lookup.TypeBinding) |
500 |
*/ |
475 |
*/ |
501 |
protected int resolveLevelForType (char[] simpleNamePattern, char[] qualificationPattern, TypeBinding type) { |
476 |
protected int resolveLevelForType (char[] simpleNamePattern, char[] qualificationPattern, TypeBinding type) { |
502 |
char[] qualifiedPattern = qualifiedPattern(simpleNamePattern, qualificationPattern); |
477 |
char[] qualifiedPattern = getQualifiedPattern(simpleNamePattern, qualificationPattern); |
503 |
int level = resolveLevelForType(qualifiedPattern, type); |
478 |
int level = resolveLevelForType(qualifiedPattern, type); |
504 |
if (level == ACCURATE_MATCH || type == null) return level; |
479 |
if (level == ACCURATE_MATCH || type == null) return level; |
505 |
boolean match = false; |
480 |
boolean match = false; |
506 |
if (type.isMemberType() || type.isLocalType()) { |
481 |
if (type.isMemberType() || type.isLocalType()) { |
507 |
if (qualificationPattern != null) { |
482 |
if (qualificationPattern != null) { |
508 |
match = CharOperation.equals(qualifiedPattern, qualifiedSourceName(type), this.isCaseSensitive); |
483 |
match = CharOperation.equals(qualifiedPattern, getQualifiedSourceName(type), this.isCaseSensitive); |
509 |
} else { |
484 |
} else { |
510 |
match = CharOperation.equals(qualifiedPattern, type.sourceName(), this.isCaseSensitive); |
485 |
match = CharOperation.equals(qualifiedPattern, type.sourceName(), this.isCaseSensitive); |
511 |
} |
486 |
} |
512 |
} else if (qualificationPattern == null) { |
487 |
} else if (qualificationPattern == null) { |
513 |
match = CharOperation.equals(qualifiedPattern, qualifiedSourceName(type), this.isCaseSensitive); |
488 |
match = CharOperation.equals(qualifiedPattern, getQualifiedSourceName(type), this.isCaseSensitive); |
514 |
} |
489 |
} |
515 |
return match ? ACCURATE_MATCH : IMPOSSIBLE_MATCH; |
490 |
return match ? ACCURATE_MATCH : IMPOSSIBLE_MATCH; |
516 |
} |
|
|
517 |
/* (non-Javadoc) |
518 |
* SEARCH_15 |
519 |
* Resolve level for type with a given binding with all pattern information. |
520 |
*/ |
521 |
protected int resolveLevelForType (char[] simpleNamePattern, |
522 |
char[] qualificationPattern, |
523 |
char[][] typeNames, |
524 |
boolean mustResolve, |
525 |
boolean declaration, |
526 |
TypeBinding type) { |
527 |
int level = resolveLevelForType(simpleNamePattern, qualificationPattern, type); |
528 |
if (level == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH; |
529 |
if (type == null) return level; |
530 |
|
531 |
// pattern has no type parameter |
532 |
if (typeNames == null || typeNames.length == 0) { |
533 |
return level; |
534 |
} |
535 |
|
536 |
// pattern has type parameter(s) or type argument(s) |
537 |
boolean isRawType = type.isRawType(); |
538 |
if (type.isGenericType()) { |
539 |
// Binding is generic, get its type variable(s) |
540 |
TypeVariableBinding[] typeVariables = null; |
541 |
if (type instanceof SourceTypeBinding) { |
542 |
SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type; |
543 |
typeVariables = sourceTypeBinding.typeVariables; |
544 |
} else if (type instanceof BinaryTypeBinding) { |
545 |
BinaryTypeBinding binaryTypeBinding = (BinaryTypeBinding) type; |
546 |
if (mustResolve) |
547 |
typeVariables = binaryTypeBinding.typeVariables(); // TODO (frederic) do we really want to resolve? |
548 |
} |
549 |
// type variables length must match at least specified type names length |
550 |
if (typeVariables == null || typeVariables.length == 0) { |
551 |
return IMPOSSIBLE_MATCH; |
552 |
} |
553 |
int length = typeNames.length; |
554 |
if (typeVariables.length != length) return IMPOSSIBLE_MATCH; |
555 |
// verify each parameters |
556 |
return level; // we can't do better |
557 |
// TODO (frederic) need to do more verifications here? |
558 |
} else if (!type.isParameterizedType() && !isRawType) { |
559 |
// Standard types (ie. neither generic nor parameterized nor raw types) |
560 |
// cannot match pattern when it has type parameters or arguments |
561 |
return IMPOSSIBLE_MATCH; |
562 |
} else { |
563 |
// Binding is parameterized type |
564 |
ParameterizedTypeBinding paramTypeBinding = (ParameterizedTypeBinding) type; |
565 |
if (paramTypeBinding.arguments == null) { |
566 |
// binding has no type parameters => ok for raw types |
567 |
if (isRawType) return level; |
568 |
// need to verify hierarchy for member types |
569 |
if (type.isMemberType() && qualificationPattern != null) { |
570 |
int lastDot = CharOperation.lastIndexOf('.', qualificationPattern); |
571 |
char[] enclosingQualificationPattern = lastDot==-1 ? null : CharOperation.subarray(qualificationPattern, 0, lastDot); |
572 |
char[] enclosingSimpleNamePattern = lastDot==-1 ? qualificationPattern : CharOperation.subarray(qualificationPattern, lastDot+1, qualificationPattern.length); |
573 |
if (resolveLevelForType(enclosingSimpleNamePattern, enclosingQualificationPattern, typeNames, mustResolve, declaration, paramTypeBinding.enclosingType()) == IMPOSSIBLE_MATCH) { |
574 |
return IMPOSSIBLE_MATCH; |
575 |
} |
576 |
return level; |
577 |
} |
578 |
return IMPOSSIBLE_MATCH; |
579 |
} |
580 |
// type parameters length must match at least specified type names length |
581 |
int length = typeNames.length; |
582 |
if (paramTypeBinding.arguments.length != length) return IMPOSSIBLE_MATCH; |
583 |
// verify each type parameter |
584 |
if (declaration) { |
585 |
// TODO (frederic) more verification to do here with type parameter bounds? |
586 |
return level; |
587 |
} |
588 |
nextTypeArgument: for (int i= 0; i<length; i++) { |
589 |
char[] argType = typeNames[i]; |
590 |
TypeBinding argTypeBinding = paramTypeBinding.arguments[i]; |
591 |
// get pattern wildcard |
592 |
int patternWildcard = this.pattern.wildcards[i]; |
593 |
if (patternWildcard == Wildcard.UNBOUND) continue; |
594 |
// try to resolve pattern |
595 |
TypeBinding patternBinding = this.pattern.getTypeNameBinding(this.unitScope, i); |
596 |
if (patternBinding != null) { |
597 |
// We can bind pattern type name => verify that types are compatible |
598 |
if (argTypeBinding == patternBinding) continue; |
599 |
if (argTypeBinding.isWildcard()) { |
600 |
TypeBinding bound = ((WildcardBinding) argTypeBinding).bound; |
601 |
if (this.pattern.wildcards != null) { |
602 |
switch (this.pattern.wildcards[i]) { |
603 |
case Wildcard.SUPER: |
604 |
if (bound == null || patternBinding.isCompatibleWith(bound)) |
605 |
// argument type is in bound hierarchy => valid |
606 |
continue; |
607 |
break; |
608 |
case Wildcard.EXTENDS: |
609 |
if (bound == null || bound.isCompatibleWith(patternBinding)) |
610 |
// argument type is a subclass of bound => valid |
611 |
continue; |
612 |
break; |
613 |
default: //UNBOUND |
614 |
// there's no bound name to match => valid |
615 |
continue; |
616 |
} |
617 |
} |
618 |
} |
619 |
return IMPOSSIBLE_MATCH; |
620 |
} |
621 |
|
622 |
// pattern hasn't be solved, try to see if names match in hierarchy |
623 |
// First if type argument is a wildcard |
624 |
if (argTypeBinding.isWildcard()) { |
625 |
WildcardBinding wildcardBinding = (WildcardBinding) argTypeBinding; |
626 |
switch (wildcardBinding.kind) { |
627 |
case Wildcard.EXTENDS: |
628 |
// We cannot know in this case... |
629 |
level = INACCURATE_MATCH; |
630 |
case Wildcard.UNBOUND: |
631 |
// there's no bound name to match => valid |
632 |
continue; |
633 |
} |
634 |
// try to match name in hierarchy |
635 |
ReferenceBinding boundBinding = (ReferenceBinding) wildcardBinding.bound; |
636 |
while (boundBinding != null) { |
637 |
if (CharOperation.equals(argType, boundBinding.shortReadableName(), this.isCaseSensitive) || |
638 |
CharOperation.equals(argType, boundBinding.readableName(), this.isCaseSensitive)) { |
639 |
continue nextTypeArgument; |
640 |
} |
641 |
boundBinding = boundBinding.superclass(); |
642 |
} |
643 |
return IMPOSSIBLE_MATCH; |
644 |
} |
645 |
|
646 |
// try to match names when there's no wildcard |
647 |
ReferenceBinding refBinding = null; |
648 |
if (argTypeBinding.isArrayType()) { |
649 |
TypeBinding leafBinding = ((ArrayBinding) argTypeBinding).leafComponentType; |
650 |
if (!leafBinding.isBaseType()) { |
651 |
refBinding = (ReferenceBinding) leafBinding; |
652 |
} |
653 |
} else if (!argTypeBinding.isBaseType()) { |
654 |
refBinding = (ReferenceBinding) argTypeBinding; |
655 |
} |
656 |
if (refBinding == null) { |
657 |
// Based type |
658 |
if (!CharOperation.equals(argType, argTypeBinding.shortReadableName(), this.isCaseSensitive) && |
659 |
!CharOperation.equals(argType, argTypeBinding.readableName(), this.isCaseSensitive)) { |
660 |
return IMPOSSIBLE_MATCH; |
661 |
} |
662 |
} else { |
663 |
while (refBinding != null) { |
664 |
if (CharOperation.equals(argType, refBinding.shortReadableName(), this.isCaseSensitive) || |
665 |
CharOperation.equals(argType, refBinding.readableName(), this.isCaseSensitive)) { |
666 |
continue nextTypeArgument; |
667 |
} |
668 |
refBinding = refBinding.superclass(); |
669 |
} |
670 |
return IMPOSSIBLE_MATCH; |
671 |
} |
672 |
} |
673 |
return level; |
674 |
} |
675 |
} |
491 |
} |
676 |
/** |
492 |
/** |
677 |
* Returns whether the given type binding or one of its enclosing types |
493 |
* Returns whether the given type binding or one of its enclosing types |