001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.core.search.matching;
011:
012: import org.eclipse.core.resources.IResource;
013: import org.eclipse.core.runtime.*;
014: import org.eclipse.jdt.core.*;
015: import org.eclipse.jdt.core.compiler.CharOperation;
016: import org.eclipse.jdt.core.search.*;
017: import org.eclipse.jdt.internal.compiler.ast.*;
018: import org.eclipse.jdt.internal.compiler.env.IBinaryType;
019: import org.eclipse.jdt.internal.compiler.lookup.*;
020: import org.eclipse.jdt.internal.compiler.util.SimpleSet;
021: import org.eclipse.jdt.internal.core.JavaElement;
022:
023: public class TypeReferenceLocator extends PatternLocator {
024:
025: protected TypeReferencePattern pattern;
026: protected boolean isDeclarationOfReferencedTypesPattern;
027:
028: public TypeReferenceLocator(TypeReferencePattern pattern) {
029:
030: super (pattern);
031:
032: this .pattern = pattern;
033: this .isDeclarationOfReferencedTypesPattern = this .pattern instanceof DeclarationOfReferencedTypesPattern;
034: }
035:
036: protected IJavaElement findElement(IJavaElement element,
037: int accuracy) {
038: // need exact match to be able to open on type ref
039: if (accuracy != SearchMatch.A_ACCURATE)
040: return null;
041:
042: // element that references the type must be included in the enclosing element
043: DeclarationOfReferencedTypesPattern declPattern = (DeclarationOfReferencedTypesPattern) this .pattern;
044: while (element != null
045: && !declPattern.enclosingElement.equals(element))
046: element = element.getParent();
047: return element;
048: }
049:
050: public int match(Annotation node, MatchingNodeSet nodeSet) {
051: return match(node.type, nodeSet);
052: }
053:
054: public int match(ASTNode node, MatchingNodeSet nodeSet) { // interested in ImportReference
055: if (!(node instanceof ImportReference))
056: return IMPOSSIBLE_MATCH;
057:
058: return nodeSet.addMatch(node,
059: matchLevel((ImportReference) node));
060: }
061:
062: //public int match(ConstructorDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
063: //public int match(Expression node, MatchingNodeSet nodeSet) - SKIP IT
064: //public int match(FieldDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
065: //public int match(MethodDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
066: //public int match(MessageSend node, MatchingNodeSet nodeSet) - SKIP IT
067: public int match(Reference node, MatchingNodeSet nodeSet) { // interested in NameReference & its subtypes
068: if (!(node instanceof NameReference))
069: return IMPOSSIBLE_MATCH;
070:
071: if (this .pattern.simpleName == null)
072: return nodeSet
073: .addMatch(
074: node,
075: ((InternalSearchPattern) this .pattern).mustResolve ? POSSIBLE_MATCH
076: : ACCURATE_MATCH);
077:
078: if (node instanceof SingleNameReference) {
079: if (matchesName(this .pattern.simpleName,
080: ((SingleNameReference) node).token))
081: return nodeSet.addMatch(node, POSSIBLE_MATCH); // resolution is needed to find out if it is a type ref
082: } else {
083: char[][] tokens = ((QualifiedNameReference) node).tokens;
084: for (int i = 0, max = tokens.length; i < max; i++)
085: if (matchesName(this .pattern.simpleName, tokens[i]))
086: return nodeSet.addMatch(node, POSSIBLE_MATCH); // resolution is needed to find out if it is a type ref
087: }
088:
089: return IMPOSSIBLE_MATCH;
090: }
091:
092: //public int match(TypeDeclaration node, MatchingNodeSet nodeSet) - SKIP IT
093: public int match(TypeReference node, MatchingNodeSet nodeSet) {
094: if (this .pattern.simpleName == null)
095: return nodeSet
096: .addMatch(
097: node,
098: ((InternalSearchPattern) this .pattern).mustResolve ? POSSIBLE_MATCH
099: : ACCURATE_MATCH);
100:
101: if (node instanceof SingleTypeReference) {
102: if (matchesName(this .pattern.simpleName,
103: ((SingleTypeReference) node).token))
104: return nodeSet
105: .addMatch(
106: node,
107: ((InternalSearchPattern) this .pattern).mustResolve ? POSSIBLE_MATCH
108: : ACCURATE_MATCH);
109: } else {
110: char[][] tokens = ((QualifiedTypeReference) node).tokens;
111: for (int i = 0, max = tokens.length; i < max; i++)
112: if (matchesName(this .pattern.simpleName, tokens[i]))
113: return nodeSet.addMatch(node, POSSIBLE_MATCH); // resolution is needed to find out if it is a type ref
114: }
115:
116: return IMPOSSIBLE_MATCH;
117: }
118:
119: protected int matchLevel(ImportReference importRef) {
120: if (this .pattern.qualification == null) {
121: if (this .pattern.simpleName == null)
122: return ACCURATE_MATCH;
123: char[][] tokens = importRef.tokens;
124: if (matchesName(this .pattern.simpleName,
125: tokens[tokens.length - 1]))
126: return ACCURATE_MATCH;
127: } else {
128: char[][] tokens = importRef.tokens;
129: char[] qualifiedPattern = this .pattern.simpleName == null ? this .pattern.qualification
130: : CharOperation.concat(this .pattern.qualification,
131: this .pattern.simpleName, '.');
132: char[] qualifiedTypeName = CharOperation.concatWith(tokens,
133: '.');
134: if (qualifiedPattern == null)
135: return ACCURATE_MATCH; // null is as if it was "*"
136: if (qualifiedTypeName == null)
137: return IMPOSSIBLE_MATCH; // cannot match null name
138: if (qualifiedTypeName.length == 0) { // empty name
139: if (qualifiedPattern.length == 0) { // can only matches empty pattern
140: return ACCURATE_MATCH;
141: }
142: return IMPOSSIBLE_MATCH;
143: }
144: boolean matchFirstChar = !this .isCaseSensitive
145: || (qualifiedPattern[0] == qualifiedTypeName[0]);
146: if (this .isCamelCase) {
147: if (matchFirstChar
148: && CharOperation
149: .camelCaseMatch(
150: qualifiedPattern,
151: qualifiedTypeName,
152: (this .matchMode & SearchPattern.R_PREFIX_MATCH) != 0)) {
153: return POSSIBLE_MATCH;
154: }
155: if (this .isCaseSensitive)
156: return IMPOSSIBLE_MATCH;
157: }
158: switch (this .matchMode) {
159: case SearchPattern.R_EXACT_MATCH:
160: case SearchPattern.R_PREFIX_MATCH:
161: if (CharOperation.prefixEquals(qualifiedPattern,
162: qualifiedTypeName, this .isCaseSensitive)) {
163: return POSSIBLE_MATCH;
164: }
165: break;
166:
167: case SearchPattern.R_PATTERN_MATCH:
168: if (CharOperation.match(qualifiedPattern,
169: qualifiedTypeName, this .isCaseSensitive)) {
170: return POSSIBLE_MATCH;
171: }
172: break;
173:
174: case SearchPattern.R_REGEXP_MATCH:
175: // TODO (frederic) implement regular expression match
176: break;
177: }
178: }
179: return IMPOSSIBLE_MATCH;
180: }
181:
182: /* (non-Javadoc)
183: * @see org.eclipse.jdt.internal.core.search.matching.PatternLocator#matchLevelAndReportImportRef(org.eclipse.jdt.internal.compiler.ast.ImportReference, org.eclipse.jdt.internal.compiler.lookup.Binding, org.eclipse.jdt.internal.core.search.matching.MatchLocator)
184: */
185: protected void matchLevelAndReportImportRef(
186: ImportReference importRef, Binding binding,
187: MatchLocator locator) throws CoreException {
188: Binding refBinding = binding;
189: if (importRef.isStatic()) {
190: // for static import, binding can be a field binding or a member type binding
191: // verify that in this case binding is static and use declaring class for fields
192: if (binding instanceof FieldBinding) {
193: FieldBinding fieldBinding = (FieldBinding) binding;
194: if (!fieldBinding.isStatic())
195: return;
196: refBinding = fieldBinding.declaringClass;
197: } else if (binding instanceof MethodBinding) {
198: MethodBinding methodBinding = (MethodBinding) binding;
199: if (!methodBinding.isStatic())
200: return;
201: refBinding = methodBinding.declaringClass;
202: } else if (binding instanceof MemberTypeBinding) {
203: MemberTypeBinding memberBinding = (MemberTypeBinding) binding;
204: if (!memberBinding.isStatic())
205: return;
206: }
207: // resolve and report
208: int level = resolveLevel(refBinding);
209: if (level >= INACCURATE_MATCH) {
210: matchReportImportRef(
211: importRef,
212: binding,
213: locator.createImportHandle(importRef),
214: level == ACCURATE_MATCH ? SearchMatch.A_ACCURATE
215: : SearchMatch.A_INACCURATE, locator);
216: }
217: return;
218: }
219: super .matchLevelAndReportImportRef(importRef, refBinding,
220: locator);
221: }
222:
223: protected void matchReportImportRef(ImportReference importRef,
224: Binding binding, IJavaElement element, int accuracy,
225: MatchLocator locator) throws CoreException {
226: if (this .isDeclarationOfReferencedTypesPattern) {
227: if ((element = findElement(element, accuracy)) != null) {
228: SimpleSet knownTypes = ((DeclarationOfReferencedTypesPattern) this .pattern).knownTypes;
229: while (binding instanceof ReferenceBinding) {
230: ReferenceBinding typeBinding = (ReferenceBinding) binding;
231: reportDeclaration(typeBinding, 1, locator,
232: knownTypes);
233: binding = typeBinding.enclosingType();
234: }
235: }
236: return;
237: }
238:
239: // return if this is not necessary to report
240: if (this .pattern.hasTypeArguments() && !this .isEquivalentMatch
241: && !this .isErasureMatch) {
242: return;
243: }
244:
245: // Create search match
246: match = locator.newTypeReferenceMatch(element, binding,
247: accuracy, importRef);
248:
249: // set match raw flag and rule
250: match.setRaw(true);
251: if (this .pattern.hasTypeArguments()) {
252: // binding is raw => only compatible erasure if pattern has type arguments
253: match.setRule(match.getRule()
254: & (~SearchPattern.R_FULL_MATCH));
255: }
256:
257: // Try to find best selection for match
258: ReferenceBinding typeBinding = null;
259: boolean lastButOne = false;
260: if (binding instanceof ReferenceBinding) {
261: typeBinding = (ReferenceBinding) binding;
262: } else if (binding instanceof FieldBinding) { // may happen for static import
263: typeBinding = ((FieldBinding) binding).declaringClass;
264: lastButOne = importRef.isStatic()
265: && ((importRef.bits & ASTNode.OnDemand) == 0);
266: } else if (binding instanceof MethodBinding) { // may happen for static import
267: typeBinding = ((MethodBinding) binding).declaringClass;
268: lastButOne = importRef.isStatic()
269: && ((importRef.bits & ASTNode.OnDemand) == 0);
270: }
271: if (typeBinding != null) {
272: int lastIndex = importRef.tokens.length - 1;
273: if (lastButOne) {
274: // for field or method static import, use last but one token
275: lastIndex--;
276: }
277: if (typeBinding instanceof ProblemReferenceBinding) {
278: ProblemReferenceBinding pbBinding = (ProblemReferenceBinding) typeBinding;
279: typeBinding = pbBinding.closestMatch();
280: lastIndex = pbBinding.compoundName.length - 1;
281: }
282: // try to match all enclosing types for which the token matches as well.
283: while (typeBinding != null && lastIndex >= 0) {
284: if (resolveLevelForType(typeBinding) != IMPOSSIBLE_MATCH) {
285: if (locator.encloses(element)) {
286: long[] positions = importRef.sourcePositions;
287: // index now depends on pattern type signature
288: int index = lastIndex;
289: if (this .pattern.qualification != null) {
290: index = lastIndex
291: - this .pattern.segmentsSize;
292: }
293: if (index < 0)
294: index = 0;
295: int start = (int) ((positions[index]) >>> 32);
296: int end = (int) positions[lastIndex];
297: // report match
298: match.setOffset(start);
299: match.setLength(end - start + 1);
300: locator.report(match);
301: }
302: return;
303: }
304: lastIndex--;
305: typeBinding = typeBinding.enclosingType();
306: }
307: }
308: locator.reportAccurateTypeReference(match, importRef,
309: this .pattern.simpleName);
310: }
311:
312: protected void matchReportReference(ArrayTypeReference arrayRef,
313: IJavaElement element, Binding elementBinding, int accuracy,
314: MatchLocator locator) throws CoreException {
315: if (this .pattern.simpleName == null) {
316: // TODO (frederic) need to add a test for this case while searching generic types...
317: if (locator.encloses(element)) {
318: int offset = arrayRef.sourceStart;
319: int length = arrayRef.sourceEnd - offset + 1;
320: if (this .match == null) {
321: this .match = locator.newTypeReferenceMatch(element,
322: elementBinding, accuracy, offset, length,
323: arrayRef);
324: } else {
325: this .match.setOffset(offset);
326: this .match.setLength(length);
327: }
328: locator.report(match);
329: return;
330: }
331: }
332: match = locator.newTypeReferenceMatch(element, elementBinding,
333: accuracy, arrayRef);
334: if (arrayRef.resolvedType != null) {
335: matchReportReference(arrayRef, -1, arrayRef.resolvedType
336: .leafComponentType(), locator);
337: return;
338: }
339: locator.reportAccurateTypeReference(match, arrayRef,
340: this .pattern.simpleName);
341: }
342:
343: /**
344: * Reports the match of the given reference.
345: */
346: protected void matchReportReference(ASTNode reference,
347: IJavaElement element, Binding elementBinding, int accuracy,
348: MatchLocator locator) throws CoreException {
349: matchReportReference(reference, element, null, null,
350: elementBinding, accuracy, locator);
351: }
352:
353: /**
354: * Reports the match of the given reference. Also provide a local and other elements to eventually report in match.
355: */
356: protected void matchReportReference(ASTNode reference,
357: IJavaElement element, IJavaElement localElement,
358: IJavaElement[] otherElements, Binding elementBinding,
359: int accuracy, MatchLocator locator) throws CoreException {
360: if (this .isDeclarationOfReferencedTypesPattern) {
361: if ((element = findElement(element, accuracy)) != null)
362: reportDeclaration(
363: reference,
364: element,
365: locator,
366: ((DeclarationOfReferencedTypesPattern) this .pattern).knownTypes);
367: return;
368: }
369:
370: // Create search match
371: TypeReferenceMatch refMatch = locator.newTypeReferenceMatch(
372: element, elementBinding, accuracy, reference);
373: refMatch.setLocalElement(localElement);
374: refMatch.setOtherElements(otherElements);
375: this .match = refMatch;
376:
377: // Report match depending on reference type
378: if (reference instanceof QualifiedNameReference)
379: matchReportReference((QualifiedNameReference) reference,
380: element, elementBinding, accuracy, locator);
381: else if (reference instanceof QualifiedTypeReference)
382: matchReportReference((QualifiedTypeReference) reference,
383: element, elementBinding, accuracy, locator);
384: else if (reference instanceof ArrayTypeReference)
385: matchReportReference((ArrayTypeReference) reference,
386: element, elementBinding, accuracy, locator);
387: else {
388: TypeBinding typeBinding = reference instanceof Expression ? ((Expression) reference).resolvedType
389: : null;
390: if (typeBinding != null) {
391: matchReportReference((Expression) reference, -1,
392: typeBinding, locator);
393: return;
394: }
395: locator.report(match);
396: }
397: }
398:
399: /**
400: * Reports the match of the given reference. Also provide a scope to look for possible local and other elements.
401: */
402: protected void matchReportReference(ASTNode reference,
403: IJavaElement element, Binding elementBinding, Scope scope,
404: int accuracy, MatchLocator locator) throws CoreException {
405: if (scope == null
406: || (scope.kind != Scope.BLOCK_SCOPE && scope.kind != Scope.METHOD_SCOPE)) {
407: matchReportReference(reference, element, elementBinding,
408: accuracy, locator);
409: return;
410: }
411:
412: // Look if some block scope local variable declarations include reference start position
413: BlockScope blockScope = (BlockScope) scope;
414: LocalDeclaration[] localDeclarations = blockScope
415: .findLocalVariableDeclarations(reference.sourceStart);
416: IJavaElement localElement = null;
417: IJavaElement[] otherElements = null;
418:
419: // Some local variable declaration are matching
420: if (localDeclarations != null) {
421: int length = localDeclarations.length;
422:
423: // Set local element to first matching local declaration
424: int idx = 0;
425: for (; idx < length; idx++) {
426: if (localDeclarations[idx] == null)
427: break;
428: if (reference.sourceStart == localDeclarations[idx].declarationSourceStart) {
429: localElement = locator.createHandle(
430: localDeclarations[idx], element);
431: break;
432: }
433: if (idx > 0
434: && localDeclarations[idx].sourceStart > reference.sourceStart) {
435: localElement = locator.createHandle(
436: localDeclarations[idx - 1], element);
437: break;
438: }
439: }
440: if (localElement == null && idx > 0) {
441: if (reference.sourceEnd < localDeclarations[idx - 1].declarationEnd) {
442: localElement = locator.createHandle(
443: localDeclarations[idx - 1], element);
444: }
445: }
446:
447: // Store other local variable declarations in other elements
448: int size = 0;
449: for (int j = 1; j < length; j++) {
450: if (localDeclarations[j] == null)
451: break;
452: if (reference.sourceStart == localDeclarations[j].declarationSourceStart) {
453: if (otherElements == null) {
454: otherElements = new IJavaElement[length - j];
455: }
456: otherElements[size++] = locator.createHandle(
457: localDeclarations[j], element);
458: }
459: }
460: if (size > 0 && size != (length - 1)) {
461: System
462: .arraycopy(otherElements, 0,
463: otherElements = new IJavaElement[size],
464: 0, size);
465: }
466: }
467:
468: // Report match with local and other elements if any
469: matchReportReference(reference, element, localElement,
470: otherElements, elementBinding, accuracy, locator);
471: }
472:
473: protected void matchReportReference(
474: QualifiedNameReference qNameRef, IJavaElement element,
475: Binding elementBinding, int accuracy, MatchLocator locator)
476: throws CoreException {
477: Binding binding = qNameRef.binding;
478: TypeBinding typeBinding = null;
479: int lastIndex = qNameRef.tokens.length - 1;
480: switch (qNameRef.bits & ASTNode.RestrictiveFlagMASK) {
481: case Binding.FIELD: // reading a field
482: typeBinding = qNameRef.actualReceiverType;
483: lastIndex -= qNameRef.otherBindings == null ? 1
484: : qNameRef.otherBindings.length + 1;
485: break;
486: case Binding.TYPE: //=============only type ==============
487: if (binding instanceof TypeBinding)
488: typeBinding = (TypeBinding) binding;
489: break;
490: case Binding.VARIABLE: //============unbound cases===========
491: case Binding.TYPE | Binding.VARIABLE:
492: if (binding instanceof ProblemReferenceBinding) {
493: typeBinding = (TypeBinding) binding;
494: } else if (binding instanceof ProblemFieldBinding) {
495: typeBinding = qNameRef.actualReceiverType;
496: lastIndex -= qNameRef.otherBindings == null ? 1
497: : qNameRef.otherBindings.length + 1;
498: } else if (binding instanceof ProblemBinding) {
499: typeBinding = ((ProblemBinding) binding).searchType;
500: }
501: break;
502: }
503: if (typeBinding instanceof ProblemReferenceBinding) {
504: ProblemReferenceBinding pbBinding = (ProblemReferenceBinding) typeBinding;
505: typeBinding = pbBinding.closestMatch();
506: lastIndex = pbBinding.compoundName.length - 1;
507: }
508:
509: // Create search match to report
510: if (this .match == null) {
511: this .match = locator.newTypeReferenceMatch(element,
512: elementBinding, accuracy, qNameRef);
513: }
514:
515: // try to match all enclosing types for which the token matches as well.
516: if (typeBinding instanceof ReferenceBinding) {
517: ReferenceBinding refBinding = (ReferenceBinding) typeBinding;
518: while (refBinding != null && lastIndex >= 0) {
519: if (resolveLevelForType(refBinding) == ACCURATE_MATCH) {
520: if (locator.encloses(element)) {
521: long[] positions = qNameRef.sourcePositions;
522: // index now depends on pattern type signature
523: int index = lastIndex;
524: if (this .pattern.qualification != null) {
525: index = lastIndex
526: - this .pattern.segmentsSize;
527: }
528: if (index < 0)
529: index = 0;
530: int start = (int) ((positions[index]) >>> 32);
531: int end = (int) positions[lastIndex];
532: match.setOffset(start);
533: match.setLength(end - start + 1);
534:
535: // Look if there's a need to special report for parameterized type
536: matchReportReference(qNameRef, lastIndex,
537: refBinding, locator);
538: }
539: return;
540: }
541: lastIndex--;
542: refBinding = refBinding.enclosingType();
543: }
544: }
545: locator.reportAccurateTypeReference(match, qNameRef,
546: this .pattern.simpleName);
547: }
548:
549: protected void matchReportReference(
550: QualifiedTypeReference qTypeRef, IJavaElement element,
551: Binding elementBinding, int accuracy, MatchLocator locator)
552: throws CoreException {
553: TypeBinding typeBinding = qTypeRef.resolvedType;
554: int lastIndex = qTypeRef.tokens.length - 1;
555: if (typeBinding instanceof ArrayBinding)
556: typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
557: if (typeBinding instanceof ProblemReferenceBinding) {
558: ProblemReferenceBinding pbBinding = (ProblemReferenceBinding) typeBinding;
559: typeBinding = pbBinding.closestMatch();
560: lastIndex = pbBinding.compoundName.length - 1;
561: }
562:
563: // Create search match to report
564: if (this .match == null) {
565: this .match = locator.newTypeReferenceMatch(element,
566: elementBinding, accuracy, qTypeRef);
567: }
568:
569: // try to match all enclosing types for which the token matches as well
570: if (typeBinding instanceof ReferenceBinding) {
571: ReferenceBinding refBinding = (ReferenceBinding) typeBinding;
572: while (refBinding != null && lastIndex >= 0) {
573: if (resolveLevelForType(refBinding) != IMPOSSIBLE_MATCH) {
574: if (locator.encloses(element)) {
575: long[] positions = qTypeRef.sourcePositions;
576: // index now depends on pattern type signature
577: int index = lastIndex;
578: if (this .pattern.qualification != null) {
579: index = lastIndex
580: - this .pattern.segmentsSize;
581: }
582: if (index < 0)
583: index = 0;
584: int start = (int) ((positions[index]) >>> 32);
585: int end = (int) positions[lastIndex];
586: match.setOffset(start);
587: match.setLength(end - start + 1);
588:
589: // Look if there's a need to special report for parameterized type
590: matchReportReference(qTypeRef, lastIndex,
591: refBinding, locator);
592: }
593: return;
594: }
595: lastIndex--;
596: refBinding = refBinding.enclosingType();
597: }
598: }
599: locator.reportAccurateTypeReference(match, qTypeRef,
600: this .pattern.simpleName);
601: }
602:
603: void matchReportReference(Expression expr, int lastIndex,
604: TypeBinding refBinding, MatchLocator locator)
605: throws CoreException {
606:
607: // Look if there's a need to special report for parameterized type
608: if (refBinding.isParameterizedType() || refBinding.isRawType()) {
609:
610: // Try to refine accuracy
611: ParameterizedTypeBinding parameterizedBinding = (ParameterizedTypeBinding) refBinding;
612: updateMatch(parameterizedBinding, this .pattern
613: .getTypeArguments(), this .pattern
614: .hasTypeParameters(), 0, locator);
615:
616: // See whether it is necessary to report or not
617: if (match.getRule() == 0)
618: return; // impossible match
619: boolean report = (this .isErasureMatch && match.isErasure())
620: || (this .isEquivalentMatch && match.isEquivalent())
621: || match.isExact();
622: if (!report)
623: return;
624:
625: // Make a special report for parameterized types if necessary
626: if (refBinding.isParameterizedType()
627: && this .pattern.hasTypeArguments()) {
628: TypeReference typeRef = null;
629: TypeReference[] typeArguments = null;
630: if (expr instanceof ParameterizedQualifiedTypeReference) {
631: typeRef = (ParameterizedQualifiedTypeReference) expr;
632: typeArguments = ((ParameterizedQualifiedTypeReference) expr).typeArguments[lastIndex];
633: } else if (expr instanceof ParameterizedSingleTypeReference) {
634: typeRef = (ParameterizedSingleTypeReference) expr;
635: typeArguments = ((ParameterizedSingleTypeReference) expr).typeArguments;
636: }
637: if (typeRef != null) {
638: locator.reportAccurateParameterizedTypeReference(
639: match, typeRef, lastIndex, typeArguments);
640: return;
641: }
642: }
643: } else if (this .pattern.hasTypeArguments()) { // binding has no type params, compatible erasure if pattern does
644: match.setRule(SearchPattern.R_ERASURE_MATCH);
645: }
646:
647: // Report match
648: if (expr instanceof ArrayTypeReference) {
649: locator.reportAccurateTypeReference(match, expr,
650: this .pattern.simpleName);
651: return;
652: }
653: if (refBinding.isLocalType()) {
654: // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=82673
655: LocalTypeBinding local = (LocalTypeBinding) refBinding;
656: IJavaElement focus = ((InternalSearchPattern) pattern).focus;
657: if (focus != null
658: && local.enclosingMethod != null
659: && focus.getParent().getElementType() == IJavaElement.METHOD) {
660: IMethod method = (IMethod) focus.getParent();
661: if (!CharOperation.equals(
662: local.enclosingMethod.selector, method
663: .getElementName().toCharArray())) {
664: return;
665: }
666: }
667: }
668: locator.report(match);
669: }
670:
671: protected int referenceType() {
672: return IJavaElement.TYPE;
673: }
674:
675: protected void reportDeclaration(ASTNode reference,
676: IJavaElement element, MatchLocator locator,
677: SimpleSet knownTypes) throws CoreException {
678: int maxType = -1;
679: TypeBinding typeBinding = null;
680: if (reference instanceof TypeReference) {
681: typeBinding = ((TypeReference) reference).resolvedType;
682: maxType = Integer.MAX_VALUE;
683: } else if (reference instanceof QualifiedNameReference) {
684: QualifiedNameReference qNameRef = (QualifiedNameReference) reference;
685: Binding binding = qNameRef.binding;
686: maxType = qNameRef.tokens.length - 1;
687: switch (qNameRef.bits & ASTNode.RestrictiveFlagMASK) {
688: case Binding.FIELD: // reading a field
689: typeBinding = qNameRef.actualReceiverType;
690: maxType -= qNameRef.otherBindings == null ? 1
691: : qNameRef.otherBindings.length + 1;
692: break;
693: case Binding.TYPE: //=============only type ==============
694: if (binding instanceof TypeBinding)
695: typeBinding = (TypeBinding) binding;
696: break;
697: case Binding.VARIABLE: //============unbound cases===========
698: case Binding.TYPE | Binding.VARIABLE:
699: if (binding instanceof ProblemFieldBinding) {
700: typeBinding = qNameRef.actualReceiverType;
701: maxType -= qNameRef.otherBindings == null ? 1
702: : qNameRef.otherBindings.length + 1;
703: } else if (binding instanceof ProblemBinding) {
704: ProblemBinding pbBinding = (ProblemBinding) binding;
705: typeBinding = pbBinding.searchType; // second chance with recorded type so far
706: char[] partialQualifiedName = pbBinding.name;
707: maxType = CharOperation.occurencesOf('.',
708: partialQualifiedName) - 1; // index of last bound token is one before the pb token
709: if (typeBinding == null || maxType < 0)
710: return;
711: }
712: break;
713: }
714: } else if (reference instanceof SingleNameReference) {
715: typeBinding = (TypeBinding) ((SingleNameReference) reference).binding;
716: maxType = 1;
717: }
718:
719: if (typeBinding instanceof ArrayBinding)
720: typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
721: if (typeBinding == null
722: || typeBinding instanceof BaseTypeBinding)
723: return;
724: if (typeBinding instanceof ProblemReferenceBinding) {
725: ReferenceBinding original = ((ProblemReferenceBinding) typeBinding)
726: .closestMatch();
727: if (original == null)
728: return; // original may not be set (bug 71279)
729: typeBinding = original;
730: }
731: typeBinding = typeBinding.erasure();
732: reportDeclaration((ReferenceBinding) typeBinding, maxType,
733: locator, knownTypes);
734: }
735:
736: protected void reportDeclaration(ReferenceBinding typeBinding,
737: int maxType, MatchLocator locator, SimpleSet knownTypes)
738: throws CoreException {
739: IType type = locator.lookupType(typeBinding);
740: if (type == null)
741: return; // case of a secondary type
742:
743: IResource resource = type.getResource();
744: boolean isBinary = type.isBinary();
745: IBinaryType info = null;
746: if (isBinary) {
747: if (resource == null)
748: resource = type.getJavaProject().getProject();
749: info = locator.getBinaryInfo(
750: (org.eclipse.jdt.internal.core.ClassFile) type
751: .getClassFile(), resource);
752: }
753: while (maxType >= 0 && type != null) {
754: if (!knownTypes.includes(type)) {
755: if (isBinary) {
756: locator.reportBinaryMemberDeclaration(resource,
757: type, typeBinding, info,
758: SearchMatch.A_ACCURATE);
759: } else {
760: if (typeBinding instanceof ParameterizedTypeBinding)
761: typeBinding = ((ParameterizedTypeBinding) typeBinding)
762: .genericType();
763: ClassScope scope = ((SourceTypeBinding) typeBinding).scope;
764: if (scope != null) {
765: TypeDeclaration typeDecl = scope.referenceContext;
766: int offset = typeDecl.sourceStart;
767: match = new TypeDeclarationMatch(
768: ((JavaElement) type)
769: .resolved(typeBinding),
770: SearchMatch.A_ACCURATE, offset,
771: typeDecl.sourceEnd - offset + 1,
772: locator.getParticipant(), resource);
773: locator.report(match);
774: }
775: }
776: knownTypes.add(type);
777: }
778: typeBinding = typeBinding.enclosingType();
779: IJavaElement parent = type.getParent();
780: if (parent instanceof IType) {
781: type = (IType) parent;
782: } else {
783: type = null;
784: }
785: maxType--;
786: }
787: }
788:
789: public int resolveLevel(ASTNode node) {
790: if (node instanceof TypeReference)
791: return resolveLevel((TypeReference) node);
792: if (node instanceof NameReference)
793: return resolveLevel((NameReference) node);
794: // if (node instanceof ImportReference) - Not called when resolve is true, see MatchingNodeSet.reportMatching(unit)
795: return IMPOSSIBLE_MATCH;
796: }
797:
798: public int resolveLevel(Binding binding) {
799: if (binding == null)
800: return INACCURATE_MATCH;
801: if (!(binding instanceof TypeBinding))
802: return IMPOSSIBLE_MATCH;
803:
804: TypeBinding typeBinding = (TypeBinding) binding;
805: if (typeBinding instanceof ArrayBinding)
806: typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
807: if (typeBinding instanceof ProblemReferenceBinding)
808: typeBinding = ((ProblemReferenceBinding) typeBinding)
809: .closestMatch();
810:
811: if (((InternalSearchPattern) this .pattern).focus instanceof IType
812: && typeBinding instanceof ReferenceBinding) {
813: IPackageFragment pkg = ((IType) ((InternalSearchPattern) this .pattern).focus)
814: .getPackageFragment();
815: // check that type is located inside this instance of a package fragment
816: if (!PackageReferenceLocator.isDeclaringPackageFragment(
817: pkg, (ReferenceBinding) typeBinding))
818: return IMPOSSIBLE_MATCH;
819: }
820:
821: return resolveLevelForTypeOrEnclosingTypes(
822: this .pattern.simpleName, this .pattern.qualification,
823: typeBinding);
824: }
825:
826: protected int resolveLevel(NameReference nameRef) {
827: Binding binding = nameRef.binding;
828:
829: if (nameRef instanceof SingleNameReference) {
830: if (binding instanceof ProblemReferenceBinding)
831: binding = ((ProblemReferenceBinding) binding)
832: .closestMatch();
833: if (binding instanceof ReferenceBinding)
834: return resolveLevelForType((ReferenceBinding) binding);
835: return binding == null || binding instanceof ProblemBinding ? INACCURATE_MATCH
836: : IMPOSSIBLE_MATCH;
837: }
838:
839: TypeBinding typeBinding = null;
840: QualifiedNameReference qNameRef = (QualifiedNameReference) nameRef;
841: switch (qNameRef.bits & ASTNode.RestrictiveFlagMASK) {
842: case Binding.FIELD: // reading a field
843: if (qNameRef.tokens.length < (qNameRef.otherBindings == null ? 2
844: : qNameRef.otherBindings.length + 2))
845: return IMPOSSIBLE_MATCH; // must be at least A.x
846: typeBinding = nameRef.actualReceiverType;
847: break;
848: case Binding.LOCAL: // reading a local variable
849: return IMPOSSIBLE_MATCH; // no type match in it
850: case Binding.TYPE: //=============only type ==============
851: if (binding instanceof TypeBinding)
852: typeBinding = (TypeBinding) binding;
853: break;
854: /*
855: * Handling of unbound qualified name references. The match may reside in the resolved fragment,
856: * which is recorded inside the problem binding, along with the portion of the name until it became a problem.
857: */
858: case Binding.VARIABLE: //============unbound cases===========
859: case Binding.TYPE | Binding.VARIABLE:
860: if (binding instanceof ProblemReferenceBinding) {
861: typeBinding = (TypeBinding) binding;
862: } else if (binding instanceof ProblemFieldBinding) {
863: if (qNameRef.tokens.length < (qNameRef.otherBindings == null ? 2
864: : qNameRef.otherBindings.length + 2))
865: return IMPOSSIBLE_MATCH; // must be at least A.x
866: typeBinding = nameRef.actualReceiverType;
867: } else if (binding instanceof ProblemBinding) {
868: ProblemBinding pbBinding = (ProblemBinding) binding;
869: if (CharOperation.occurencesOf('.', pbBinding.name) <= 0) // index of last bound token is one before the pb token
870: return INACCURATE_MATCH;
871: typeBinding = pbBinding.searchType;
872: }
873: break;
874: }
875: return resolveLevel(typeBinding);
876: }
877:
878: protected int resolveLevel(TypeReference typeRef) {
879: TypeBinding typeBinding = typeRef.resolvedType;
880: if (typeBinding instanceof ArrayBinding)
881: typeBinding = ((ArrayBinding) typeBinding).leafComponentType;
882: if (typeBinding instanceof ProblemReferenceBinding)
883: typeBinding = ((ProblemReferenceBinding) typeBinding)
884: .closestMatch();
885:
886: if (typeRef instanceof SingleTypeReference) {
887: return resolveLevelForType(typeBinding);
888: } else
889: return resolveLevelForTypeOrEnclosingTypes(
890: this .pattern.simpleName,
891: this .pattern.qualification, typeBinding);
892: }
893:
894: /* (non-Javadoc)
895: * Resolve level for type with a given binding.
896: * This is just an helper to avoid call of method with all parameters...
897: */
898: protected int resolveLevelForType(TypeBinding typeBinding) {
899: return resolveLevelForType(this .pattern.simpleName,
900: this .pattern.qualification, this .pattern
901: .getTypeArguments(), 0, typeBinding);
902: }
903:
904: /**
905: * Returns whether the given type binding or one of its enclosing types
906: * matches the given simple name pattern and qualification pattern.
907: * Returns ACCURATE_MATCH if it does.
908: * Returns INACCURATE_MATCH if resolve failed.
909: * Returns IMPOSSIBLE_MATCH if it doesn't.
910: */
911: protected int resolveLevelForTypeOrEnclosingTypes(
912: char[] simpleNamePattern, char[] qualificationPattern,
913: TypeBinding binding) {
914: if (binding == null)
915: return INACCURATE_MATCH;
916:
917: if (binding instanceof ReferenceBinding) {
918: ReferenceBinding type = (ReferenceBinding) binding;
919: while (type != null) {
920: int level = resolveLevelForType(type);
921: if (level != IMPOSSIBLE_MATCH)
922: return level;
923:
924: type = type.enclosingType();
925: }
926: }
927: return IMPOSSIBLE_MATCH;
928: }
929:
930: public String toString() {
931: return "Locator for " + this .pattern.toString(); //$NON-NLS-1$
932: }
933: }
|