KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > search > matching > PatternLocator


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.search.matching;
12
13 import org.eclipse.core.runtime.*;
14 import org.eclipse.jdt.core.*;
15 import org.eclipse.jdt.core.compiler.*;
16 import org.eclipse.jdt.core.search.*;
17 import org.eclipse.jdt.internal.compiler.ast.*;
18 import org.eclipse.jdt.internal.compiler.lookup.*;
19 import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
20
21 public abstract class PatternLocator implements IIndexConstants {
22
23 // store pattern info
24
protected int matchMode;
25 protected boolean isCaseSensitive;
26 protected boolean isCamelCase;
27 protected boolean isEquivalentMatch;
28 protected boolean isErasureMatch;
29 protected boolean mustResolve;
30 protected boolean mayBeGeneric;
31
32 // match to report
33
SearchMatch match = null;
34
35 /* match levels */
36 public static final int IMPOSSIBLE_MATCH = 0;
37 public static final int INACCURATE_MATCH = 1;
38 public static final int POSSIBLE_MATCH = 2;
39 public static final int ACCURATE_MATCH = 3;
40 public static final int ERASURE_MATCH = 4;
41
42 // Possible rule match flavors
43
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=79866
44
public static final int EXACT_FLAVOR = 0x0010;
45 public static final int PREFIX_FLAVOR = 0x0020;
46 public static final int PATTERN_FLAVOR = 0x0040;
47 public static final int REGEXP_FLAVOR = 0x0080;
48 public static final int CAMELCASE_FLAVOR = 0x0100;
49 public static final int SUPER_INVOCATION_FLAVOR = 0x0200;
50 public static final int SUB_INVOCATION_FLAVOR = 0x0400;
51 public static final int OVERRIDDEN_METHOD_FLAVOR = 0x0800;
52 public static final int MATCH_LEVEL_MASK = 0x0F;
53 public static final int FLAVORS_MASK = ~MATCH_LEVEL_MASK;
54
55 /* match container */
56 public static final int COMPILATION_UNIT_CONTAINER = 1;
57 public static final int CLASS_CONTAINER = 2;
58 public static final int METHOD_CONTAINER = 4;
59 public static final int FIELD_CONTAINER = 8;
60 public static final int ALL_CONTAINER =
61     COMPILATION_UNIT_CONTAINER | CLASS_CONTAINER | METHOD_CONTAINER | FIELD_CONTAINER;
62
63 /* match rule */
64 public static final int RAW_MASK = SearchPattern.R_EQUIVALENT_MATCH | SearchPattern.R_ERASURE_MATCH;
65 public static final int RULE_MASK = RAW_MASK; // no other values for the while...
66

67 public static PatternLocator patternLocator(SearchPattern pattern) {
68     switch (((InternalSearchPattern)pattern).kind) {
69         case IIndexConstants.PKG_REF_PATTERN :
70             return new PackageReferenceLocator((PackageReferencePattern) pattern);
71         case IIndexConstants.PKG_DECL_PATTERN :
72             return new PackageDeclarationLocator((PackageDeclarationPattern) pattern);
73         case IIndexConstants.TYPE_REF_PATTERN :
74             return new TypeReferenceLocator((TypeReferencePattern) pattern);
75         case IIndexConstants.TYPE_DECL_PATTERN :
76             return new TypeDeclarationLocator((TypeDeclarationPattern) pattern);
77         case IIndexConstants.SUPER_REF_PATTERN :
78             return new SuperTypeReferenceLocator((SuperTypeReferencePattern) pattern);
79         case IIndexConstants.CONSTRUCTOR_PATTERN :
80             return new ConstructorLocator((ConstructorPattern) pattern);
81         case IIndexConstants.FIELD_PATTERN :
82             return new FieldLocator((FieldPattern) pattern);
83         case IIndexConstants.METHOD_PATTERN :
84             return new MethodLocator((MethodPattern) pattern);
85         case IIndexConstants.OR_PATTERN :
86             return new OrLocator((OrPattern) pattern);
87         case IIndexConstants.LOCAL_VAR_PATTERN :
88             return new LocalVariableLocator((LocalVariablePattern) pattern);
89         case IIndexConstants.TYPE_PARAM_PATTERN:
90             return new TypeParameterLocator((TypeParameterPattern) pattern);
91     }
92     return null;
93 }
94 public static char[] qualifiedPattern(char[] simpleNamePattern, char[] qualificationPattern) {
95     // NOTE: if case insensitive search then simpleNamePattern & qualificationPattern are assumed to be lowercase
96
if (simpleNamePattern == null) {
97         if (qualificationPattern == null) return null;
98         return CharOperation.concat(qualificationPattern, ONE_STAR, '.');
99     } else {
100         return qualificationPattern == null
101             ? CharOperation.concat(ONE_STAR, simpleNamePattern)
102             : CharOperation.concat(qualificationPattern, simpleNamePattern, '.');
103     }
104 }
105 public static char[] qualifiedSourceName(TypeBinding binding) {
106     if (binding instanceof ReferenceBinding) {
107         ReferenceBinding type = (ReferenceBinding) binding;
108         if (type.isLocalType())
109             return type.isMemberType()
110                 ? CharOperation.concat(qualifiedSourceName(type.enclosingType()), type.sourceName(), '.')
111                 : CharOperation.concat(qualifiedSourceName(type.enclosingType()), new char[] {'.', '1', '.'}, type.sourceName());
112     }
113     return binding != null ? binding.qualifiedSourceName() : null;
114 }
115
116 public PatternLocator(SearchPattern pattern) {
117     int matchRule = pattern.getMatchRule();
118     this.isCaseSensitive = (matchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
119     this.isCamelCase = (matchRule & SearchPattern.R_CAMELCASE_MATCH) != 0;
120     this.isErasureMatch = (matchRule & SearchPattern.R_ERASURE_MATCH) != 0;
121     this.isEquivalentMatch = (matchRule & SearchPattern.R_EQUIVALENT_MATCH) != 0;
122     this.matchMode = matchRule & JavaSearchPattern.MATCH_MODE_MASK;
123     this.mustResolve = ((InternalSearchPattern)pattern).mustResolve;
124 }
125 /*
126  * Clear caches
127  */

128 protected void clear() {
129     // nothing to clear by default
130
}
131 /* (non-Javadoc)
132  * Modify PatternLocator.qualifiedPattern behavior:
133  * do not add star before simple name pattern when qualification pattern is null.
134  * This avoid to match p.X when pattern is only X...
135  */

136 protected char[] getQualifiedPattern(char[] simpleNamePattern, char[] qualificationPattern) {
137     // NOTE: if case insensitive search then simpleNamePattern & qualificationPattern are assumed to be lowercase
138
if (simpleNamePattern == null) {
139         if (qualificationPattern == null) return null;
140         return CharOperation.concat(qualificationPattern, ONE_STAR, '.');
141     } else if (qualificationPattern == null) {
142         return simpleNamePattern;
143     } else {
144         return CharOperation.concat(qualificationPattern, simpleNamePattern, '.');
145     }
146 }
147 /* (non-Javadoc)
148  * Modify PatternLocator.qualifiedSourceName behavior:
149  * also concatene enclosing type name when type is a only a member type.
150  */

151 protected char[] getQualifiedSourceName(TypeBinding binding) {
152     TypeBinding type = binding instanceof ArrayBinding ? ((ArrayBinding)binding).leafComponentType : binding;
153     if (type instanceof ReferenceBinding) {
154         if (type.isLocalType()) {
155             return CharOperation.concat(qualifiedSourceName(type.enclosingType()), new char[] {'.', '1', '.'}, binding.sourceName());
156         } else if (type.isMemberType()) {
157             return CharOperation.concat(qualifiedSourceName(type.enclosingType()), binding.sourceName(), '.');
158         }
159     }
160     return binding != null ? binding.qualifiedSourceName() : null;
161 }
162 /*
163  * Get binding of type argument from a class unit scope and its index position.
164  * Cache is lazy initialized and if no binding is found, then store a problem binding
165  * to avoid making research twice...
166  */

167 protected TypeBinding getTypeNameBinding(int index) {
168     return null;
169 }
170 /**
171  * Initializes this search pattern so that polymorphic search can be performed.
172  */

173 public void initializePolymorphicSearch(MatchLocator locator) {
174     // default is to do nothing
175
}
176 public int match(Annotation node, MatchingNodeSet nodeSet) {
177     // each subtype should override if needed
178
return IMPOSSIBLE_MATCH;
179 }
180 /**
181  * Check if the given ast node syntactically matches this pattern.
182  * If it does, add it to the match set.
183  * Returns the match level.
184  */

185 public int match(ASTNode node, MatchingNodeSet nodeSet) { // needed for some generic nodes
186
// each subtype should override if needed
187
return IMPOSSIBLE_MATCH;
188 }
189 public int match(ConstructorDeclaration node, MatchingNodeSet nodeSet) {
190     // each subtype should override if needed
191
return IMPOSSIBLE_MATCH;
192 }
193 public int match(Expression node, MatchingNodeSet nodeSet) {
194     // each subtype should override if needed
195
return IMPOSSIBLE_MATCH;
196 }
197 public int match(FieldDeclaration node, MatchingNodeSet nodeSet) {
198     // each subtype should override if needed
199
return IMPOSSIBLE_MATCH;
200 }
201 public int match(LocalDeclaration node, MatchingNodeSet nodeSet) {
202     // each subtype should override if needed
203
return IMPOSSIBLE_MATCH;
204 }
205 public int match(MethodDeclaration node, MatchingNodeSet nodeSet) {
206     // each subtype should override if needed
207
return IMPOSSIBLE_MATCH;
208 }
209 public int match(MemberValuePair node, MatchingNodeSet nodeSet) {
210     // each subtype should override if needed
211
return IMPOSSIBLE_MATCH;
212 }
213 public int match(MessageSend node, MatchingNodeSet nodeSet) {
214     // each subtype should override if needed
215
return IMPOSSIBLE_MATCH;
216 }
217 public int match(Reference node, MatchingNodeSet nodeSet) {
218     // each subtype should override if needed
219
return IMPOSSIBLE_MATCH;
220 }
221 public int match(TypeDeclaration node, MatchingNodeSet nodeSet) {
222     // each subtype should override if needed
223
return IMPOSSIBLE_MATCH;
224 }
225 public int match(TypeParameter node, MatchingNodeSet nodeSet) {
226     // each subtype should override if needed
227
return IMPOSSIBLE_MATCH;
228 }
229 public int match(TypeReference node, MatchingNodeSet nodeSet) {
230     // each subtype should override if needed
231
return IMPOSSIBLE_MATCH;
232 }
233 /**
234  * Returns the type(s) of container for this pattern.
235  * It is a bit combination of types, denoting compilation unit, class declarations, field declarations or method declarations.
236  */

237 protected int matchContainer() {
238     // override if the pattern can be more specific
239
return ALL_CONTAINER;
240 }
241 /**
242  * Returns whether the given name matches the given pattern.
243  */

244 protected boolean matchesName(char[] pattern, char[] name) {
245     if (pattern == null) return true; // null is as if it was "*"
246
if (name == null) return false; // cannot match null name
247
return matchNameValue(pattern, name) != IMPOSSIBLE_MATCH;
248 }
249 /**
250  * Return how the given name matches the given pattern.
251  * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=79866"
252  *
253  * @param pattern
254  * @param name
255  * @return Possible values are:
256  * <ul>
257  * <li> {@link #ACCURATE_MATCH}</li>
258  * <li> {@link #IMPOSSIBLE_MATCH}</li>
259  * <li> {@link #POSSIBLE_MATCH} which may be flavored with following values:
260  * <ul>
261  * <li>{@link #EXACT_FLAVOR}: Given name is equals to pattern</li>
262  * <li>{@link #PREFIX_FLAVOR}: Given name prefix equals to pattern</li>
263  * <li>{@link #CAMELCASE_FLAVOR}: Given name matches pattern as Camel Case</li>
264  * <li>{@link #PATTERN_FLAVOR}: Given name matches pattern as Pattern (ie. using '*' and '?' characters)</li>
265  * </ul>
266  * </li>
267  * </ul>
268  */

269 protected int matchNameValue(char[] pattern, char[] name) {
270     if (pattern == null) return ACCURATE_MATCH; // null is as if it was "*"
271
if (name == null) return IMPOSSIBLE_MATCH; // cannot match null name
272
if (name.length == 0) { // empty name
273
if (pattern.length == 0) { // can only matches empty pattern
274
return ACCURATE_MATCH;
275         }
276         return IMPOSSIBLE_MATCH;
277     } else if (pattern.length == 0) {
278         return IMPOSSIBLE_MATCH; // need to have both name and pattern length==0 to be accurate
279
}
280     boolean matchFirstChar = !this.isCaseSensitive || pattern[0] == name[0];
281     boolean sameLength = pattern.length == name.length;
282     boolean canBePrefix = name.length >= pattern.length;
283     if (this.isCamelCase && matchFirstChar && CharOperation.camelCaseMatch(pattern, name)) {
284         return POSSIBLE_MATCH;
285     }
286     switch (this.matchMode) {
287         case SearchPattern.R_EXACT_MATCH:
288             if (!this.isCamelCase) {
289                 if (sameLength && matchFirstChar && CharOperation.equals(pattern, name, this.isCaseSensitive)) {
290                     return POSSIBLE_MATCH | EXACT_FLAVOR;
291                 }
292                 break;
293             }
294             // fall through next case to match as prefix if camel case failed
295
case SearchPattern.R_PREFIX_MATCH:
296             if (canBePrefix && matchFirstChar && CharOperation.prefixEquals(pattern, name, this.isCaseSensitive)) {
297                 return POSSIBLE_MATCH;
298             }
299             break;
300         case SearchPattern.R_PATTERN_MATCH:
301             if (!this.isCaseSensitive) {
302                 pattern = CharOperation.toLowerCase(pattern);
303             }
304             if (CharOperation.match(pattern, name, this.isCaseSensitive)) {
305                 return POSSIBLE_MATCH;
306             }
307             break;
308         case SearchPattern.R_REGEXP_MATCH :
309             // TODO (frederic) implement regular expression match
310
break;
311     }
312     return IMPOSSIBLE_MATCH;
313 }
314 /**
315  * Returns whether the given type reference matches the given pattern.
316  */

317 protected boolean matchesTypeReference(char[] pattern, TypeReference type) {
318     if (pattern == null) return true; // null is as if it was "*"
319
if (type == null) return true; // treat as an inexact match
320

321     char[][] compoundName = type.getTypeName();
322     char[] simpleName = compoundName[compoundName.length - 1];
323     int dimensions = type.dimensions() * 2;
324     if (dimensions > 0) {
325         int length = simpleName.length;
326         char[] result = new char[length + dimensions];
327         System.arraycopy(simpleName, 0, result, 0, length);
328         for (int i = length, l = result.length; i < l;) {
329             result[i++] = '[';
330             result[i++] = ']';
331         }
332         simpleName = result;
333     }
334
335     return matchesName(pattern, simpleName);
336 }
337 /**
338  * Returns the match level for the given importRef.
339  */

340 protected int matchLevel(ImportReference importRef) {
341     // override if interested in import references which are caught by the generic version of match(ASTNode, MatchingNodeSet)
342
return IMPOSSIBLE_MATCH;
343 }
344 /**
345  * Reports the match of the given import reference if the resolveLevel is high enough.
346  */

347 protected void matchLevelAndReportImportRef(ImportReference importRef, Binding binding, MatchLocator locator) throws CoreException {
348     int level = resolveLevel(binding);
349     if (level >= INACCURATE_MATCH) {
350         matchReportImportRef(
351             importRef,
352             binding,
353             locator.createImportHandle(importRef),
354             level == ACCURATE_MATCH
355                 ? SearchMatch.A_ACCURATE
356                 : SearchMatch.A_INACCURATE,
357             locator);
358     }
359 }
360 /**
361  * Reports the match of the given import reference.
362  */

363 protected void matchReportImportRef(ImportReference importRef, Binding binding, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
364     if (locator.encloses(element)) {
365         // default is to report a match as a regular ref.
366
this.matchReportReference(importRef, element, null/*no binding*/, accuracy, locator);
367     }
368 }
369 /**
370  * Reports the match of the given reference.
371  */

372 protected void matchReportReference(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException {
373     match = null;
374     int referenceType = referenceType();
375     int offset = reference.sourceStart;
376     switch (referenceType) {
377         case IJavaElement.PACKAGE_FRAGMENT:
378             match = locator.newPackageReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
379             break;
380         case IJavaElement.TYPE:
381             match = locator.newTypeReferenceMatch(element, elementBinding, accuracy, offset, reference.sourceEnd-offset+1, reference);
382             break;
383         case IJavaElement.FIELD:
384             match = locator.newFieldReferenceMatch(element, elementBinding, accuracy, offset, reference.sourceEnd-offset+1, reference);
385             break;
386         case IJavaElement.LOCAL_VARIABLE:
387             match = locator.newLocalVariableReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
388             break;
389         case IJavaElement.TYPE_PARAMETER:
390             match = locator.newTypeParameterReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
391             break;
392     }
393     if (match != null) {
394         locator.report(match);
395     }
396 }
397 /**
398  * Reports the match of the given reference. Also provide a local element to eventually report in match.
399  */

400 protected void matchReportReference(ASTNode reference, IJavaElement element, IJavaElement localElement, IJavaElement[] otherElements, Binding elementBinding, int accuracy, MatchLocator locator) throws CoreException {
401     matchReportReference(reference, element, elementBinding, accuracy, locator);
402 }
403 /**
404  * Reports the match of the given reference. Also provide a scope to look for potential other elements.
405  */

406 protected void matchReportReference(ASTNode reference, IJavaElement element, Binding elementBinding, Scope scope, int accuracy, MatchLocator locator) throws CoreException {
407     matchReportReference(reference, element, elementBinding, accuracy, locator);
408 }
409 public SearchMatch newDeclarationMatch(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, int length, MatchLocator locator) {
410     return locator.newDeclarationMatch(element, elementBinding, accuracy, reference.sourceStart, length);
411 }
412 protected int referenceType() {
413     return 0; // defaults to unknown (a generic JavaSearchMatch will be created)
414
}
415 /**
416  * Finds out whether the given ast node matches this search pattern.
417  * Returns IMPOSSIBLE_MATCH if it doesn't.
418  * Returns INACCURATE_MATCH if it potentially matches this search pattern (ie.
419  * it has already been resolved but resolving failed.)
420  * Returns ACCURATE_MATCH if it matches exactly this search pattern (ie.
421  * it doesn't need to be resolved or it has already been resolved.)
422  */

423 public int resolveLevel(ASTNode possibleMatchingNode) {
424     // only called with nodes which were possible matches to the call to matchLevel
425
// need to do instance of checks to find out exact type of ASTNode
426
return IMPOSSIBLE_MATCH;
427 }
428 /*
429  * Update pattern locator match for parameterized top level types.
430  * Set match raw flag and recurse to enclosing types if any...
431  */

432 protected void updateMatch(ParameterizedTypeBinding parameterizedBinding, char[][][] patternTypeArguments, MatchLocator locator) {
433     // Only possible if locator has an unit scope.
434
if (locator.unitScope != null) {
435         updateMatch(parameterizedBinding, patternTypeArguments, false, 0, locator);
436     }
437 }
438 protected void updateMatch(ParameterizedTypeBinding parameterizedBinding, char[][][] patternTypeArguments, boolean patternHasTypeParameters, int depth, MatchLocator locator) {
439     // Only possible if locator has an unit scope.
440
if (locator.unitScope == null) return;
441
442     // Set match raw flag
443
boolean endPattern = patternTypeArguments==null ? true : depth>=patternTypeArguments.length;
444     TypeBinding[] argumentsBindings = parameterizedBinding.arguments;
445     boolean isRaw = parameterizedBinding.isRawType()|| (argumentsBindings==null && parameterizedBinding.genericType().isGenericType());
446     if (isRaw && !match.isRaw()) {
447         match.setRaw(isRaw);
448     }
449     
450     // Update match
451
if (!endPattern && patternTypeArguments != null) {
452         // verify if this is a reference to the generic type itself
453
if (!isRaw && patternHasTypeParameters && argumentsBindings != null) {
454             boolean needUpdate = false;
455             TypeVariableBinding[] typeVariables = parameterizedBinding.genericType().typeVariables();
456             for (int i=0, l=argumentsBindings.length; i<l; i++) {
457                 if (argumentsBindings[i] != typeVariables[i]) {
458                     needUpdate = true;
459                     break;
460                 }
461             }
462             if (needUpdate) {
463                 char[][] patternArguments = patternTypeArguments[depth];
464                 updateMatch(argumentsBindings, locator, patternArguments, patternHasTypeParameters);
465             }
466         } else {
467             char[][] patternArguments = patternTypeArguments[depth];
468             updateMatch(argumentsBindings, locator, patternArguments, patternHasTypeParameters);
469         }
470     }
471
472     // Recurse
473
TypeBinding enclosingType = parameterizedBinding.enclosingType();
474     if (enclosingType != null && (enclosingType.isParameterizedType() || enclosingType.isRawType())) {
475         updateMatch((ParameterizedTypeBinding)enclosingType, patternTypeArguments, patternHasTypeParameters, depth+1, locator);
476     }
477 }
478 /*
479  * Update pattern locator match comparing type arguments with pattern ones.
480  * Try to resolve pattern and look for compatibility with type arguments
481  * to set match rule.
482  */

483 protected void updateMatch(TypeBinding[] argumentsBinding, MatchLocator locator, char[][] patternArguments, boolean hasTypeParameters) {
484     // Only possible if locator has an unit scope.
485
if (locator.unitScope == null) return;
486
487     // First compare lengthes
488
int patternTypeArgsLength = patternArguments==null ? 0 : patternArguments.length;
489     int typeArgumentsLength = argumentsBinding == null ? 0 : argumentsBinding.length;
490
491     // Initialize match rule
492
int matchRule = match.getRule();
493     if (match.isRaw()) {
494         if (patternTypeArgsLength != 0) {
495             matchRule &= ~SearchPattern.R_FULL_MATCH;
496         }
497     }
498     if (hasTypeParameters) {
499         matchRule = SearchPattern.R_ERASURE_MATCH;
500     }
501     
502     // Compare arguments lengthes
503
if (patternTypeArgsLength == typeArgumentsLength) {
504         if (!match.isRaw() && hasTypeParameters) {
505             // generic patterns are always not compatible match
506
match.setRule(SearchPattern.R_ERASURE_MATCH);
507             return;
508         }
509     } else {
510         if (patternTypeArgsLength==0) {
511             if (!match.isRaw() || hasTypeParameters) {
512                 match.setRule(matchRule & ~SearchPattern.R_FULL_MATCH);
513             }
514         } else if (typeArgumentsLength==0) {
515             // raw binding is always compatible
516
match.setRule(matchRule & ~SearchPattern.R_FULL_MATCH);
517         } else {
518             match.setRule(0); // impossible match
519
}
520         return;
521     }
522     if (argumentsBinding == null || patternArguments == null) {
523         match.setRule(matchRule);
524         return;
525     }
526
527     // Compare binding for each type argument only if pattern is not erasure only and at first level
528
if (!hasTypeParameters && !match.isRaw() && (match.isEquivalent() || match.isExact())) {
529         for (int i=0; i<typeArgumentsLength; i++) {
530             // Get parameterized type argument binding
531
TypeBinding argumentBinding = argumentsBinding[i];
532             if (argumentBinding instanceof CaptureBinding) {
533                 WildcardBinding capturedWildcard = ((CaptureBinding)argumentBinding).wildcard;
534                 if (capturedWildcard != null) argumentBinding = capturedWildcard;
535             }
536             // Get binding for pattern argument
537
char[] patternTypeArgument = patternArguments[i];
538             char patternWildcard = patternTypeArgument[0];
539             char[] patternTypeName = patternTypeArgument;
540             int patternWildcardKind = -1;
541             switch (patternWildcard) {
542                 case Signature.C_STAR:
543                     if (argumentBinding.isWildcard()) {
544                         WildcardBinding wildcardBinding = (WildcardBinding) argumentBinding;
545                         if (wildcardBinding.boundKind == Wildcard.UNBOUND) continue;
546                     }
547                     matchRule &= ~SearchPattern.R_FULL_MATCH;
548                     continue; // unbound parameter always match
549
case Signature.C_EXTENDS :
550                     patternWildcardKind = Wildcard.EXTENDS;
551                     patternTypeName = CharOperation.subarray(patternTypeArgument, 1, patternTypeArgument.length);
552                     break;
553                 case Signature.C_SUPER :
554                     patternWildcardKind = Wildcard.SUPER;
555                     patternTypeName = CharOperation.subarray(patternTypeArgument, 1, patternTypeArgument.length);
556                 default :
557                     break;
558             }
559             patternTypeName = Signature.toCharArray(patternTypeName);
560             TypeBinding patternBinding = locator.getType(patternTypeArgument, patternTypeName);
561             
562             // If have no binding for pattern arg, then we won't be able to refine accuracy
563
if (patternBinding == null) {
564                 if (argumentBinding.isWildcard()) {
565                     WildcardBinding wildcardBinding = (WildcardBinding) argumentBinding;
566                     if (wildcardBinding.boundKind == Wildcard.UNBOUND) {
567                         matchRule &= ~SearchPattern.R_FULL_MATCH;
568                     } else {
569                         match.setRule(SearchPattern.R_ERASURE_MATCH);
570                         return;
571                     }
572                 }
573                 continue;
574             }
575                 
576             // Verify tha pattern binding is compatible with match type argument binding
577
switch (patternWildcard) {
578                 case Signature.C_STAR : // UNBOUND pattern
579
// unbound always match => skip to next argument
580
matchRule &= ~SearchPattern.R_FULL_MATCH;
581                     continue;
582                 case Signature.C_EXTENDS : // EXTENDS pattern
583
if (argumentBinding.isWildcard()) { // argument is a wildcard
584
WildcardBinding wildcardBinding = (WildcardBinding) argumentBinding;
585                         // It's ok if wildcards are identical
586
if (wildcardBinding.boundKind == patternWildcardKind && wildcardBinding.bound == patternBinding) {
587                             continue;
588                         }
589                         // Look for wildcard compatibility
590
switch (wildcardBinding.boundKind) {
591                             case Wildcard.EXTENDS:
592                                 if (wildcardBinding.bound== null || wildcardBinding.bound.isCompatibleWith(patternBinding)) {
593                                     // valid when arg extends a subclass of pattern
594
matchRule &= ~SearchPattern.R_FULL_MATCH;
595                                     continue;
596                                 }
597                                 break;
598                             case Wildcard.SUPER:
599                                 break;
600                             case Wildcard.UNBOUND:
601                                 matchRule &= ~SearchPattern.R_FULL_MATCH;
602                                 continue;
603                         }
604                     } else if (argumentBinding.isCompatibleWith(patternBinding)) {
605                         // valid when arg is a subclass of pattern
606
matchRule &= ~SearchPattern.R_FULL_MATCH;
607                         continue;
608                     }
609                     break;
610                 case Signature.C_SUPER : // SUPER pattern
611
if (argumentBinding.isWildcard()) { // argument is a wildcard
612
WildcardBinding wildcardBinding = (WildcardBinding) argumentBinding;
613                         // It's ok if wildcards are identical
614
if (wildcardBinding.boundKind == patternWildcardKind && wildcardBinding.bound == patternBinding) {
615                             continue;
616                         }
617                         // Look for wildcard compatibility
618
switch (wildcardBinding.boundKind) {
619                             case Wildcard.EXTENDS:
620                                 break;
621                             case Wildcard.SUPER:
622                                 if (wildcardBinding.bound== null || patternBinding.isCompatibleWith(wildcardBinding.bound)) {
623                                     // valid only when arg super a superclass of pattern
624
matchRule &= ~SearchPattern.R_FULL_MATCH;
625                                     continue;
626                                 }
627                                 break;
628                             case Wildcard.UNBOUND:
629                                 matchRule &= ~SearchPattern.R_FULL_MATCH;
630                                 continue;
631                         }
632                     } else if (patternBinding.isCompatibleWith(argumentBinding)) {
633                         // valid only when arg is a superclass of pattern
634
matchRule &= ~SearchPattern.R_FULL_MATCH;
635                         continue;
636                     }
637                     break;
638                 default:
639                     if (argumentBinding.isWildcard()) {
640                         WildcardBinding wildcardBinding = (WildcardBinding) argumentBinding;
641                         switch (wildcardBinding.boundKind) {
642                             case Wildcard.EXTENDS:
643                                 if (wildcardBinding.bound== null || patternBinding.isCompatibleWith(wildcardBinding.bound)) {
644                                     // valid only when arg extends a superclass of pattern
645
matchRule &= ~SearchPattern.R_FULL_MATCH;
646                                     continue;
647                                 }
648                                 break;
649                             case Wildcard.SUPER:
650                                 if (wildcardBinding.bound== null || wildcardBinding.bound.isCompatibleWith(patternBinding)) {
651                                     // valid only when arg super a subclass of pattern
652
matchRule &= ~SearchPattern.R_FULL_MATCH;
653                                     continue;
654                                 }
655                                 break;
656                             case Wildcard.UNBOUND:
657                                 matchRule &= ~SearchPattern.R_FULL_MATCH;
658                                 continue;
659                         }
660                     } else if (argumentBinding == patternBinding)
661                         // valid only when arg is equals to pattern
662
continue;
663                     break;
664             }
665             
666             // Argument does not match => erasure match will be the only possible one
667
match.setRule(SearchPattern.R_ERASURE_MATCH);
668             return;
669         }
670     }
671
672     // Set match rule
673
match.setRule(matchRule);
674 }
675 /**
676  * Finds out whether the given binding matches this search pattern.
677  * Returns ACCURATE_MATCH if it does.
678  * Returns INACCURATE_MATCH if resolve failed but match is still possible.
679  * Returns IMPOSSIBLE_MATCH otherwise.
680  * Default is to return INACCURATE_MATCH.
681  */

682 public int resolveLevel(Binding binding) {
683     // override if the pattern can match the binding
684
return INACCURATE_MATCH;
685 }
686 /**
687  * Returns whether the given type binding matches the given simple name pattern
688  * and qualification pattern.
689  * Note that from since 3.1, this method resolve to accurate member or local types
690  * even if they are not fully qualified (ie. X.Member instead of p.X.Member).
691  * Returns ACCURATE_MATCH if it does.
692  * Returns INACCURATE_MATCH if resolve failed.
693  * Returns IMPOSSIBLE_MATCH if it doesn't.
694  */

695 protected int resolveLevelForType(char[] simpleNamePattern, char[] qualificationPattern, TypeBinding binding) {
696 // return resolveLevelForType(qualifiedPattern(simpleNamePattern, qualificationPattern), type);
697
char[] qualifiedPattern = getQualifiedPattern(simpleNamePattern, qualificationPattern);
698     int level = resolveLevelForType(qualifiedPattern, binding);
699     if (level == ACCURATE_MATCH || binding == null) return level;
700     TypeBinding type = binding instanceof ArrayBinding ? ((ArrayBinding)binding).leafComponentType : binding;
701     char[] sourceName = null;
702     if (type.isMemberType() || type.isLocalType()) {
703         if (qualificationPattern != null) {
704             sourceName = getQualifiedSourceName(binding);
705         } else {
706             sourceName = binding.sourceName();
707         }
708     } else if (qualificationPattern == null) {
709         sourceName = getQualifiedSourceName(binding);
710     }
711     if (sourceName == null) return IMPOSSIBLE_MATCH;
712     if ((this.matchMode & SearchPattern.R_PREFIX_MATCH) != 0) {
713         if (CharOperation.prefixEquals(qualifiedPattern, sourceName, this.isCaseSensitive)) {
714             return ACCURATE_MATCH;
715         }
716     }
717     if (this.isCamelCase) {
718         if (!this.isCaseSensitive || (qualifiedPattern.length>0 && sourceName.length>0 && qualifiedPattern[0] == sourceName[0])) {
719             if (CharOperation.camelCaseMatch(qualifiedPattern, sourceName)) {
720                 return ACCURATE_MATCH;
721             }
722         }
723         if (this.matchMode == SearchPattern.R_EXACT_MATCH) {
724             boolean matchPattern = CharOperation.prefixEquals(qualifiedPattern, sourceName, this.isCaseSensitive);
725             return matchPattern ? ACCURATE_MATCH : IMPOSSIBLE_MATCH;
726         }
727     }
728     boolean matchPattern = CharOperation.match(qualifiedPattern, sourceName, this.isCaseSensitive);
729     return matchPattern ? ACCURATE_MATCH : IMPOSSIBLE_MATCH;
730
731 }
732
733 /**
734  * Returns whether the given type binding matches the given qualified pattern.
735  * Returns ACCURATE_MATCH if it does.
736  * Returns INACCURATE_MATCH if resolve failed.
737  * Returns IMPOSSIBLE_MATCH if it doesn't.
738  */

739 protected int resolveLevelForType(char[] qualifiedPattern, TypeBinding type) {
740     if (qualifiedPattern == null) return ACCURATE_MATCH;
741     if (type == null) return INACCURATE_MATCH;
742
743     // Type variable cannot be specified through pattern => this kind of binding cannot match it (see bug 79803)
744
if (type.isTypeVariable()) return IMPOSSIBLE_MATCH;
745
746     // NOTE: if case insensitive search then qualifiedPattern is assumed to be lowercase
747

748     char[] qualifiedPackageName = type.qualifiedPackageName();
749     char[] qualifiedSourceName = qualifiedSourceName(type);
750     char[] fullyQualifiedTypeName = qualifiedPackageName.length == 0
751         ? qualifiedSourceName
752         : CharOperation.concat(qualifiedPackageName, qualifiedSourceName, '.');
753     return CharOperation.match(qualifiedPattern, fullyQualifiedTypeName, this.isCaseSensitive)
754         ? ACCURATE_MATCH
755         : IMPOSSIBLE_MATCH;
756 }
757 /* (non-Javadoc)
758  * Resolve level for type with a given binding with all pattern information.
759  */

760 protected int resolveLevelForType (char[] simpleNamePattern,
761                                     char[] qualificationPattern,
762                                     char[][][] patternTypeArguments,
763                                     int depth,
764                                     TypeBinding type) {
765     // standard search with no generic additional information must succeed
766
int level = resolveLevelForType(simpleNamePattern, qualificationPattern, type);
767     if (level == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
768     if (type == null || patternTypeArguments == null || patternTypeArguments.length == 0 || depth >= patternTypeArguments.length) {
769         return level;
770     }
771     
772     // if pattern is erasure match (see bug 79790), commute impossible to erasure
773
int impossible = this.isErasureMatch ? ERASURE_MATCH : IMPOSSIBLE_MATCH;
774
775     // pattern has type parameter(s) or type argument(s)
776
if (type.isGenericType()) {
777         // Binding is generic, get its type variable(s)
778
TypeVariableBinding[] typeVariables = null;
779         if (type instanceof SourceTypeBinding) {
780             SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type;
781             typeVariables = sourceTypeBinding.typeVariables;
782         } else if (type instanceof BinaryTypeBinding) {
783             BinaryTypeBinding binaryTypeBinding = (BinaryTypeBinding) type;
784             if (this.mustResolve)
785                 typeVariables = binaryTypeBinding.typeVariables(); // TODO (frederic) verify performance
786
}
787         if (patternTypeArguments[depth] != null && patternTypeArguments[depth].length > 0 &&
788             typeVariables != null && typeVariables.length > 0) {
789             if (typeVariables.length != patternTypeArguments[depth].length) return IMPOSSIBLE_MATCH;
790         }
791         // TODO (frederic) do we need to verify each parameter?
792
return level; // we can't do better
793
} else if (type.isRawType()) {
794         return level; // raw type always match
795
} else {
796         TypeBinding leafType = type.leafComponentType();
797         if (!leafType.isParameterizedType()) {
798             // Standard types (ie. neither generic nor parameterized nor raw types)
799
// cannot match pattern with type parameters or arguments
800
return (patternTypeArguments[depth]==null || patternTypeArguments[depth].length==0) ? level : IMPOSSIBLE_MATCH;
801         }
802         ParameterizedTypeBinding paramTypeBinding = (ParameterizedTypeBinding) leafType;
803
804         // Compare arguments only if there ones on both sides
805
if (patternTypeArguments[depth] != null && patternTypeArguments[depth].length > 0 &&
806             paramTypeBinding.arguments != null && paramTypeBinding.arguments.length > 0) {
807
808             // type parameters length must match at least specified type names length
809
int length = patternTypeArguments[depth].length;
810             if (paramTypeBinding.arguments.length != length) return IMPOSSIBLE_MATCH;
811     
812             // verify each pattern type parameter
813
nextTypeArgument: for (int i= 0; i<length; i++) {
814                 char[] patternTypeArgument = patternTypeArguments[depth][i];
815                 TypeBinding argTypeBinding = paramTypeBinding.arguments[i];
816                 // get corresponding pattern wildcard
817
switch (patternTypeArgument[0]) {
818                     case Signature.C_STAR : // unbound parameter always match
819
case Signature.C_SUPER : // needs pattern type parameter binding
820
// skip to next type argument as it will be resolved later
821
continue nextTypeArgument;
822                     case Signature.C_EXTENDS :
823                         // remove wildcard from patter type argument
824
patternTypeArgument = CharOperation.subarray(patternTypeArgument, 1, patternTypeArgument.length);
825                     default :
826                         // no wildcard
827
break;
828                 }
829                 // get pattern type argument from its signature
830
patternTypeArgument = Signature.toCharArray(patternTypeArgument);
831                 if (!this.isCaseSensitive) patternTypeArgument = CharOperation.toLowerCase(patternTypeArgument);
832                 boolean patternTypeArgHasAnyChars = CharOperation.contains(new char[] {'*', '?'}, patternTypeArgument);
833     
834                 // Verify that names match...
835
// ...special case for wildcard
836
if (argTypeBinding instanceof CaptureBinding) {
837                     WildcardBinding capturedWildcard = ((CaptureBinding)argTypeBinding).wildcard;
838                     if (capturedWildcard != null) argTypeBinding = capturedWildcard;
839                 }
840                 if (argTypeBinding.isWildcard()) {
841                     WildcardBinding wildcardBinding = (WildcardBinding) argTypeBinding;
842                     switch (wildcardBinding.boundKind) {
843                         case Wildcard.EXTENDS:
844                             // Invalid if type argument is not exact
845
if (patternTypeArgHasAnyChars) return impossible;
846                         case Wildcard.UNBOUND:
847                             // there's no bound name to match => valid
848
continue nextTypeArgument;
849                     }
850                     // Look if bound name match pattern type argument
851
ReferenceBinding boundBinding = (ReferenceBinding) wildcardBinding.bound;
852                     if (CharOperation.match(patternTypeArgument, boundBinding.shortReadableName(), this.isCaseSensitive) ||
853                         CharOperation.match(patternTypeArgument, boundBinding.readableName(), this.isCaseSensitive)) {
854                         // found name in hierarchy => match
855
continue nextTypeArgument;
856                     }
857
858                     // If pattern is not exact then match fails
859
if (patternTypeArgHasAnyChars) return impossible;
860                         
861                     // Look for bound name in type argument superclasses
862
boundBinding = boundBinding.superclass();
863                     while (boundBinding != null) {
864                         if (CharOperation.equals(patternTypeArgument, boundBinding.shortReadableName(), this.isCaseSensitive) ||
865                             CharOperation.equals(patternTypeArgument, boundBinding.readableName(), this.isCaseSensitive)) {
866                             // found name in hierarchy => match
867
continue nextTypeArgument;
868                         } else if (boundBinding.isLocalType() || boundBinding.isMemberType()) {
869                             // for local or member type, verify also source name (bug 81084)
870
if (CharOperation.match(patternTypeArgument, boundBinding.sourceName(), this.isCaseSensitive))
871                                 continue nextTypeArgument;
872                         }
873                         boundBinding = boundBinding.superclass();
874                     }
875                     return impossible;
876                 }
877                 
878                 // See if names match
879
if (CharOperation.match(patternTypeArgument, argTypeBinding.shortReadableName(), this.isCaseSensitive) ||
880                     CharOperation.match(patternTypeArgument, argTypeBinding.readableName(), this.isCaseSensitive)) {
881                     continue nextTypeArgument;
882                 } else if (argTypeBinding.isLocalType() || argTypeBinding.isMemberType()) {
883                     // for local or member type, verify also source name (bug 81084)
884
if (CharOperation.match(patternTypeArgument, argTypeBinding.sourceName(), this.isCaseSensitive))
885                         continue nextTypeArgument;
886                 }
887
888                 // If pattern is not exact then match fails
889
if (patternTypeArgHasAnyChars) return impossible;
890
891                 // Scan hierarchy
892
TypeBinding leafTypeBinding = argTypeBinding.leafComponentType();
893                 if (leafTypeBinding.isBaseType()) return impossible;
894                 ReferenceBinding refBinding = ((ReferenceBinding) leafTypeBinding).superclass();
895                 while (refBinding != null) {
896                     if (CharOperation.equals(patternTypeArgument, refBinding.shortReadableName(), this.isCaseSensitive) ||
897                         CharOperation.equals(patternTypeArgument, refBinding.readableName(), this.isCaseSensitive)) {
898                         // found name in hierarchy => match
899
continue nextTypeArgument;
900                     } else if (refBinding.isLocalType() || refBinding.isMemberType()) {
901                         // for local or member type, verify also source name (bug 81084)
902
if (CharOperation.match(patternTypeArgument, refBinding.sourceName(), this.isCaseSensitive))
903                             continue nextTypeArgument;
904                     }
905                     refBinding = refBinding.superclass();
906                 }
907                 return impossible;
908             }
909         }
910         
911         // Recurse on enclosing type
912
TypeBinding enclosingType = paramTypeBinding.enclosingType();
913         if (enclosingType != null && enclosingType.isParameterizedType() && depth < patternTypeArguments.length && qualificationPattern != null) {
914             int lastDot = CharOperation.lastIndexOf('.', qualificationPattern);
915             char[] enclosingQualificationPattern = lastDot==-1 ? null : CharOperation.subarray(qualificationPattern, 0, lastDot);
916             char[] enclosingSimpleNamePattern = lastDot==-1 ? qualificationPattern : CharOperation.subarray(qualificationPattern, lastDot+1, qualificationPattern.length);
917             int enclosingLevel = resolveLevelForType(enclosingSimpleNamePattern, enclosingQualificationPattern, patternTypeArguments, depth+1, enclosingType);
918             if (enclosingLevel == impossible) return impossible;
919             if (enclosingLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
920         }
921         return level;
922     }
923 }
924 public String JavaDoc toString(){
925     return "SearchPattern"; //$NON-NLS-1$
926
}
927 }
928
Popular Tags