0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.core.search.matching;
0011:
0012: import java.io.IOException;
0013: import java.util.ArrayList;
0014: import java.util.HashMap;
0015: import java.util.HashSet;
0016: import java.util.Iterator;
0017: import java.util.Map;
0018: import java.util.zip.ZipFile;
0019:
0020: import org.eclipse.core.resources.IResource;
0021: import org.eclipse.core.runtime.*;
0022: import org.eclipse.jdt.core.Flags;
0023: import org.eclipse.jdt.core.IClassFile;
0024: import org.eclipse.jdt.core.IJavaElement;
0025: import org.eclipse.jdt.core.IJavaModelStatusConstants;
0026: import org.eclipse.jdt.core.IJavaProject;
0027: import org.eclipse.jdt.core.IMember;
0028: import org.eclipse.jdt.core.IMethod;
0029: import org.eclipse.jdt.core.IPackageFragment;
0030: import org.eclipse.jdt.core.IPackageFragmentRoot;
0031: import org.eclipse.jdt.core.ISourceRange;
0032: import org.eclipse.jdt.core.IType;
0033: import org.eclipse.jdt.core.JavaModelException;
0034: import org.eclipse.jdt.core.Signature;
0035: import org.eclipse.jdt.core.compiler.*;
0036: import org.eclipse.jdt.core.search.*;
0037: import org.eclipse.jdt.internal.compiler.ASTVisitor;
0038: import org.eclipse.jdt.internal.compiler.CompilationResult;
0039: import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
0040: import org.eclipse.jdt.internal.compiler.ast.*;
0041: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
0042: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
0043: import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
0044: import org.eclipse.jdt.internal.compiler.env.*;
0045: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
0046: import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor;
0047: import org.eclipse.jdt.internal.compiler.lookup.*;
0048: import org.eclipse.jdt.internal.compiler.parser.*;
0049: import org.eclipse.jdt.internal.compiler.problem.*;
0050: import org.eclipse.jdt.internal.compiler.util.HashtableOfIntValues;
0051: import org.eclipse.jdt.internal.compiler.util.Messages;
0052: import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
0053: import org.eclipse.jdt.internal.compiler.util.SimpleSet;
0054: import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
0055: import org.eclipse.jdt.internal.core.hierarchy.HierarchyResolver;
0056: import org.eclipse.jdt.internal.core.BinaryMember;
0057: import org.eclipse.jdt.internal.core.BinaryType;
0058: import org.eclipse.jdt.internal.core.ClassFile;
0059: import org.eclipse.jdt.internal.core.CompilationUnit;
0060: import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
0061: import org.eclipse.jdt.internal.core.JavaElement;
0062: import org.eclipse.jdt.internal.core.JavaModelManager;
0063: import org.eclipse.jdt.internal.core.JavaProject;
0064: import org.eclipse.jdt.internal.core.LocalVariable;
0065: import org.eclipse.jdt.internal.core.NameLookup;
0066: import org.eclipse.jdt.internal.core.Openable;
0067: import org.eclipse.jdt.internal.core.PackageFragment;
0068: import org.eclipse.jdt.internal.core.PackageFragmentRoot;
0069: import org.eclipse.jdt.internal.core.SearchableEnvironment;
0070: import org.eclipse.jdt.internal.core.SourceMapper;
0071: import org.eclipse.jdt.internal.core.SourceMethod;
0072: import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
0073: import org.eclipse.jdt.internal.core.index.Index;
0074: import org.eclipse.jdt.internal.core.search.*;
0075: import org.eclipse.jdt.internal.core.util.HandleFactory;
0076: import org.eclipse.jdt.internal.core.util.Util;
0077:
0078: public class MatchLocator implements ITypeRequestor {
0079:
0080: public static final int MAX_AT_ONCE;
0081: static {
0082: long maxMemory = Runtime.getRuntime().maxMemory();
0083: int ratio = (int) Math.round(((double) maxMemory)
0084: / (64 * 0x100000));
0085: switch (ratio) {
0086: case 0:
0087: case 1:
0088: MAX_AT_ONCE = 100;
0089: break;
0090: case 2:
0091: MAX_AT_ONCE = 200;
0092: break;
0093: case 3:
0094: MAX_AT_ONCE = 300;
0095: break;
0096: default:
0097: MAX_AT_ONCE = 400;
0098: break;
0099: }
0100: }
0101:
0102: // permanent state
0103: public SearchPattern pattern;
0104: public PatternLocator patternLocator;
0105: public int matchContainer;
0106: public SearchRequestor requestor;
0107: public IJavaSearchScope scope;
0108: public IProgressMonitor progressMonitor;
0109:
0110: public org.eclipse.jdt.core.ICompilationUnit[] workingCopies;
0111: public HandleFactory handleFactory;
0112:
0113: // cache of all super type names if scope is hierarchy scope
0114: public char[][][] allSuperTypeNames;
0115:
0116: // the following is valid for the current project
0117: public MatchLocatorParser parser;
0118: private Parser basicParser;
0119: public INameEnvironment nameEnvironment;
0120: public NameLookup nameLookup;
0121: public LookupEnvironment lookupEnvironment;
0122: public HierarchyResolver hierarchyResolver;
0123:
0124: public CompilerOptions options;
0125:
0126: // management of PossibleMatch to be processed
0127: public int numberOfMatches; // (numberOfMatches - 1) is the last unit in matchesToProcess
0128: public PossibleMatch[] matchesToProcess;
0129: public PossibleMatch currentPossibleMatch;
0130:
0131: /*
0132: * Time spent in the IJavaSearchResultCollector
0133: */
0134: public long resultCollectorTime = 0;
0135:
0136: // Progress information
0137: int progressStep;
0138: int progressWorked;
0139:
0140: // Binding resolution and cache
0141: CompilationUnitScope unitScope;
0142: SimpleLookupTable bindings;
0143:
0144: // Cache for method handles
0145: HashSet methodHandles;
0146:
0147: /**
0148: * An ast visitor that visits local type declarations.
0149: */
0150: public class LocalDeclarationVisitor extends ASTVisitor {
0151: IJavaElement enclosingElement;
0152: Binding enclosingElementBinding;
0153: MatchingNodeSet nodeSet;
0154: HashtableOfIntValues occurrencesCounts = new HashtableOfIntValues(); // key = class name (char[]), value = occurrenceCount (int)
0155:
0156: public LocalDeclarationVisitor(IJavaElement enclosingElement,
0157: Binding enclosingElementBinding, MatchingNodeSet nodeSet) {
0158: this .enclosingElement = enclosingElement;
0159: this .enclosingElementBinding = enclosingElementBinding;
0160: this .nodeSet = nodeSet;
0161: }
0162:
0163: public boolean visit(TypeDeclaration typeDeclaration,
0164: BlockScope unused) {
0165: try {
0166: char[] simpleName;
0167: if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
0168: simpleName = CharOperation.NO_CHAR;
0169: } else {
0170: simpleName = typeDeclaration.name;
0171: }
0172: int occurrenceCount = occurrencesCounts.get(simpleName);
0173: if (occurrenceCount == HashtableOfIntValues.NO_VALUE) {
0174: occurrenceCount = 1;
0175: } else {
0176: occurrenceCount = occurrenceCount + 1;
0177: }
0178: occurrencesCounts.put(simpleName, occurrenceCount);
0179: if ((typeDeclaration.bits & ASTNode.IsAnonymousType) != 0) {
0180: reportMatching(typeDeclaration,
0181: this .enclosingElement, -1, nodeSet,
0182: occurrenceCount);
0183: } else {
0184: Integer level = (Integer) nodeSet.matchingNodes
0185: .removeKey(typeDeclaration);
0186: reportMatching(typeDeclaration,
0187: this .enclosingElement,
0188: level != null ? level.intValue() : -1,
0189: nodeSet, occurrenceCount);
0190: }
0191: return false; // don't visit members as this was done during reportMatching(...)
0192: } catch (CoreException e) {
0193: throw new WrappedCoreException(e);
0194: }
0195: }
0196: }
0197:
0198: public static class WorkingCopyDocument extends JavaSearchDocument {
0199: public org.eclipse.jdt.core.ICompilationUnit workingCopy;
0200:
0201: WorkingCopyDocument(
0202: org.eclipse.jdt.core.ICompilationUnit workingCopy,
0203: SearchParticipant participant) {
0204: super (workingCopy.getPath().toString(), participant);
0205: this .charContents = ((CompilationUnit) workingCopy)
0206: .getContents();
0207: this .workingCopy = workingCopy;
0208: }
0209:
0210: public String toString() {
0211: return "WorkingCopyDocument for " + getPath(); //$NON-NLS-1$
0212: }
0213: }
0214:
0215: public static class WrappedCoreException extends RuntimeException {
0216: private static final long serialVersionUID = 8354329870126121212L; // backward compatible
0217: public CoreException coreException;
0218:
0219: public WrappedCoreException(CoreException coreException) {
0220: this .coreException = coreException;
0221: }
0222: }
0223:
0224: public static SearchDocument[] addWorkingCopies(
0225: InternalSearchPattern pattern,
0226: SearchDocument[] indexMatches,
0227: org.eclipse.jdt.core.ICompilationUnit[] copies,
0228: SearchParticipant participant) {
0229: if (copies == null)
0230: return indexMatches;
0231: // working copies take precedence over corresponding compilation units
0232: HashMap workingCopyDocuments = workingCopiesThatCanSeeFocus(
0233: copies, pattern.focus, pattern.isPolymorphicSearch(),
0234: participant);
0235: if (workingCopyDocuments.size() == 0)
0236: return indexMatches;
0237: SearchDocument[] matches = null;
0238: int length = indexMatches.length;
0239: for (int i = 0; i < length; i++) {
0240: SearchDocument searchDocument = indexMatches[i];
0241: if (searchDocument.getParticipant() == participant) {
0242: SearchDocument workingCopyDocument = (SearchDocument) workingCopyDocuments
0243: .remove(searchDocument.getPath());
0244: if (workingCopyDocument != null) {
0245: if (matches == null) {
0246: System.arraycopy(indexMatches, 0,
0247: matches = new SearchDocument[length],
0248: 0, length);
0249: }
0250: matches[i] = workingCopyDocument;
0251: }
0252: }
0253: }
0254: if (matches == null) { // no working copy
0255: matches = indexMatches;
0256: }
0257: int remainingWorkingCopiesSize = workingCopyDocuments.size();
0258: if (remainingWorkingCopiesSize != 0) {
0259: System.arraycopy(matches, 0,
0260: matches = new SearchDocument[length
0261: + remainingWorkingCopiesSize], 0, length);
0262: Iterator iterator = workingCopyDocuments.values()
0263: .iterator();
0264: int index = length;
0265: while (iterator.hasNext()) {
0266: matches[index++] = (SearchDocument) iterator.next();
0267: }
0268: }
0269: return matches;
0270: }
0271:
0272: public static void setFocus(InternalSearchPattern pattern,
0273: IJavaElement focus) {
0274: pattern.focus = focus;
0275: }
0276:
0277: /*
0278: * Returns the working copies that can see the given focus.
0279: */
0280: private static HashMap workingCopiesThatCanSeeFocus(
0281: org.eclipse.jdt.core.ICompilationUnit[] copies,
0282: IJavaElement focus, boolean isPolymorphicSearch,
0283: SearchParticipant participant) {
0284: if (copies == null)
0285: return new HashMap();
0286: if (focus != null) {
0287: while (!(focus instanceof IJavaProject)
0288: && !(focus instanceof JarPackageFragmentRoot)) {
0289: focus = focus.getParent();
0290: }
0291: }
0292: HashMap result = new HashMap();
0293: for (int i = 0, length = copies.length; i < length; i++) {
0294: org.eclipse.jdt.core.ICompilationUnit workingCopy = copies[i];
0295: IPath projectOrJar = MatchLocator.getProjectOrJar(
0296: workingCopy).getPath();
0297: if (focus == null
0298: || IndexSelector.canSeeFocus(focus,
0299: isPolymorphicSearch, projectOrJar)) {
0300: result.put(workingCopy.getPath().toString(),
0301: new WorkingCopyDocument(workingCopy,
0302: participant));
0303: }
0304: }
0305: return result;
0306: }
0307:
0308: public static ClassFileReader classFileReader(IType type) {
0309: IClassFile classFile = type.getClassFile();
0310: JavaModelManager manager = JavaModelManager
0311: .getJavaModelManager();
0312: if (classFile.isOpen())
0313: return (ClassFileReader) manager.getInfo(type);
0314:
0315: PackageFragment pkg = (PackageFragment) type
0316: .getPackageFragment();
0317: IPackageFragmentRoot root = (IPackageFragmentRoot) pkg
0318: .getParent();
0319: try {
0320: if (!root.isArchive())
0321: return Util.newClassFileReader(type.getResource());
0322:
0323: ZipFile zipFile = null;
0324: try {
0325: IPath zipPath = root.getPath();
0326: if (JavaModelManager.ZIP_ACCESS_VERBOSE)
0327: System.out
0328: .println("(" + Thread.currentThread() + ") [MatchLocator.classFileReader()] Creating ZipFile on " + zipPath); //$NON-NLS-1$ //$NON-NLS-2$
0329: zipFile = manager.getZipFile(zipPath);
0330: String classFileName = classFile.getElementName();
0331: String path = Util.concatWith(pkg.names, classFileName,
0332: '/');
0333: return ClassFileReader.read(zipFile, path);
0334: } finally {
0335: manager.closeZipFile(zipFile);
0336: }
0337: } catch (ClassFormatException e) {
0338: // invalid class file: return null
0339: } catch (CoreException e) {
0340: // cannot read class file: return null
0341: } catch (IOException e) {
0342: // cannot read class file: return null
0343: }
0344: return null;
0345: }
0346:
0347: /**
0348: * Query a given index for matching entries. Assumes the sender has opened the index and will close when finished.
0349: */
0350: public static void findIndexMatches(InternalSearchPattern pattern,
0351: Index index, IndexQueryRequestor requestor,
0352: SearchParticipant participant, IJavaSearchScope scope,
0353: IProgressMonitor monitor) throws IOException {
0354: pattern.findIndexMatches(index, requestor, participant, scope,
0355: monitor);
0356: }
0357:
0358: public static IJavaElement getProjectOrJar(IJavaElement element) {
0359: while (!(element instanceof IJavaProject)
0360: && !(element instanceof JarPackageFragmentRoot)) {
0361: element = element.getParent();
0362: }
0363: return element;
0364: }
0365:
0366: public static IJavaElement projectOrJarFocus(
0367: InternalSearchPattern pattern) {
0368: return pattern == null || pattern.focus == null ? null
0369: : getProjectOrJar(pattern.focus);
0370: }
0371:
0372: public MatchLocator(SearchPattern pattern,
0373: SearchRequestor requestor, IJavaSearchScope scope,
0374: IProgressMonitor progressMonitor) {
0375:
0376: this .pattern = pattern;
0377: this .patternLocator = PatternLocator
0378: .patternLocator(this .pattern);
0379: this .matchContainer = this .patternLocator == null ? 0
0380: : this .patternLocator.matchContainer();
0381: this .requestor = requestor;
0382: this .scope = scope;
0383: this .progressMonitor = progressMonitor;
0384: }
0385:
0386: /**
0387: * Add an additional binary type
0388: */
0389: public void accept(IBinaryType binaryType,
0390: PackageBinding packageBinding,
0391: AccessRestriction accessRestriction) {
0392: this .lookupEnvironment.createBinaryTypeFrom(binaryType,
0393: packageBinding, accessRestriction);
0394: }
0395:
0396: /**
0397: * Add an additional compilation unit into the loop
0398: * -> build compilation unit declarations, their bindings and record their results.
0399: */
0400: public void accept(ICompilationUnit sourceUnit,
0401: AccessRestriction accessRestriction) {
0402: // Switch the current policy and compilation result for this unit to the requested one.
0403: CompilationResult unitResult = new CompilationResult(
0404: sourceUnit, 1, 1, this .options.maxProblemsPerUnit);
0405: try {
0406: CompilationUnitDeclaration parsedUnit = basicParser()
0407: .dietParse(sourceUnit, unitResult);
0408: this .lookupEnvironment.buildTypeBindings(parsedUnit,
0409: accessRestriction);
0410: this .lookupEnvironment.completeTypeBindings(parsedUnit,
0411: true);
0412: } catch (AbortCompilationUnit e) {
0413: // at this point, currentCompilationUnitResult may not be sourceUnit, but some other
0414: // one requested further along to resolve sourceUnit.
0415: if (unitResult.compilationUnit == sourceUnit) { // only report once
0416: //requestor.acceptResult(unitResult.tagAsAccepted());
0417: } else {
0418: throw e; // want to abort enclosing request to compile
0419: }
0420: }
0421: // Display unit error in debug mode
0422: if (BasicSearchEngine.VERBOSE) {
0423: if (unitResult.problemCount > 0) {
0424: System.out.println(unitResult);
0425: }
0426: }
0427: }
0428:
0429: /**
0430: * Add additional source types
0431: */
0432: public void accept(ISourceType[] sourceTypes,
0433: PackageBinding packageBinding,
0434: AccessRestriction accessRestriction) {
0435: // case of SearchableEnvironment of an IJavaProject is used
0436: ISourceType sourceType = sourceTypes[0];
0437: while (sourceType.getEnclosingType() != null)
0438: sourceType = sourceType.getEnclosingType();
0439: if (sourceType instanceof SourceTypeElementInfo) {
0440: // get source
0441: SourceTypeElementInfo elementInfo = (SourceTypeElementInfo) sourceType;
0442: IType type = elementInfo.getHandle();
0443: ICompilationUnit sourceUnit = (ICompilationUnit) type
0444: .getCompilationUnit();
0445: accept(sourceUnit, accessRestriction);
0446: } else {
0447: CompilationResult result = new CompilationResult(sourceType
0448: .getFileName(), 1, 1, 0);
0449: CompilationUnitDeclaration unit = SourceTypeConverter
0450: .buildCompilationUnit(
0451: sourceTypes,
0452: SourceTypeConverter.FIELD_AND_METHOD // need field and methods
0453: | SourceTypeConverter.MEMBER_TYPE, // need member types
0454: // no need for field initialization
0455: this .lookupEnvironment.problemReporter,
0456: result);
0457: this .lookupEnvironment.buildTypeBindings(unit,
0458: accessRestriction);
0459: this .lookupEnvironment.completeTypeBindings(unit, true);
0460: }
0461: }
0462:
0463: protected Parser basicParser() {
0464: if (this .basicParser == null) {
0465: ProblemReporter problemReporter = new ProblemReporter(
0466: DefaultErrorHandlingPolicies
0467: .proceedWithAllProblems(), this .options,
0468: new DefaultProblemFactory());
0469: this .basicParser = new Parser(problemReporter, false);
0470: this .basicParser.reportOnlyOneSyntaxError = true;
0471: }
0472: return this .basicParser;
0473: }
0474:
0475: /*
0476: * Caches the given binary type in the lookup environment and returns it.
0477: * Returns the existing one if already cached.
0478: * Returns null if source type binding was cached.
0479: */
0480: protected BinaryTypeBinding cacheBinaryType(IType type,
0481: IBinaryType binaryType) throws JavaModelException {
0482: IType enclosingType = type.getDeclaringType();
0483: if (enclosingType != null)
0484: cacheBinaryType(enclosingType, null); // cache enclosing types first, so that binary type can be found in lookup enviroment
0485: if (binaryType == null) {
0486: ClassFile classFile = (ClassFile) type.getClassFile();
0487: try {
0488: binaryType = getBinaryInfo(classFile, classFile
0489: .getResource());
0490: } catch (CoreException e) {
0491: if (e instanceof JavaModelException) {
0492: throw (JavaModelException) e;
0493: } else {
0494: throw new JavaModelException(e);
0495: }
0496: }
0497: }
0498: BinaryTypeBinding binding = this .lookupEnvironment
0499: .cacheBinaryType(binaryType, null /*no access restriction*/);
0500: if (binding == null) { // it was already cached as a result of a previous query
0501: char[][] compoundName = CharOperation.splitOn('.', type
0502: .getFullyQualifiedName().toCharArray());
0503: ReferenceBinding referenceBinding = this .lookupEnvironment
0504: .getCachedType(compoundName);
0505: if (referenceBinding != null
0506: && (referenceBinding instanceof BinaryTypeBinding))
0507: binding = (BinaryTypeBinding) referenceBinding; // if the binding could be found and if it comes from a binary type
0508: }
0509: return binding;
0510: }
0511:
0512: /*
0513: * Computes the super type names of the focus type if any.
0514: */
0515: protected char[][][] computeSuperTypeNames(IType focusType) {
0516: String fullyQualifiedName = focusType.getFullyQualifiedName();
0517: int lastDot = fullyQualifiedName.lastIndexOf('.');
0518: char[] qualification = lastDot == -1 ? CharOperation.NO_CHAR
0519: : fullyQualifiedName.substring(0, lastDot)
0520: .toCharArray();
0521: char[] simpleName = focusType.getElementName().toCharArray();
0522:
0523: SuperTypeNamesCollector super TypeNamesCollector = new SuperTypeNamesCollector(
0524: this .pattern, simpleName, qualification,
0525: new MatchLocator(this .pattern, this .requestor,
0526: this .scope, this .progressMonitor), // clone MatchLocator so that it has no side effect
0527: focusType, this .progressMonitor);
0528: try {
0529: this .allSuperTypeNames = super TypeNamesCollector.collect();
0530: } catch (JavaModelException e) {
0531: // problem collecting super type names: leave it null
0532: }
0533: return this .allSuperTypeNames;
0534: }
0535:
0536: /**
0537: * Creates an IMethod from the given method declaration and type.
0538: */
0539: protected IJavaElement createHandle(
0540: AbstractMethodDeclaration method, IJavaElement parent) {
0541: if (!(parent instanceof IType))
0542: return parent;
0543:
0544: IType type = (IType) parent;
0545: Argument[] arguments = method.arguments;
0546: int argCount = arguments == null ? 0 : arguments.length;
0547: if (type.isBinary()) {
0548: // don't cache the methods of the binary type
0549: // fall thru if its a constructor with a synthetic argument... find it the slower way
0550: ClassFileReader reader = classFileReader(type);
0551: if (reader != null) {
0552: IBinaryMethod[] methods = reader.getMethods();
0553: if (methods != null) {
0554: // build arguments names
0555: boolean firstIsSynthetic = false;
0556: if (reader.isMember() && method.isConstructor()
0557: && !Flags.isStatic(reader.getModifiers())) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=48261
0558: firstIsSynthetic = true;
0559: argCount++;
0560: }
0561: char[][] argumentTypeNames = new char[argCount][];
0562: for (int i = 0; i < argCount; i++) {
0563: char[] typeName = null;
0564: if (i == 0 && firstIsSynthetic) {
0565: typeName = type.getDeclaringType()
0566: .getFullyQualifiedName()
0567: .toCharArray();
0568: } else if (arguments != null) {
0569: TypeReference typeRef = arguments[firstIsSynthetic ? i - 1
0570: : i].type;
0571: typeName = CharOperation.concatWith(typeRef
0572: .getTypeName(), '.');
0573: for (int k = 0, dim = typeRef.dimensions(); k < dim; k++)
0574: typeName = CharOperation.concat(
0575: typeName,
0576: new char[] { '[', ']' });
0577: }
0578: if (typeName == null) {
0579: // invalid type name
0580: return null;
0581: }
0582: argumentTypeNames[i] = typeName;
0583: }
0584:
0585: // return binary method
0586: return createBinaryMethodHandle(type,
0587: method.selector, argumentTypeNames);
0588: }
0589: }
0590: return null;
0591: }
0592:
0593: String[] parameterTypeSignatures = new String[argCount];
0594: if (arguments != null) {
0595: for (int i = 0; i < argCount; i++) {
0596: TypeReference typeRef = arguments[i].type;
0597: char[] typeName = CharOperation.concatWith(typeRef
0598: .getParameterizedTypeName(), '.');
0599: parameterTypeSignatures[i] = Signature
0600: .createTypeSignature(typeName, false);
0601: }
0602: }
0603:
0604: return createMethodHandle(type, new String(method.selector),
0605: parameterTypeSignatures);
0606: }
0607:
0608: /*
0609: * Create binary method handle
0610: */
0611: IMethod createBinaryMethodHandle(IType type, char[] methodSelector,
0612: char[][] argumentTypeNames) {
0613: ClassFileReader reader = MatchLocator.classFileReader(type);
0614: if (reader != null) {
0615: IBinaryMethod[] methods = reader.getMethods();
0616: if (methods != null) {
0617: int argCount = argumentTypeNames == null ? 0
0618: : argumentTypeNames.length;
0619: nextMethod: for (int i = 0, methodsLength = methods.length; i < methodsLength; i++) {
0620: IBinaryMethod binaryMethod = methods[i];
0621: char[] selector = binaryMethod.isConstructor() ? type
0622: .getElementName().toCharArray()
0623: : binaryMethod.getSelector();
0624: if (CharOperation.equals(selector, methodSelector)) {
0625: char[] signature = binaryMethod
0626: .getGenericSignature();
0627: if (signature == null)
0628: signature = binaryMethod
0629: .getMethodDescriptor();
0630: char[][] parameterTypes = Signature
0631: .getParameterTypes(signature);
0632: if (argCount != parameterTypes.length)
0633: continue nextMethod;
0634: if (argumentTypeNames != null) {
0635: for (int j = 0; j < argCount; j++) {
0636: char[] parameterTypeName = ClassFileMatchLocator
0637: .convertClassFileFormat(parameterTypes[j]);
0638: if (!CharOperation
0639: .endsWith(
0640: Signature
0641: .toCharArray(Signature
0642: .getTypeErasure(parameterTypeName)),
0643: CharOperation
0644: .replaceOnCopy(
0645: argumentTypeNames[j],
0646: '$',
0647: '.')))
0648: continue nextMethod;
0649: parameterTypes[j] = parameterTypeName;
0650: }
0651: }
0652: return (IMethod) createMethodHandle(type,
0653: new String(selector), CharOperation
0654: .toStrings(parameterTypes));
0655: }
0656: }
0657: }
0658: }
0659: return null;
0660: }
0661:
0662: /*
0663: * Create method handle.
0664: * Store occurences for create handle to retrieve possible duplicate ones.
0665: */
0666: private IJavaElement createMethodHandle(IType type,
0667: String methodName, String[] parameterTypeSignatures) {
0668: IMethod methodHandle = type.getMethod(methodName,
0669: parameterTypeSignatures);
0670: if (methodHandle instanceof SourceMethod) {
0671: while (this .methodHandles.contains(methodHandle)) {
0672: ((SourceMethod) methodHandle).occurrenceCount++;
0673: }
0674: }
0675: this .methodHandles.add(methodHandle);
0676: return methodHandle;
0677: }
0678:
0679: /**
0680: * Creates an IField from the given field declaration and type.
0681: */
0682: protected IJavaElement createHandle(
0683: FieldDeclaration fieldDeclaration,
0684: TypeDeclaration typeDeclaration, IJavaElement parent) {
0685: if (!(parent instanceof IType))
0686: return parent;
0687: IType type = (IType) parent;
0688:
0689: switch (fieldDeclaration.getKind()) {
0690: case AbstractVariableDeclaration.FIELD:
0691: case AbstractVariableDeclaration.ENUM_CONSTANT:
0692: return ((IType) parent).getField(new String(
0693: fieldDeclaration.name));
0694: }
0695: if (type.isBinary()) {
0696: // do not return initializer for binary types
0697: // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=98378
0698: return type;
0699: }
0700: // find occurence count of the given initializer in its type declaration
0701: int occurrenceCount = 0;
0702: FieldDeclaration[] fields = typeDeclaration.fields;
0703: for (int i = 0, length = fields.length; i < length; i++) {
0704: if (fields[i].getKind() == AbstractVariableDeclaration.INITIALIZER) {
0705: occurrenceCount++;
0706: if (fields[i].equals(fieldDeclaration))
0707: break;
0708: }
0709: }
0710: return ((IType) parent).getInitializer(occurrenceCount);
0711: }
0712:
0713: /**
0714: * Create an handle for a local variable declartion (may be a local variable or type parameter).
0715: */
0716: protected IJavaElement createHandle(
0717: AbstractVariableDeclaration variableDeclaration,
0718: IJavaElement parent) {
0719: switch (variableDeclaration.getKind()) {
0720: case AbstractVariableDeclaration.LOCAL_VARIABLE:
0721: return new LocalVariable((JavaElement) parent, new String(
0722: variableDeclaration.name),
0723: variableDeclaration.declarationSourceStart,
0724: variableDeclaration.declarationSourceEnd,
0725: variableDeclaration.sourceStart,
0726: variableDeclaration.sourceEnd, new String(
0727: variableDeclaration.type.resolvedType
0728: .signature()));
0729: case AbstractVariableDeclaration.PARAMETER:
0730: return new LocalVariable((JavaElement) parent, new String(
0731: variableDeclaration.name),
0732: variableDeclaration.declarationSourceStart,
0733: variableDeclaration.declarationSourceEnd,
0734: variableDeclaration.sourceStart,
0735: variableDeclaration.sourceEnd, new String(
0736: variableDeclaration.type.resolvedType
0737: .signature()));
0738: case AbstractVariableDeclaration.TYPE_PARAMETER:
0739: return new org.eclipse.jdt.internal.core.TypeParameter(
0740: (JavaElement) parent, new String(
0741: variableDeclaration.name));
0742: }
0743: return null;
0744: }
0745:
0746: /*
0747: * Creates hierarchy resolver if needed.
0748: * Returns whether focus is visible.
0749: */
0750: protected boolean createHierarchyResolver(IType focusType,
0751: PossibleMatch[] possibleMatches) {
0752: // cache focus type if not a possible match
0753: char[][] compoundName = CharOperation.splitOn('.', focusType
0754: .getFullyQualifiedName().toCharArray());
0755: boolean isPossibleMatch = false;
0756: for (int i = 0, length = possibleMatches.length; i < length; i++) {
0757: if (CharOperation.equals(possibleMatches[i].compoundName,
0758: compoundName)) {
0759: isPossibleMatch = true;
0760: break;
0761: }
0762: }
0763: if (!isPossibleMatch) {
0764: if (focusType.isBinary()) {
0765: try {
0766: cacheBinaryType(focusType, null);
0767: } catch (JavaModelException e) {
0768: return false;
0769: }
0770: } else {
0771: // cache all types in the focus' compilation unit (even secondary types)
0772: accept((ICompilationUnit) focusType
0773: .getCompilationUnit(), null /*TODO no access restriction*/);
0774: }
0775: }
0776:
0777: // resolve focus type
0778: this .hierarchyResolver = new HierarchyResolver(
0779: this .lookupEnvironment, null/*hierarchy is not going to be computed*/);
0780: ReferenceBinding binding = this .hierarchyResolver
0781: .setFocusType(compoundName);
0782: return binding != null
0783: && binding.isValidBinding()
0784: && (binding.tagBits & TagBits.HierarchyHasProblems) == 0;
0785: }
0786:
0787: /**
0788: * Creates an IImportDeclaration from the given import statement
0789: */
0790: protected IJavaElement createImportHandle(ImportReference importRef) {
0791: char[] importName = CharOperation.concatWith(importRef
0792: .getImportName(), '.');
0793: if ((importRef.bits & ASTNode.OnDemand) != 0)
0794: importName = CharOperation.concat(importName,
0795: ".*".toCharArray()); //$NON-NLS-1$
0796: Openable openable = this .currentPossibleMatch.openable;
0797: if (openable instanceof CompilationUnit)
0798: return ((CompilationUnit) openable).getImport(new String(
0799: importName));
0800:
0801: // binary types do not contain import statements so just answer the top-level type as the element
0802: IType binaryType = ((ClassFile) openable).getType();
0803: String typeName = binaryType.getElementName();
0804: int lastDollar = typeName.lastIndexOf('$');
0805: if (lastDollar == -1)
0806: return binaryType;
0807: return createTypeHandle(typeName.substring(0, lastDollar));
0808: }
0809:
0810: /**
0811: * Creates an IImportDeclaration from the given import statement
0812: */
0813: protected IJavaElement createPackageDeclarationHandle(
0814: CompilationUnitDeclaration unit) {
0815: if (unit.isPackageInfo()) {
0816: char[] packName = CharOperation.concatWith(
0817: unit.currentPackage.getImportName(), '.');
0818: Openable openable = this .currentPossibleMatch.openable;
0819: if (openable instanceof CompilationUnit) {
0820: return ((CompilationUnit) openable)
0821: .getPackageDeclaration(new String(packName));
0822: }
0823: }
0824: return createTypeHandle(new String(unit.getMainTypeName()));
0825: }
0826:
0827: /**
0828: * Creates an IType from the given simple top level type name.
0829: */
0830: protected IType createTypeHandle(String simpleTypeName) {
0831: Openable openable = this .currentPossibleMatch.openable;
0832: if (openable instanceof CompilationUnit)
0833: return ((CompilationUnit) openable).getType(simpleTypeName);
0834:
0835: IType binaryType = ((ClassFile) openable).getType();
0836: String binaryTypeQualifiedName = binaryType
0837: .getTypeQualifiedName();
0838: if (simpleTypeName.equals(binaryTypeQualifiedName))
0839: return binaryType; // answer only top-level types, sometimes the classFile is for a member/local type
0840:
0841: // type name may be null for anonymous (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=164791)
0842: String classFileName = simpleTypeName.length() == 0 ? binaryTypeQualifiedName
0843: : simpleTypeName;
0844: IClassFile classFile = binaryType.getPackageFragment()
0845: .getClassFile(
0846: classFileName
0847: + SuffixConstants.SUFFIX_STRING_class);
0848: return classFile.getType();
0849: }
0850:
0851: protected boolean encloses(IJavaElement element) {
0852: return element != null && this .scope.encloses(element);
0853: }
0854:
0855: /* (non-Javadoc)
0856: * Return info about last type argument of a parameterized type reference.
0857: * These info are made of concatenation of 2 int values which are respectively
0858: * depth and end position of the last type argument.
0859: * For example, this method will return 0x300000020 for type ref List<List<List<String>>>
0860: * if end position of type reference "String" equals 32.
0861: */
0862: private long findLastTypeArgumentInfo(TypeReference typeRef) {
0863: // Get last list of type arguments for parameterized qualified type reference
0864: TypeReference lastTypeArgument = typeRef;
0865: int depth = 0;
0866: while (true) {
0867: TypeReference[] lastTypeArguments = null;
0868: if (lastTypeArgument instanceof ParameterizedQualifiedTypeReference) {
0869: ParameterizedQualifiedTypeReference pqtRef = (ParameterizedQualifiedTypeReference) lastTypeArgument;
0870: for (int i = pqtRef.typeArguments.length - 1; i >= 0
0871: && lastTypeArguments == null; i--) {
0872: lastTypeArguments = pqtRef.typeArguments[i];
0873: }
0874: }
0875: // Get last type argument for single type reference of last list of argument of parameterized qualified type reference
0876: TypeReference last = null;
0877: if (lastTypeArgument instanceof ParameterizedSingleTypeReference
0878: || lastTypeArguments != null) {
0879: if (lastTypeArguments == null) {
0880: lastTypeArguments = ((ParameterizedSingleTypeReference) lastTypeArgument).typeArguments;
0881: }
0882: if (lastTypeArguments != null) {
0883: for (int i = lastTypeArguments.length - 1; i >= 0
0884: && last == null; i++) {
0885: last = lastTypeArguments[i];
0886: }
0887: }
0888: }
0889: if (last == null)
0890: break;
0891: depth++;
0892: lastTypeArgument = last;
0893: }
0894: // Current type reference is not parameterized. So, it is the last type argument
0895: return (((long) depth) << 32) + lastTypeArgument.sourceEnd;
0896: }
0897:
0898: protected IBinaryType getBinaryInfo(ClassFile classFile,
0899: IResource resource) throws CoreException {
0900: BinaryType binaryType = (BinaryType) classFile.getType();
0901: if (classFile.isOpen())
0902: return (IBinaryType) binaryType.getElementInfo(); // reuse the info from the java model cache
0903:
0904: // create a temporary info
0905: IBinaryType info;
0906: try {
0907: PackageFragment pkg = (PackageFragment) classFile
0908: .getParent();
0909: PackageFragmentRoot root = (PackageFragmentRoot) pkg
0910: .getParent();
0911: if (root.isArchive()) {
0912: // class file in a jar
0913: String classFileName = classFile.getElementName();
0914: String classFilePath = Util.concatWith(pkg.names,
0915: classFileName, '/');
0916: ZipFile zipFile = null;
0917: try {
0918: zipFile = ((JarPackageFragmentRoot) root).getJar();
0919: info = ClassFileReader.read(zipFile, classFilePath);
0920: } finally {
0921: JavaModelManager.getJavaModelManager()
0922: .closeZipFile(zipFile);
0923: }
0924: } else {
0925: // class file in a directory
0926: info = Util.newClassFileReader(resource);
0927: }
0928: if (info == null)
0929: throw binaryType.newNotPresentException();
0930: return info;
0931: } catch (ClassFormatException e) {
0932: //e.printStackTrace();
0933: return null;
0934: } catch (java.io.IOException e) {
0935: throw new JavaModelException(e,
0936: IJavaModelStatusConstants.IO_EXCEPTION);
0937: }
0938: }
0939:
0940: protected IType getFocusType() {
0941: return this .scope instanceof HierarchyScope ? ((HierarchyScope) this .scope).focusType
0942: : null;
0943: }
0944:
0945: protected void getMethodBodies(CompilationUnitDeclaration unit,
0946: MatchingNodeSet nodeSet) {
0947: if (unit.ignoreMethodBodies) {
0948: unit.ignoreFurtherInvestigation = true;
0949: return; // if initial diet parse did not work, no need to dig into method bodies.
0950: }
0951:
0952: // save existing values to restore them at the end of the parsing process
0953: // see bug 47079 for more details
0954: int[] oldLineEnds = this .parser.scanner.lineEnds;
0955: int oldLinePtr = this .parser.scanner.linePtr;
0956:
0957: try {
0958: CompilationResult compilationResult = unit.compilationResult;
0959: this .parser.scanner.setSource(compilationResult);
0960:
0961: if (this .parser.javadocParser.checkDocComment) {
0962: char[] contents = compilationResult.compilationUnit
0963: .getContents();
0964: this .parser.javadocParser.scanner.setSource(contents);
0965: }
0966: this .parser.nodeSet = nodeSet;
0967: this .parser.parseBodies(unit);
0968: } finally {
0969: this .parser.nodeSet = null;
0970: // this is done to prevent any side effects on the compilation unit result
0971: // line separator positions array.
0972: this .parser.scanner.lineEnds = oldLineEnds;
0973: this .parser.scanner.linePtr = oldLinePtr;
0974: }
0975: }
0976:
0977: protected TypeBinding getType(Object typeKey, char[] typeName) {
0978: if (this .unitScope == null || typeName == null
0979: || typeName.length == 0)
0980: return null;
0981: // Try to get binding from cache
0982: Binding binding = (Binding) this .bindings.get(typeKey);
0983: if (binding != null) {
0984: if (binding instanceof TypeBinding
0985: && binding.isValidBinding())
0986: return (TypeBinding) binding;
0987: return null;
0988: }
0989: // Get binding from unit scope
0990: char[][] compoundName = CharOperation.splitOn('.', typeName);
0991: TypeBinding typeBinding = this .unitScope.getType(compoundName,
0992: compoundName.length);
0993: this .bindings.put(typeKey, typeBinding);
0994: return typeBinding.isValidBinding() ? typeBinding : null;
0995: }
0996:
0997: public MethodBinding getMethodBinding(MethodPattern methodPattern) {
0998: if (this .unitScope == null)
0999: return null;
1000: // Try to get binding from cache
1001: Binding binding = (Binding) this .bindings.get(methodPattern);
1002: if (binding != null) {
1003: if (binding instanceof MethodBinding
1004: && binding.isValidBinding())
1005: return (MethodBinding) binding;
1006: return null;
1007: }
1008: // Get binding from unit scope
1009: char[] typeName = PatternLocator.qualifiedPattern(
1010: methodPattern.declaringSimpleName,
1011: methodPattern.declaringQualification);
1012: if (typeName == null) {
1013: if (methodPattern.declaringType == null)
1014: return null;
1015: typeName = methodPattern.declaringType
1016: .getFullyQualifiedName().toCharArray();
1017: }
1018: TypeBinding declaringTypeBinding = getType(typeName, typeName);
1019: if (declaringTypeBinding != null) {
1020: if (declaringTypeBinding.isArrayType()) {
1021: declaringTypeBinding = declaringTypeBinding
1022: .leafComponentType();
1023: }
1024: if (!declaringTypeBinding.isBaseType()) {
1025: char[][] parameterTypes = methodPattern.parameterSimpleNames;
1026: if (parameterTypes == null)
1027: return null;
1028: int paramTypeslength = parameterTypes.length;
1029: ReferenceBinding referenceBinding = (ReferenceBinding) declaringTypeBinding;
1030: MethodBinding[] methods = referenceBinding
1031: .getMethods(methodPattern.selector);
1032: int methodsLength = methods.length;
1033: TypeVariableBinding[] refTypeVariables = referenceBinding
1034: .typeVariables();
1035: int typeVarLength = refTypeVariables == null ? 0
1036: : refTypeVariables.length;
1037: for (int i = 0; i < methodsLength; i++) {
1038: TypeBinding[] methodParameters = methods[i].parameters;
1039: int paramLength = methodParameters == null ? 0
1040: : methodParameters.length;
1041: TypeVariableBinding[] methodTypeVariables = methods[i].typeVariables;
1042: int methTypeVarLength = methodTypeVariables == null ? 0
1043: : methodTypeVariables.length;
1044: boolean found = false;
1045: if (methodParameters != null
1046: && paramLength == paramTypeslength) {
1047: for (int p = 0; p < paramLength; p++) {
1048: if (CharOperation.equals(
1049: methodParameters[p].sourceName(),
1050: parameterTypes[p])) {
1051: // param erasure match
1052: found = true;
1053: } else {
1054: // type variable
1055: found = false;
1056: if (refTypeVariables != null) {
1057: for (int v = 0; v < typeVarLength; v++) {
1058: if (!CharOperation
1059: .equals(
1060: refTypeVariables[v].sourceName,
1061: parameterTypes[p])) {
1062: found = false;
1063: break;
1064: }
1065: found = true;
1066: }
1067: }
1068: if (!found
1069: && methodTypeVariables != null) {
1070: for (int v = 0; v < methTypeVarLength; v++) {
1071: if (!CharOperation
1072: .equals(
1073: methodTypeVariables[v].sourceName,
1074: parameterTypes[p])) {
1075: found = false;
1076: break;
1077: }
1078: found = true;
1079: }
1080: }
1081: if (!found)
1082: break;
1083: }
1084: }
1085: }
1086: if (found) {
1087: this .bindings.put(methodPattern, methods[i]);
1088: return methods[i];
1089: }
1090: }
1091: }
1092: }
1093: this .bindings.put(methodPattern, new ProblemMethodBinding(
1094: methodPattern.selector, null, ProblemReasons.NotFound));
1095: return null;
1096: }
1097:
1098: protected boolean hasAlreadyDefinedType(
1099: CompilationUnitDeclaration parsedUnit) {
1100: CompilationResult result = parsedUnit.compilationResult;
1101: if (result == null)
1102: return false;
1103: for (int i = 0; i < result.problemCount; i++)
1104: if (result.problems[i].getID() == IProblem.DuplicateTypes)
1105: return true;
1106: return false;
1107: }
1108:
1109: /**
1110: * Create a new parser for the given project, as well as a lookup environment.
1111: */
1112: public void initialize(JavaProject project, int possibleMatchSize)
1113: throws JavaModelException {
1114: // clean up name environment only if there are several possible match as it is reused
1115: // when only one possible match (bug 58581)
1116: if (this .nameEnvironment != null && possibleMatchSize != 1)
1117: this .nameEnvironment.cleanup();
1118:
1119: SearchableEnvironment searchableEnvironment = project
1120: .newSearchableNameEnvironment(this .workingCopies);
1121:
1122: // if only one possible match, a file name environment costs too much,
1123: // so use the existing searchable environment which will populate the java model
1124: // only for this possible match and its required types.
1125: this .nameEnvironment = possibleMatchSize == 1 ? (INameEnvironment) searchableEnvironment
1126: : (INameEnvironment) new JavaSearchNameEnvironment(
1127: project, this .workingCopies);
1128:
1129: // create lookup environment
1130: Map map = project.getOptions(true);
1131: map.put(CompilerOptions.OPTION_TaskTags, ""); //$NON-NLS-1$
1132: this .options = new CompilerOptions(map);
1133: ProblemReporter problemReporter = new ProblemReporter(
1134: DefaultErrorHandlingPolicies.proceedWithAllProblems(),
1135: this .options, new DefaultProblemFactory());
1136: this .lookupEnvironment = new LookupEnvironment(this ,
1137: this .options, problemReporter, this .nameEnvironment);
1138:
1139: this .parser = MatchLocatorParser.createParser(problemReporter,
1140: this );
1141:
1142: // basic parser needs also to be reset as project options may have changed
1143: // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=163072
1144: this .basicParser = null;
1145:
1146: // remember project's name lookup
1147: this .nameLookup = searchableEnvironment.nameLookup;
1148:
1149: // initialize queue of units
1150: this .numberOfMatches = 0;
1151: this .matchesToProcess = new PossibleMatch[possibleMatchSize];
1152: }
1153:
1154: protected void locateMatches(JavaProject javaProject,
1155: PossibleMatch[] possibleMatches, int start, int length)
1156: throws CoreException {
1157: initialize(javaProject, length);
1158:
1159: // create and resolve binding (equivalent to beginCompilation() in Compiler)
1160: boolean mustResolvePattern = ((InternalSearchPattern) this .pattern).mustResolve;
1161: boolean mustResolve = mustResolvePattern;
1162: this .patternLocator.mayBeGeneric = this .options.sourceLevel >= ClassFileConstants.JDK1_5;
1163: boolean bindingsWereCreated = mustResolve;
1164: try {
1165: for (int i = start, maxUnits = start + length; i < maxUnits; i++) {
1166: PossibleMatch possibleMatch = possibleMatches[i];
1167: try {
1168: if (!parseAndBuildBindings(possibleMatch,
1169: mustResolvePattern))
1170: continue;
1171: // Currently we only need to resolve over pattern flag if there's potential parameterized types
1172: if (this .patternLocator.mayBeGeneric) {
1173: // If pattern does not resolve then rely on possible match node set resolution
1174: // which may have been modified while locator was adding possible matches to it
1175: if (!mustResolvePattern && !mustResolve) {
1176: mustResolve = possibleMatch.nodeSet.mustResolve;
1177: bindingsWereCreated = mustResolve;
1178: }
1179: } else {
1180: // Reset matching node resolution with pattern one if there's no potential parameterized type
1181: // to minimize side effect on previous search behavior
1182: possibleMatch.nodeSet.mustResolve = mustResolvePattern;
1183: }
1184: // possible match node resolution has been merged with pattern one, so rely on it to know
1185: // whether we need to process compilation unit now or later
1186: if (!possibleMatch.nodeSet.mustResolve) {
1187: if (this .progressMonitor != null) {
1188: this .progressWorked++;
1189: if ((this .progressWorked % this .progressStep) == 0)
1190: this .progressMonitor
1191: .worked(this .progressStep);
1192: }
1193: process(possibleMatch, bindingsWereCreated);
1194: if (this .numberOfMatches > 0
1195: && this .matchesToProcess[this .numberOfMatches - 1] == possibleMatch) {
1196: // forget last possible match as it was processed
1197: this .numberOfMatches--;
1198: }
1199: }
1200: } finally {
1201: if (!possibleMatch.nodeSet.mustResolve)
1202: possibleMatch.cleanUp();
1203: }
1204: }
1205: if (mustResolve)
1206: this .lookupEnvironment.completeTypeBindings();
1207:
1208: // create hierarchy resolver if needed
1209: IType focusType = getFocusType();
1210: if (focusType == null) {
1211: this .hierarchyResolver = null;
1212: } else if (!createHierarchyResolver(focusType,
1213: possibleMatches)) {
1214: // focus type is not visible, use the super type names instead of the bindings
1215: if (computeSuperTypeNames(focusType) == null)
1216: return;
1217: }
1218: } catch (AbortCompilation e) {
1219: bindingsWereCreated = false;
1220: }
1221:
1222: if (!mustResolve) {
1223: return;
1224: }
1225:
1226: // possible match resolution
1227: for (int i = 0; i < this .numberOfMatches; i++) {
1228: if (this .progressMonitor != null
1229: && this .progressMonitor.isCanceled())
1230: throw new OperationCanceledException();
1231: PossibleMatch possibleMatch = this .matchesToProcess[i];
1232: this .matchesToProcess[i] = null; // release reference to processed possible match
1233: try {
1234: process(possibleMatch, bindingsWereCreated);
1235: } catch (AbortCompilation e) {
1236: // problem with class path: it could not find base classes
1237: // continue and try next matching openable reporting innacurate matches (since bindings will be null)
1238: bindingsWereCreated = false;
1239: } catch (JavaModelException e) {
1240: // problem with class path: it could not find base classes
1241: // continue and try next matching openable reporting innacurate matches (since bindings will be null)
1242: bindingsWereCreated = false;
1243: } finally {
1244: if (this .progressMonitor != null) {
1245: this .progressWorked++;
1246: if ((this .progressWorked % this .progressStep) == 0)
1247: this .progressMonitor.worked(this .progressStep);
1248: }
1249: if (this .options.verbose)
1250: System.out
1251: .println(Messages
1252: .bind(
1253: Messages.compilation_done,
1254: new String[] {
1255: String
1256: .valueOf(i + 1),
1257: String
1258: .valueOf(this .numberOfMatches),
1259: new String(
1260: possibleMatch.parsedUnit
1261: .getFileName()) }));
1262: // cleanup compilation unit result
1263: possibleMatch.cleanUp();
1264: }
1265: }
1266: }
1267:
1268: /**
1269: * Locate the matches amongst the possible matches.
1270: */
1271: protected void locateMatches(JavaProject javaProject,
1272: PossibleMatchSet matchSet, int expected)
1273: throws CoreException {
1274: PossibleMatch[] possibleMatches = matchSet
1275: .getPossibleMatches(javaProject
1276: .getPackageFragmentRoots());
1277: int length = possibleMatches.length;
1278: // increase progress from duplicate matches not stored in matchSet while adding...
1279: if (this .progressMonitor != null && expected > length) {
1280: this .progressWorked += expected - length;
1281: this .progressMonitor.worked(expected - length);
1282: }
1283: // locate matches (processed matches are limited to avoid problem while using VM default memory heap size)
1284: for (int index = 0; index < length;) {
1285: int max = Math.min(MAX_AT_ONCE, length - index);
1286: locateMatches(javaProject, possibleMatches, index, max);
1287: index += max;
1288: }
1289: this .patternLocator.clear();
1290: }
1291:
1292: /**
1293: * Locate the matches in the given files and report them using the search requestor.
1294: */
1295: public void locateMatches(SearchDocument[] searchDocuments)
1296: throws CoreException {
1297: if (this .patternLocator == null)
1298: return;
1299: int docsLength = searchDocuments.length;
1300: if (BasicSearchEngine.VERBOSE) {
1301: System.out.println("Locating matches in documents ["); //$NON-NLS-1$
1302: for (int i = 0; i < docsLength; i++)
1303: System.out.println("\t" + searchDocuments[i]); //$NON-NLS-1$
1304: System.out.println("]"); //$NON-NLS-1$
1305: }
1306:
1307: // init infos for progress increasing
1308: int n = docsLength < 1000 ? Math.min(Math.max(
1309: docsLength / 200 + 1, 2), 4) : 5 * (docsLength / 1000);
1310: this .progressStep = docsLength < n ? 1 : docsLength / n; // step should not be 0
1311: this .progressWorked = 0;
1312:
1313: // extract working copies
1314: ArrayList copies = new ArrayList();
1315: for (int i = 0; i < docsLength; i++) {
1316: SearchDocument document = searchDocuments[i];
1317: if (document instanceof WorkingCopyDocument) {
1318: copies
1319: .add(((WorkingCopyDocument) document).workingCopy);
1320: }
1321: }
1322: int copiesLength = copies.size();
1323: this .workingCopies = new org.eclipse.jdt.core.ICompilationUnit[copiesLength];
1324: copies.toArray(this .workingCopies);
1325:
1326: JavaModelManager manager = JavaModelManager
1327: .getJavaModelManager();
1328: this .bindings = new SimpleLookupTable();
1329: try {
1330: // optimize access to zip files during search operation
1331: manager.cacheZipFiles();
1332:
1333: // initialize handle factory (used as a cache of handles so as to optimize space)
1334: if (this .handleFactory == null)
1335: this .handleFactory = new HandleFactory();
1336:
1337: if (this .progressMonitor != null) {
1338: this .progressMonitor.beginTask(
1339: "", searchDocuments.length); //$NON-NLS-1$
1340: }
1341:
1342: // initialize pattern for polymorphic search (ie. method reference pattern)
1343: this .patternLocator.initializePolymorphicSearch(this );
1344:
1345: JavaProject previousJavaProject = null;
1346: PossibleMatchSet matchSet = new PossibleMatchSet();
1347: Util.sort(searchDocuments, new Util.Comparer() {
1348: public int compare(Object a, Object b) {
1349: return ((SearchDocument) a).getPath().compareTo(
1350: ((SearchDocument) b).getPath());
1351: }
1352: });
1353: int displayed = 0; // progress worked displayed
1354: String previousPath = null;
1355: for (int i = 0; i < docsLength; i++) {
1356: if (this .progressMonitor != null
1357: && this .progressMonitor.isCanceled()) {
1358: throw new OperationCanceledException();
1359: }
1360:
1361: // skip duplicate paths
1362: SearchDocument searchDocument = searchDocuments[i];
1363: searchDocuments[i] = null; // free current document
1364: String pathString = searchDocument.getPath();
1365: if (i > 0 && pathString.equals(previousPath)) {
1366: if (this .progressMonitor != null) {
1367: this .progressWorked++;
1368: if ((this .progressWorked % this .progressStep) == 0)
1369: this .progressMonitor
1370: .worked(this .progressStep);
1371: }
1372: displayed++;
1373: continue;
1374: }
1375: previousPath = pathString;
1376:
1377: Openable openable;
1378: org.eclipse.jdt.core.ICompilationUnit workingCopy = null;
1379: if (searchDocument instanceof WorkingCopyDocument) {
1380: workingCopy = ((WorkingCopyDocument) searchDocument).workingCopy;
1381: openable = (Openable) workingCopy;
1382: } else {
1383: openable = this .handleFactory.createOpenable(
1384: pathString, this .scope);
1385: }
1386: if (openable == null) {
1387: if (this .progressMonitor != null) {
1388: this .progressWorked++;
1389: if ((this .progressWorked % this .progressStep) == 0)
1390: this .progressMonitor
1391: .worked(this .progressStep);
1392: }
1393: displayed++;
1394: continue; // match is outside classpath
1395: }
1396:
1397: // create new parser and lookup environment if this is a new project
1398: IResource resource = null;
1399: JavaProject javaProject = (JavaProject) openable
1400: .getJavaProject();
1401: resource = workingCopy != null ? workingCopy
1402: .getResource() : openable.getResource();
1403: if (resource == null)
1404: resource = javaProject.getProject(); // case of a file in an external jar
1405: if (!javaProject.equals(previousJavaProject)) {
1406: // locate matches in previous project
1407: if (previousJavaProject != null) {
1408: try {
1409: locateMatches(previousJavaProject,
1410: matchSet, i - displayed);
1411: displayed = i;
1412: } catch (JavaModelException e) {
1413: // problem with classpath in this project -> skip it
1414: }
1415: matchSet.reset();
1416: }
1417: previousJavaProject = javaProject;
1418: }
1419: matchSet
1420: .add(new PossibleMatch(
1421: this ,
1422: resource,
1423: openable,
1424: searchDocument,
1425: ((InternalSearchPattern) this .pattern).mustResolve));
1426: }
1427:
1428: // last project
1429: if (previousJavaProject != null) {
1430: try {
1431: locateMatches(previousJavaProject, matchSet,
1432: docsLength - displayed);
1433: } catch (JavaModelException e) {
1434: // problem with classpath in last project -> ignore
1435: }
1436: }
1437:
1438: } finally {
1439: if (this .progressMonitor != null)
1440: this .progressMonitor.done();
1441: if (this .nameEnvironment != null)
1442: this .nameEnvironment.cleanup();
1443: manager.flushZipFiles();
1444: this .bindings = null;
1445: }
1446: }
1447:
1448: /**
1449: * Locates the package declarations corresponding to this locator's pattern.
1450: */
1451: public void locatePackageDeclarations(SearchParticipant participant)
1452: throws CoreException {
1453: locatePackageDeclarations(this .pattern, participant);
1454: }
1455:
1456: /**
1457: * Locates the package declarations corresponding to the search pattern.
1458: */
1459: protected void locatePackageDeclarations(
1460: SearchPattern searchPattern, SearchParticipant participant)
1461: throws CoreException {
1462: if (searchPattern instanceof OrPattern) {
1463: SearchPattern[] patterns = ((OrPattern) searchPattern).patterns;
1464: for (int i = 0, length = patterns.length; i < length; i++)
1465: locatePackageDeclarations(patterns[i], participant);
1466: } else if (searchPattern instanceof PackageDeclarationPattern) {
1467: IJavaElement focus = ((InternalSearchPattern) searchPattern).focus;
1468: if (focus != null) {
1469: if (encloses(focus)) {
1470: SearchMatch match = new PackageDeclarationMatch(
1471: focus
1472: .getAncestor(IJavaElement.PACKAGE_FRAGMENT),
1473: SearchMatch.A_ACCURATE, -1, -1,
1474: participant, focus.getResource());
1475: report(match);
1476: }
1477: return;
1478: }
1479: PackageDeclarationPattern pkgPattern = (PackageDeclarationPattern) searchPattern;
1480: boolean isWorkspaceScope = this .scope == JavaModelManager
1481: .getJavaModelManager().getWorkspaceScope();
1482: IPath[] scopeProjectsAndJars = isWorkspaceScope ? null
1483: : this .scope.enclosingProjectsAndJars();
1484: int scopeLength = isWorkspaceScope ? 0
1485: : scopeProjectsAndJars.length;
1486: IJavaProject[] projects = JavaModelManager
1487: .getJavaModelManager().getJavaModel()
1488: .getJavaProjects();
1489: SimpleSet packages = new SimpleSet();
1490: for (int i = 0, length = projects.length; i < length; i++) {
1491: IJavaProject javaProject = projects[i];
1492: // Verify that project belongs to the scope
1493: if (!isWorkspaceScope) {
1494: boolean found = false;
1495: for (int j = 0; j < scopeLength; j++) {
1496: if (javaProject.getPath().equals(
1497: scopeProjectsAndJars[j])) {
1498: found = true;
1499: break;
1500: }
1501: }
1502: if (!found)
1503: continue;
1504: }
1505: // Get all project package fragment names
1506: this .nameLookup = ((JavaProject) projects[i])
1507: .newNameLookup(this .workingCopies);
1508: IPackageFragment[] packageFragments = this .nameLookup
1509: .findPackageFragments(new String(
1510: pkgPattern.pkgName), false, true);
1511: int pLength = packageFragments == null ? 0
1512: : packageFragments.length;
1513: // Report matches avoiding duplicate names
1514: for (int p = 0; p < pLength; p++) {
1515: IPackageFragment fragment = packageFragments[p];
1516: if (packages.addIfNotIncluded(fragment) == null)
1517: continue;
1518: if (encloses(fragment)) {
1519: IResource resource = fragment.getResource();
1520: if (resource == null) // case of a file in an external jar
1521: resource = javaProject.getProject();
1522: try {
1523: if (encloses(fragment)) {
1524: SearchMatch match = new PackageDeclarationMatch(
1525: fragment,
1526: SearchMatch.A_ACCURATE, -1, -1,
1527: participant, resource);
1528: report(match);
1529: }
1530: } catch (JavaModelException e) {
1531: throw e;
1532: } catch (CoreException e) {
1533: throw new JavaModelException(e);
1534: }
1535: }
1536: }
1537: }
1538: }
1539: }
1540:
1541: //*/
1542: protected IType lookupType(ReferenceBinding typeBinding) {
1543: if (typeBinding == null)
1544: return null;
1545:
1546: char[] packageName = typeBinding.qualifiedPackageName();
1547: IPackageFragment[] pkgs = this .nameLookup
1548: .findPackageFragments(
1549: (packageName == null || packageName.length == 0) ? IPackageFragment.DEFAULT_PACKAGE_NAME
1550: : new String(packageName), false);
1551:
1552: // iterate type lookup in each package fragment
1553: char[] sourceName = typeBinding.qualifiedSourceName();
1554: String typeName = new String(sourceName);
1555: int acceptFlag = 0;
1556: if (typeBinding.isAnnotationType()) {
1557: acceptFlag = NameLookup.ACCEPT_ANNOTATIONS;
1558: } else if (typeBinding.isEnum()) {
1559: acceptFlag = NameLookup.ACCEPT_ENUMS;
1560: } else if (typeBinding.isInterface()) {
1561: acceptFlag = NameLookup.ACCEPT_INTERFACES;
1562: } else if (typeBinding.isClass()) {
1563: acceptFlag = NameLookup.ACCEPT_CLASSES;
1564: }
1565: if (pkgs != null) {
1566: for (int i = 0, length = pkgs.length; i < length; i++) {
1567: IType type = this .nameLookup
1568: .findType(typeName, pkgs[i], false, acceptFlag,
1569: true/*consider secondary types*/);
1570: if (type != null)
1571: return type;
1572: }
1573: }
1574:
1575: // search inside enclosing element
1576: char[][] qualifiedName = CharOperation.splitOn('.', sourceName);
1577: int length = qualifiedName.length;
1578: if (length == 0)
1579: return null;
1580:
1581: IType type = createTypeHandle(new String(qualifiedName[0])); // find the top-level type
1582: if (type == null)
1583: return null;
1584:
1585: for (int i = 1; i < length; i++) {
1586: type = type.getType(new String(qualifiedName[i]));
1587: if (type == null)
1588: return null;
1589: }
1590: if (type.exists())
1591: return type;
1592: return null;
1593: }
1594:
1595: public SearchMatch newDeclarationMatch(IJavaElement element,
1596: Binding binding, int accuracy, int offset, int length) {
1597: SearchParticipant participant = getParticipant();
1598: IResource resource = this .currentPossibleMatch.resource;
1599: return newDeclarationMatch(element, binding, accuracy, offset,
1600: length, participant, resource);
1601: }
1602:
1603: public SearchMatch newDeclarationMatch(IJavaElement element,
1604: Binding binding, int accuracy, int offset, int length,
1605: SearchParticipant participant, IResource resource) {
1606: switch (element.getElementType()) {
1607: case IJavaElement.PACKAGE_FRAGMENT:
1608: return new PackageDeclarationMatch(element, accuracy,
1609: offset, length, participant, resource);
1610: case IJavaElement.TYPE:
1611: return new TypeDeclarationMatch(binding == null ? element
1612: : ((JavaElement) element).resolved(binding),
1613: accuracy, offset, length, participant, resource);
1614: case IJavaElement.FIELD:
1615: return new FieldDeclarationMatch(binding == null ? element
1616: : ((JavaElement) element).resolved(binding),
1617: accuracy, offset, length, participant, resource);
1618: case IJavaElement.METHOD:
1619: return new MethodDeclarationMatch(binding == null ? element
1620: : ((JavaElement) element).resolved(binding),
1621: accuracy, offset, length, participant, resource);
1622: case IJavaElement.LOCAL_VARIABLE:
1623: return new LocalVariableDeclarationMatch(element, accuracy,
1624: offset, length, participant, resource);
1625: case IJavaElement.PACKAGE_DECLARATION:
1626: return new PackageDeclarationMatch(element, accuracy,
1627: offset, length, participant, resource);
1628: case IJavaElement.TYPE_PARAMETER:
1629: return new TypeParameterDeclarationMatch(element, accuracy,
1630: offset, length, participant, resource);
1631: default:
1632: return null;
1633: }
1634: }
1635:
1636: public SearchMatch newFieldReferenceMatch(
1637: IJavaElement enclosingElement, Binding enclosingBinding,
1638: int accuracy, int offset, int length, ASTNode reference) {
1639: int bits = reference.bits;
1640: boolean isCoupoundAssigned = (bits & ASTNode.IsCompoundAssigned) != 0;
1641: boolean isReadAccess = isCoupoundAssigned
1642: || (bits & ASTNode.IsStrictlyAssigned) == 0;
1643: boolean isWriteAccess = isCoupoundAssigned
1644: || (bits & ASTNode.IsStrictlyAssigned) != 0;
1645: boolean insideDocComment = (bits & ASTNode.InsideJavadoc) != 0;
1646: SearchParticipant participant = getParticipant();
1647: IResource resource = this .currentPossibleMatch.resource;
1648: if (enclosingBinding != null)
1649: enclosingElement = ((JavaElement) enclosingElement)
1650: .resolved(enclosingBinding);
1651: return new FieldReferenceMatch(enclosingElement, accuracy,
1652: offset, length, isReadAccess, isWriteAccess,
1653: insideDocComment, participant, resource);
1654: }
1655:
1656: public SearchMatch newLocalVariableReferenceMatch(
1657: IJavaElement enclosingElement, int accuracy, int offset,
1658: int length, ASTNode reference) {
1659: int bits = reference.bits;
1660: boolean isCoupoundAssigned = (bits & ASTNode.IsCompoundAssigned) != 0;
1661: boolean isReadAccess = isCoupoundAssigned
1662: || (bits & ASTNode.IsStrictlyAssigned) == 0;
1663: boolean isWriteAccess = isCoupoundAssigned
1664: || (bits & ASTNode.IsStrictlyAssigned) != 0;
1665: boolean insideDocComment = (bits & ASTNode.InsideJavadoc) != 0;
1666: SearchParticipant participant = getParticipant();
1667: IResource resource = this .currentPossibleMatch.resource;
1668: return new LocalVariableReferenceMatch(enclosingElement,
1669: accuracy, offset, length, isReadAccess, isWriteAccess,
1670: insideDocComment, participant, resource);
1671: }
1672:
1673: public SearchMatch newMethodReferenceMatch(
1674: IJavaElement enclosingElement, Binding enclosingBinding,
1675: int accuracy, int offset, int length,
1676: boolean isConstructor, boolean isSynthetic,
1677: ASTNode reference) {
1678: SearchParticipant participant = getParticipant();
1679: IResource resource = this .currentPossibleMatch.resource;
1680: boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
1681: if (enclosingBinding != null)
1682: enclosingElement = ((JavaElement) enclosingElement)
1683: .resolved(enclosingBinding);
1684: boolean isOverridden = (accuracy & PatternLocator.SUPER_INVOCATION_FLAVOR) != 0;
1685: return new MethodReferenceMatch(enclosingElement, accuracy,
1686: offset, length, isConstructor, isSynthetic,
1687: isOverridden, insideDocComment, participant, resource);
1688: }
1689:
1690: public SearchMatch newPackageReferenceMatch(
1691: IJavaElement enclosingElement, int accuracy, int offset,
1692: int length, ASTNode reference) {
1693: SearchParticipant participant = getParticipant();
1694: IResource resource = this .currentPossibleMatch.resource;
1695: boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
1696: return new PackageReferenceMatch(enclosingElement, accuracy,
1697: offset, length, insideDocComment, participant, resource);
1698: }
1699:
1700: public SearchMatch newTypeParameterReferenceMatch(
1701: IJavaElement enclosingElement, int accuracy, int offset,
1702: int length, ASTNode reference) {
1703: int bits = reference.bits;
1704: boolean insideDocComment = (bits & ASTNode.InsideJavadoc) != 0;
1705: SearchParticipant participant = getParticipant();
1706: IResource resource = this .currentPossibleMatch.resource;
1707: return new TypeParameterReferenceMatch(enclosingElement,
1708: accuracy, offset, length, insideDocComment,
1709: participant, resource);
1710: }
1711:
1712: public TypeReferenceMatch newTypeReferenceMatch(
1713: IJavaElement enclosingElement, Binding enclosingBinding,
1714: int accuracy, int offset, int length, ASTNode reference) {
1715: SearchParticipant participant = getParticipant();
1716: IResource resource = this .currentPossibleMatch.resource;
1717: boolean insideDocComment = (reference.bits & ASTNode.InsideJavadoc) != 0;
1718: if (enclosingBinding != null)
1719: enclosingElement = ((JavaElement) enclosingElement)
1720: .resolved(enclosingBinding);
1721: return new TypeReferenceMatch(enclosingElement, accuracy,
1722: offset, length, insideDocComment, participant, resource);
1723: }
1724:
1725: public TypeReferenceMatch newTypeReferenceMatch(
1726: IJavaElement enclosingElement, Binding enclosingBinding,
1727: int accuracy, ASTNode reference) {
1728: return newTypeReferenceMatch(enclosingElement,
1729: enclosingBinding, accuracy, reference.sourceStart,
1730: reference.sourceEnd - reference.sourceStart + 1,
1731: reference);
1732: }
1733:
1734: /**
1735: * Add the possibleMatch to the loop
1736: * -> build compilation unit declarations, their bindings and record their results.
1737: */
1738: protected boolean parseAndBuildBindings(
1739: PossibleMatch possibleMatch, boolean mustResolve)
1740: throws CoreException {
1741: if (this .progressMonitor != null
1742: && this .progressMonitor.isCanceled())
1743: throw new OperationCanceledException();
1744:
1745: try {
1746: if (BasicSearchEngine.VERBOSE)
1747: System.out
1748: .println("Parsing " + possibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
1749:
1750: this .parser.nodeSet = possibleMatch.nodeSet;
1751: CompilationResult unitResult = new CompilationResult(
1752: possibleMatch, 1, 1,
1753: this .options.maxProblemsPerUnit);
1754: CompilationUnitDeclaration parsedUnit = this .parser
1755: .dietParse(possibleMatch, unitResult);
1756: if (parsedUnit != null) {
1757: if (!parsedUnit.isEmpty()) {
1758: if (mustResolve) {
1759: this .lookupEnvironment
1760: .buildTypeBindings(parsedUnit, null /*no access restriction*/);
1761: }
1762: if (hasAlreadyDefinedType(parsedUnit))
1763: return false; // skip type has it is hidden so not visible
1764: getMethodBodies(parsedUnit, possibleMatch.nodeSet);
1765: if (this .patternLocator.mayBeGeneric
1766: && !mustResolve
1767: && possibleMatch.nodeSet.mustResolve) {
1768: // special case: possible match node set force resolution although pattern does not
1769: // => we need to build types for this compilation unit
1770: this .lookupEnvironment
1771: .buildTypeBindings(parsedUnit, null /*no access restriction*/);
1772: }
1773: }
1774:
1775: // add the possibleMatch with its parsedUnit to matchesToProcess
1776: possibleMatch.parsedUnit = parsedUnit;
1777: int size = this .matchesToProcess.length;
1778: if (this .numberOfMatches == size)
1779: System
1780: .arraycopy(
1781: this .matchesToProcess,
1782: 0,
1783: this .matchesToProcess = new PossibleMatch[size == 0 ? 1
1784: : size * 2], 0,
1785: this .numberOfMatches);
1786: this .matchesToProcess[this .numberOfMatches++] = possibleMatch;
1787: }
1788: } finally {
1789: this .parser.nodeSet = null;
1790: }
1791: return true;
1792: }
1793:
1794: /*
1795: * Process a compilation unit already parsed and build.
1796: */
1797: protected void process(PossibleMatch possibleMatch,
1798: boolean bindingsWereCreated) throws CoreException {
1799: this .currentPossibleMatch = possibleMatch;
1800: CompilationUnitDeclaration unit = possibleMatch.parsedUnit;
1801: try {
1802: if (unit.isEmpty()) {
1803: if (this .currentPossibleMatch.openable instanceof ClassFile) {
1804: ClassFile classFile = (ClassFile) this .currentPossibleMatch.openable;
1805: IBinaryType info = getBinaryInfo(classFile,
1806: this .currentPossibleMatch.resource);
1807: if (info != null) {
1808: boolean mayBeGeneric = this .patternLocator.mayBeGeneric;
1809: this .patternLocator.mayBeGeneric = false; // there's no longer generics in class files
1810: try {
1811: new ClassFileMatchLocator().locateMatches(
1812: this , classFile, info);
1813: } finally {
1814: this .patternLocator.mayBeGeneric = mayBeGeneric;
1815: }
1816: }
1817: }
1818: return;
1819: }
1820: if (hasAlreadyDefinedType(unit))
1821: return; // skip type has it is hidden so not visible
1822:
1823: // Move getMethodBodies to #parseAndBuildings(...) method to allow possible match resolution management
1824: //getMethodBodies(unit);
1825:
1826: boolean mustResolve = (((InternalSearchPattern) this .pattern).mustResolve || possibleMatch.nodeSet.mustResolve);
1827: if (bindingsWereCreated && mustResolve) {
1828: if (unit.types != null) {
1829: if (BasicSearchEngine.VERBOSE)
1830: System.out
1831: .println("Resolving " + this .currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
1832:
1833: this .lookupEnvironment.unitBeingCompleted = unit;
1834: reduceParseTree(unit);
1835:
1836: if (unit.scope != null) {
1837: // fault in fields & methods
1838: unit.scope.faultInTypes();
1839: }
1840: unit.resolve();
1841: } else if (unit.isPackageInfo()) {
1842: if (BasicSearchEngine.VERBOSE)
1843: System.out
1844: .println("Resolving " + this .currentPossibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$
1845: unit.resolve();
1846: }
1847: }
1848: reportMatching(unit, mustResolve);
1849: } catch (AbortCompilation e) {
1850: // could not resolve: report inaccurate matches
1851: reportMatching(unit, false); // do not resolve when cu has errors
1852: if (!(e instanceof AbortCompilationUnit)) {
1853: // problem with class path
1854: throw e;
1855: }
1856: } finally {
1857: this .lookupEnvironment.unitBeingCompleted = null;
1858: this .currentPossibleMatch = null;
1859: }
1860: }
1861:
1862: protected void purgeMethodStatements(TypeDeclaration type,
1863: boolean checkEachMethod) {
1864: checkEachMethod = checkEachMethod
1865: && this .currentPossibleMatch.nodeSet.hasPossibleNodes(
1866: type.declarationSourceStart,
1867: type.declarationSourceEnd);
1868: AbstractMethodDeclaration[] methods = type.methods;
1869: if (methods != null) {
1870: if (checkEachMethod) {
1871: for (int j = 0, length = methods.length; j < length; j++) {
1872: AbstractMethodDeclaration method = methods[j];
1873: if (!this .currentPossibleMatch.nodeSet
1874: .hasPossibleNodes(
1875: method.declarationSourceStart,
1876: method.declarationSourceEnd)) {
1877: method.statements = null;
1878: method.javadoc = null;
1879: }
1880: }
1881: } else {
1882: for (int j = 0, length = methods.length; j < length; j++) {
1883: methods[j].statements = null;
1884: methods[j].javadoc = null;
1885: }
1886: }
1887: }
1888:
1889: TypeDeclaration[] memberTypes = type.memberTypes;
1890: if (memberTypes != null)
1891: for (int i = 0, l = memberTypes.length; i < l; i++)
1892: purgeMethodStatements(memberTypes[i], checkEachMethod);
1893: }
1894:
1895: /**
1896: * Called prior to the unit being resolved. Reduce the parse tree where possible.
1897: */
1898: protected void reduceParseTree(CompilationUnitDeclaration unit) {
1899: // remove statements from methods that have no possible matching nodes
1900: TypeDeclaration[] types = unit.types;
1901: for (int i = 0, l = types.length; i < l; i++)
1902: purgeMethodStatements(types[i], true);
1903: }
1904:
1905: public SearchParticipant getParticipant() {
1906: return this .currentPossibleMatch.document.getParticipant();
1907: }
1908:
1909: protected void report(SearchMatch match) throws CoreException {
1910: if (match == null) {
1911: if (BasicSearchEngine.VERBOSE) {
1912: System.out.println("Cannot report a null match!!!"); //$NON-NLS-1$
1913: }
1914: return;
1915: }
1916: long start = -1;
1917: if (BasicSearchEngine.VERBOSE) {
1918: start = System.currentTimeMillis();
1919: System.out.println("Reporting match"); //$NON-NLS-1$
1920: System.out.println("\tResource: " + match.getResource());//$NON-NLS-1$
1921: System.out
1922: .println("\tPositions: [offset=" + match.getOffset() + ", length=" + match.getLength() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
1923: try {
1924: if (this .parser != null
1925: && match.getOffset() > 0
1926: && match.getLength() > 0
1927: && !(match.getElement() instanceof BinaryMember)) {
1928: String selection = new String(
1929: this .parser.scanner.source, match
1930: .getOffset(), match.getLength());
1931: System.out
1932: .println("\tSelection: -->" + selection + "<--"); //$NON-NLS-1$ //$NON-NLS-2$
1933: }
1934: } catch (Exception e) {
1935: // it's just for debug purposes... ignore all exceptions in this area
1936: }
1937: try {
1938: JavaElement javaElement = (JavaElement) match
1939: .getElement();
1940: System.out
1941: .println("\tJava element: " + javaElement.toStringWithAncestors()); //$NON-NLS-1$
1942: if (!javaElement.exists()) {
1943: System.out
1944: .println("\t\tWARNING: this element does NOT exist!"); //$NON-NLS-1$
1945: }
1946: } catch (Exception e) {
1947: // it's just for debug purposes... ignore all exceptions in this area
1948: }
1949: if (match instanceof TypeReferenceMatch) {
1950: try {
1951: TypeReferenceMatch typeRefMatch = (TypeReferenceMatch) match;
1952: JavaElement local = (JavaElement) typeRefMatch
1953: .getLocalElement();
1954: if (local != null) {
1955: System.out
1956: .println("\tLocal element: " + local.toStringWithAncestors()); //$NON-NLS-1$
1957: }
1958: IJavaElement[] others = typeRefMatch
1959: .getOtherElements();
1960: if (others != null) {
1961: int length = others.length;
1962: if (length > 0) {
1963: System.out.println("\tOther elements:"); //$NON-NLS-1$
1964: for (int i = 0; i < length; i++) {
1965: JavaElement other = (JavaElement) others[i];
1966: System.out
1967: .println("\t\t- " + other.toStringWithAncestors()); //$NON-NLS-1$
1968: }
1969: }
1970: }
1971: } catch (Exception e) {
1972: // it's just for debug purposes... ignore all exceptions in this area
1973: }
1974: }
1975: System.out
1976: .println(match.getAccuracy() == SearchMatch.A_ACCURATE ? "\tAccuracy: EXACT_MATCH" //$NON-NLS-1$
1977: : "\tAccuracy: POTENTIAL_MATCH"); //$NON-NLS-1$
1978: System.out.print("\tRule: "); //$NON-NLS-1$
1979: if (match.isExact()) {
1980: System.out.print("EXACT"); //$NON-NLS-1$
1981: } else if (match.isEquivalent()) {
1982: System.out.print("EQUIVALENT"); //$NON-NLS-1$
1983: } else if (match.isErasure()) {
1984: System.out.print("ERASURE"); //$NON-NLS-1$
1985: } else {
1986: System.out.print("INVALID RULE"); //$NON-NLS-1$
1987: }
1988: if (match instanceof MethodReferenceMatch) {
1989: MethodReferenceMatch methodReferenceMatch = (MethodReferenceMatch) match;
1990: if (methodReferenceMatch.isSuperInvocation()) {
1991: System.out.print("+SUPER INVOCATION"); //$NON-NLS-1$
1992: }
1993: if (methodReferenceMatch.isImplicit()) {
1994: System.out.print("+IMPLICIT"); //$NON-NLS-1$
1995: }
1996: if (methodReferenceMatch.isSynthetic()) {
1997: System.out.print("+SYNTHETIC"); //$NON-NLS-1$
1998: }
1999: }
2000: System.out.println("\n\tRaw: " + match.isRaw()); //$NON-NLS-1$
2001: }
2002: this .requestor.acceptSearchMatch(match);
2003: if (BasicSearchEngine.VERBOSE)
2004: this .resultCollectorTime += System.currentTimeMillis()
2005: - start;
2006: }
2007:
2008: /**
2009: * Finds the accurate positions of the sequence of tokens given by qualifiedName
2010: * in the source and reports a reference to this this qualified name
2011: * to the search requestor.
2012: */
2013: protected void reportAccurateTypeReference(SearchMatch match,
2014: ASTNode typeRef, char[] name) throws CoreException {
2015: if (match.getRule() == 0)
2016: return;
2017: if (!encloses((IJavaElement) match.getElement()))
2018: return;
2019:
2020: // Compute source positions of the qualified reference
2021: int sourceStart = typeRef.sourceStart;
2022: int sourceEnd = typeRef.sourceEnd;
2023: Scanner scanner = this .parser.scanner;
2024: scanner.setSource(this .currentPossibleMatch.getContents());
2025: scanner.resetTo(sourceStart, sourceEnd);
2026:
2027: int token = -1;
2028: int currentPosition;
2029: do {
2030: currentPosition = scanner.currentPosition;
2031: try {
2032: token = scanner.getNextToken();
2033: } catch (InvalidInputException e) {
2034: // ignore
2035: }
2036: if (token == TerminalTokens.TokenNameIdentifier
2037: && this .pattern.matchesName(name, scanner
2038: .getCurrentTokenSource())) {
2039: int length = scanner.currentPosition - currentPosition;
2040: match.setOffset(currentPosition);
2041: match.setLength(length);
2042: report(match);
2043: return;
2044: }
2045: } while (token != TerminalTokens.TokenNameEOF);
2046:
2047: // Report match
2048: match.setOffset(sourceStart);
2049: match.setLength(sourceEnd - sourceStart + 1);
2050: report(match);
2051: }
2052:
2053: /**
2054: * Finds the accurate positions of the sequence of tokens given by qualifiedName
2055: * in the source and reports a reference to this parameterized type name
2056: * to the search requestor.
2057: * @since 3.1
2058: */
2059: protected void reportAccurateParameterizedMethodReference(
2060: SearchMatch match, ASTNode statement,
2061: TypeReference[] typeArguments) throws CoreException {
2062: if (match.getRule() == 0)
2063: return;
2064: if (!encloses((IJavaElement) match.getElement()))
2065: return;
2066:
2067: // If there's type arguments, look for end (ie. char '>') of last one.
2068: int start = match.getOffset();
2069: if (typeArguments != null && typeArguments.length > 0) {
2070: boolean isErasureMatch = (pattern instanceof OrPattern) ? ((OrPattern) pattern)
2071: .isErasureMatch()
2072: : ((JavaSearchPattern) pattern).isErasureMatch();
2073: if (!isErasureMatch) {
2074:
2075: // Initialize scanner
2076: Scanner scanner = this .parser.scanner;
2077: char[] source = this .currentPossibleMatch.getContents();
2078: scanner.setSource(source);
2079:
2080: // Search previous opening '<'
2081: start = typeArguments[0].sourceStart;
2082: int end = statement.sourceEnd;
2083: scanner.resetTo(start, end);
2084: int lineStart = start;
2085: try {
2086: linesUp: while (true) {
2087: while (scanner.source[scanner.currentPosition] != '\n') {
2088: scanner.currentPosition--;
2089: if (scanner.currentPosition == 0)
2090: break linesUp;
2091: }
2092: lineStart = scanner.currentPosition + 1;
2093: scanner.resetTo(lineStart, end);
2094: while (!scanner.atEnd()) {
2095: if (scanner.getNextToken() == TerminalTokens.TokenNameLESS) {
2096: start = scanner
2097: .getCurrentTokenStartPosition();
2098: break linesUp;
2099: }
2100: }
2101: end = lineStart - 2;
2102: scanner.currentPosition = end;
2103: }
2104: } catch (InvalidInputException ex) {
2105: // give up
2106: }
2107: }
2108: }
2109:
2110: // Report match
2111: match.setOffset(start);
2112: match.setLength(statement.sourceEnd - start + 1);
2113: report(match);
2114: }
2115:
2116: /**
2117: * Finds the accurate positions of the sequence of tokens given by qualifiedName
2118: * in the source and reports a reference to this parameterized type name
2119: * to the search requestor.
2120: * @since 3.1
2121: */
2122: protected void reportAccurateParameterizedTypeReference(
2123: SearchMatch match, TypeReference typeRef, int index,
2124: TypeReference[] typeArguments) throws CoreException {
2125: if (match.getRule() == 0)
2126: return;
2127: if (!encloses((IJavaElement) match.getElement()))
2128: return;
2129:
2130: // If there's type arguments, look for end (ie. char '>') of last one.
2131: int end = typeRef.sourceEnd;
2132: if (typeArguments != null) {
2133: // Initialize scanner
2134: Scanner scanner = this .parser.scanner;
2135: char[] source = this .currentPossibleMatch.getContents();
2136: scanner.setSource(source);
2137:
2138: boolean shouldMatchErasure = (pattern instanceof OrPattern) ? ((OrPattern) pattern)
2139: .isErasureMatch()
2140: : ((JavaSearchPattern) pattern).isErasureMatch();
2141: boolean hasSignatures = (pattern instanceof OrPattern) ? ((OrPattern) pattern)
2142: .hasSignatures()
2143: : ((JavaSearchPattern) pattern).hasSignatures();
2144: if (shouldMatchErasure || !hasSignatures) {
2145: // if pattern is erasure only, then select the end of the reference
2146: if (typeRef instanceof QualifiedTypeReference
2147: && index >= 0) {
2148: long[] positions = ((QualifiedTypeReference) typeRef).sourcePositions;
2149: end = (int) positions[index];
2150: } else if (typeRef instanceof ArrayTypeReference) {
2151: end = ((ArrayTypeReference) typeRef).originalSourceEnd;
2152: }
2153: } else {
2154: // Set scanner position at end of last type argument
2155: scanner.resetTo(end, source.length - 1);
2156: int depth = 0;
2157: for (int i = typeArguments.length - 1; i >= 0; i--) {
2158: if (typeArguments[i] != null) {
2159: long lastTypeArgInfo = findLastTypeArgumentInfo(typeArguments[i]);
2160: depth = (int) (lastTypeArgInfo >>> 32) + 1;
2161: scanner.resetTo(((int) lastTypeArgInfo) + 1,
2162: scanner.eofPosition - 1);
2163: break;
2164: }
2165: }
2166:
2167: // Now, scan to search next closing '>'
2168: while (depth-- > 0) {
2169: while (!scanner.atEnd()) {
2170: if (scanner.getNextChar() == '>') {
2171: end = scanner.currentPosition - 1;
2172: break;
2173: }
2174: }
2175: }
2176: }
2177: }
2178:
2179: // Report match
2180: match.setLength(end - match.getOffset() + 1);
2181: report(match);
2182: }
2183:
2184: /**
2185: * Finds the accurate positions of each valid token in the source and
2186: * reports a reference to this token to the search requestor.
2187: * A token is valid if it has an accuracy which is not -1.
2188: */
2189: protected void reportAccurateEnumConstructorReference(
2190: SearchMatch match, FieldDeclaration field,
2191: AllocationExpression allocation) throws CoreException {
2192: // Verify that field declaration is really an enum constant
2193: if (allocation == null || allocation.enumConstant == null) {
2194: report(match);
2195: return;
2196: }
2197:
2198: // Get scan area
2199: int sourceStart = match.getOffset() + match.getLength();
2200: if (allocation.arguments != null
2201: && allocation.arguments.length > 0) {
2202: sourceStart = allocation.arguments[allocation.arguments.length - 1].sourceEnd + 1;
2203: }
2204: int sourceEnd = field.declarationSourceEnd;
2205: if (allocation instanceof QualifiedAllocationExpression) {
2206: QualifiedAllocationExpression qualifiedAllocation = (QualifiedAllocationExpression) allocation;
2207: if (qualifiedAllocation.anonymousType != null) {
2208: sourceEnd = qualifiedAllocation.anonymousType.sourceStart - 1;
2209: }
2210: }
2211:
2212: // Scan to find last closing parenthesis
2213: Scanner scanner = this .parser.scanner;
2214: scanner.setSource(this .currentPossibleMatch.getContents());
2215: scanner.resetTo(sourceStart, sourceEnd);
2216: try {
2217: int token = scanner.getNextToken();
2218: while (token != TerminalTokens.TokenNameEOF) {
2219: if (token == TerminalTokens.TokenNameRPAREN) {
2220: sourceEnd = scanner.getCurrentTokenEndPosition();
2221: }
2222: token = scanner.getNextToken();
2223: }
2224: } catch (InvalidInputException iie) {
2225: // give up
2226: }
2227:
2228: // Report match
2229: match.setLength(sourceEnd - match.getOffset() + 1);
2230: report(match);
2231: }
2232:
2233: /**
2234: * Finds the accurate positions of each valid token in the source and
2235: * reports a reference to this token to the search requestor.
2236: * A token is valid if it has an accuracy which is not -1.
2237: */
2238: protected void reportAccurateFieldReference(SearchMatch[] matches,
2239: QualifiedNameReference qNameRef) throws CoreException {
2240: if (matches == null)
2241: return; // there's nothing to accurate in this case
2242: int matchesLength = matches.length;
2243:
2244: int sourceStart = qNameRef.sourceStart;
2245: int sourceEnd = qNameRef.sourceEnd;
2246: char[][] tokens = qNameRef.tokens;
2247:
2248: // compute source positions of the qualified reference
2249: Scanner scanner = this .parser.scanner;
2250: scanner.setSource(this .currentPossibleMatch.getContents());
2251: scanner.resetTo(sourceStart, sourceEnd);
2252: int sourceLength = sourceEnd - sourceStart + 1;
2253:
2254: int refSourceStart = -1, refSourceEnd = -1;
2255: int length = tokens.length;
2256: int token = -1;
2257: int previousValid = -1;
2258: int i = 0;
2259: int index = 0;
2260: do {
2261: int currentPosition = scanner.currentPosition;
2262: // read token
2263: try {
2264: token = scanner.getNextToken();
2265: } catch (InvalidInputException e) {
2266: //ignore
2267: }
2268: if (token != TerminalTokens.TokenNameEOF) {
2269: char[] currentTokenSource = scanner
2270: .getCurrentTokenSource();
2271: boolean equals = false;
2272: while (i < length
2273: && !(equals = this .pattern.matchesName(
2274: tokens[i++], currentTokenSource))) {/*empty*/
2275: }
2276: if (equals
2277: && (previousValid == -1 || previousValid == i - 2)) {
2278: previousValid = i - 1;
2279: if (refSourceStart == -1)
2280: refSourceStart = currentPosition;
2281: refSourceEnd = scanner.currentPosition - 1;
2282: } else {
2283: i = 0;
2284: refSourceStart = -1;
2285: previousValid = -1;
2286: }
2287: // read '.'
2288: try {
2289: token = scanner.getNextToken();
2290: } catch (InvalidInputException e) {
2291: // ignore
2292: }
2293: }
2294: SearchMatch match = matches[index];
2295: if (match != null && match.getRule() != 0) {
2296: if (!encloses((IJavaElement) match.getElement()))
2297: return;
2298: // accept reference
2299: if (refSourceStart != -1) {
2300: match.setOffset(refSourceStart);
2301: match.setLength(refSourceEnd - refSourceStart + 1);
2302: report(match);
2303: } else {
2304: match.setOffset(sourceStart);
2305: match.setLength(sourceLength);
2306: report(match);
2307: }
2308: i = 0;
2309: }
2310: refSourceStart = -1;
2311: previousValid = -1;
2312: if (index < matchesLength - 1) {
2313: index++;
2314: }
2315: } while (token != TerminalTokens.TokenNameEOF);
2316:
2317: }
2318:
2319: protected void reportBinaryMemberDeclaration(IResource resource,
2320: IMember binaryMember, Binding binaryMemberBinding,
2321: IBinaryType info, int accuracy) throws CoreException {
2322: ClassFile classFile = (ClassFile) binaryMember.getClassFile();
2323: ISourceRange range = classFile.isOpen() ? binaryMember
2324: .getNameRange() : SourceMapper.UNKNOWN_RANGE;
2325: if (range.getOffset() == -1) {
2326: BinaryType type = (BinaryType) classFile.getType();
2327: String sourceFileName = type.sourceFileName(info);
2328: if (sourceFileName != null) {
2329: SourceMapper mapper = classFile.getSourceMapper();
2330: if (mapper != null) {
2331: char[] contents = mapper.findSource(type,
2332: sourceFileName);
2333: if (contents != null)
2334: range = mapper.mapSource(type, contents, info,
2335: binaryMember);
2336: }
2337: }
2338: }
2339: if (resource == null)
2340: resource = this .currentPossibleMatch.resource;
2341: SearchMatch match = newDeclarationMatch(binaryMember,
2342: binaryMemberBinding, accuracy, range.getOffset(), range
2343: .getLength(), getParticipant(), resource);
2344: report(match);
2345: }
2346:
2347: /**
2348: * Visit the given method declaration and report the nodes that match exactly the
2349: * search pattern (ie. the ones in the matching nodes set)
2350: * Note that the method declaration has already been checked.
2351: */
2352: protected void reportMatching(TypeDeclaration type,
2353: AbstractMethodDeclaration method, IJavaElement parent,
2354: int accuracy, boolean typeInHierarchy,
2355: MatchingNodeSet nodeSet) throws CoreException {
2356: IJavaElement enclosingElement = null;
2357: if (accuracy > -1) {
2358: enclosingElement = createHandle(method, parent);
2359: if (enclosingElement != null) { // skip if unable to find method
2360: // compute source positions of the selector
2361: Scanner scanner = parser.scanner;
2362: int nameSourceStart = method.sourceStart;
2363: scanner.setSource(this .currentPossibleMatch
2364: .getContents());
2365: scanner.resetTo(nameSourceStart, method.sourceEnd);
2366: try {
2367: scanner.getNextToken();
2368: } catch (InvalidInputException e) {
2369: // ignore
2370: }
2371: if (encloses(enclosingElement)) {
2372: SearchMatch match = null;
2373: if (method.isDefaultConstructor()) {
2374: // Use type for match associated element as default constructor does not exist in source
2375: int offset = type.sourceStart;
2376: match = this .patternLocator
2377: .newDeclarationMatch(type, parent,
2378: type.binding, accuracy,
2379: type.sourceEnd - offset + 1,
2380: this );
2381: } else {
2382: int length = scanner.currentPosition
2383: - nameSourceStart;
2384: match = this .patternLocator
2385: .newDeclarationMatch(method,
2386: enclosingElement,
2387: method.binding, accuracy,
2388: length, this );
2389: }
2390: if (match != null) {
2391: report(match);
2392: }
2393: }
2394: }
2395: }
2396:
2397: // handle nodes for the local type first
2398: if ((method.bits & ASTNode.HasLocalType) != 0) {
2399: if (enclosingElement == null)
2400: enclosingElement = createHandle(method, parent);
2401: LocalDeclarationVisitor localDeclarationVisitor = new LocalDeclarationVisitor(
2402: enclosingElement, method.binding, nodeSet);
2403: try {
2404: method.traverse(localDeclarationVisitor,
2405: (ClassScope) null);
2406: } catch (WrappedCoreException e) {
2407: throw e.coreException;
2408: }
2409: }
2410:
2411: // report the type parameters
2412: TypeParameter[] typeParameters = method.typeParameters();
2413: if (typeParameters != null) {
2414: if (enclosingElement == null) {
2415: enclosingElement = createHandle(method, parent);
2416: }
2417: reportMatching(typeParameters, enclosingElement, parent,
2418: method.binding, nodeSet);
2419: }
2420:
2421: // report annotations
2422: if (method.annotations != null) {
2423: if (enclosingElement == null) {
2424: enclosingElement = createHandle(method, parent);
2425: }
2426: reportMatching(method.annotations, enclosingElement,
2427: method.binding, nodeSet, true, true);
2428: }
2429:
2430: // references in this method
2431: if (typeInHierarchy) {
2432: ASTNode[] nodes = nodeSet.matchingNodes(
2433: method.declarationSourceStart,
2434: method.declarationSourceEnd);
2435: if (nodes != null) {
2436: if ((this .matchContainer & PatternLocator.METHOD_CONTAINER) != 0) {
2437: if (enclosingElement == null)
2438: enclosingElement = createHandle(method, parent);
2439: if (encloses(enclosingElement)) {
2440: for (int i = 0, l = nodes.length; i < l; i++) {
2441: ASTNode node = nodes[i];
2442: Integer level = (Integer) nodeSet.matchingNodes
2443: .removeKey(node);
2444: this .patternLocator.matchReportReference(
2445: node, enclosingElement,
2446: method.binding, method.scope, level
2447: .intValue(), this );
2448: }
2449: return;
2450: }
2451: }
2452: for (int i = 0, l = nodes.length; i < l; i++)
2453: nodeSet.matchingNodes.removeKey(nodes[i]);
2454: }
2455: }
2456: }
2457:
2458: /**
2459: * Report matching in annotations.
2460: */
2461: protected void reportMatching(Annotation[] annotations,
2462: IJavaElement enclosingElement, Binding elementBinding,
2463: MatchingNodeSet nodeSet, boolean matchedContainer,
2464: boolean enclosesElement) throws CoreException {
2465: for (int i = 0, al = annotations.length; i < al; i++) {
2466: Annotation annotationType = annotations[i];
2467:
2468: // Look for annotation type ref
2469: TypeReference typeRef = annotationType.type;
2470: Integer level = (Integer) nodeSet.matchingNodes
2471: .removeKey(typeRef);
2472: if (level != null && matchedContainer) {
2473: this .patternLocator.matchReportReference(typeRef,
2474: enclosingElement, elementBinding, level
2475: .intValue(), this );
2476: }
2477:
2478: // Look for attribute ref
2479: MemberValuePair[] pairs = annotationType.memberValuePairs();
2480: for (int j = 0, pl = pairs.length; j < pl; j++) {
2481: MemberValuePair pair = pairs[j];
2482: level = (Integer) nodeSet.matchingNodes.removeKey(pair);
2483: if (level != null && enclosesElement) {
2484: ASTNode reference = (annotationType instanceof SingleMemberAnnotation) ? (ASTNode) annotationType
2485: : pair;
2486: this .patternLocator.matchReportReference(reference,
2487: enclosingElement, pair.binding, level
2488: .intValue(), this );
2489: }
2490: }
2491:
2492: // Look for reference inside annotation
2493: ASTNode[] nodes = nodeSet.matchingNodes(
2494: annotationType.sourceStart,
2495: annotationType.declarationSourceEnd);
2496: if (nodes != null) {
2497: if (!matchedContainer) {
2498: for (int j = 0, nl = nodes.length; j < nl; j++) {
2499: nodeSet.matchingNodes.removeKey(nodes[j]);
2500: }
2501: } else {
2502: for (int j = 0, nl = nodes.length; j < nl; j++) {
2503: ASTNode node = nodes[j];
2504: level = (Integer) nodeSet.matchingNodes
2505: .removeKey(node);
2506: if (enclosesElement) {
2507: this .patternLocator.matchReportReference(
2508: node, enclosingElement,
2509: elementBinding, level.intValue(),
2510: this );
2511: }
2512: }
2513: }
2514: }
2515: }
2516: }
2517:
2518: /**
2519: * Visit the given resolved parse tree and report the nodes that match the search pattern.
2520: */
2521: protected void reportMatching(CompilationUnitDeclaration unit,
2522: boolean mustResolve) throws CoreException {
2523: MatchingNodeSet nodeSet = this .currentPossibleMatch.nodeSet;
2524: boolean locatorMustResolve = this .patternLocator.mustResolve;
2525: if (nodeSet.mustResolve)
2526: this .patternLocator.mustResolve = true;
2527: if (BasicSearchEngine.VERBOSE) {
2528: System.out.println("Report matching: "); //$NON-NLS-1$
2529: int size = nodeSet.matchingNodes == null ? 0
2530: : nodeSet.matchingNodes.elementSize;
2531: System.out.print(" - node set: accurate=" + size); //$NON-NLS-1$
2532: size = nodeSet.possibleMatchingNodesSet == null ? 0
2533: : nodeSet.possibleMatchingNodesSet.elementSize;
2534: System.out.println(", possible=" + size); //$NON-NLS-1$
2535: System.out.print(" - must resolve: " + mustResolve); //$NON-NLS-1$
2536: System.out
2537: .print(" (locator: " + this .patternLocator.mustResolve); //$NON-NLS-1$
2538: System.out
2539: .println(", nodeSet: " + nodeSet.mustResolve + ')'); //$NON-NLS-1$
2540: }
2541: if (mustResolve) {
2542: this .unitScope = unit.scope.compilationUnitScope();
2543: // move the possible matching nodes that exactly match the search pattern to the matching nodes set
2544: Object[] nodes = nodeSet.possibleMatchingNodesSet.values;
2545: for (int i = 0, l = nodes.length; i < l; i++) {
2546: ASTNode node = (ASTNode) nodes[i];
2547: if (node == null)
2548: continue;
2549: if (node instanceof ImportReference) {
2550: // special case for import refs: they don't know their binding
2551: // import ref cannot be in the hierarchy of a type
2552: if (this .hierarchyResolver != null)
2553: continue;
2554:
2555: ImportReference importRef = (ImportReference) node;
2556: Binding binding = (importRef.bits & ASTNode.OnDemand) != 0 ? unitScope
2557: .getImport(CharOperation.subarray(
2558: importRef.tokens, 0,
2559: importRef.tokens.length), true,
2560: importRef.isStatic())
2561: : unitScope.getImport(importRef.tokens,
2562: false, importRef.isStatic());
2563: this .patternLocator.matchLevelAndReportImportRef(
2564: importRef, binding, this );
2565: }
2566: nodeSet.addMatch(node, this .patternLocator
2567: .resolveLevel(node));
2568: }
2569: nodeSet.possibleMatchingNodesSet = new SimpleSet(3);
2570: if (BasicSearchEngine.VERBOSE) {
2571: int size = nodeSet.matchingNodes == null ? 0
2572: : nodeSet.matchingNodes.elementSize;
2573: System.out.print(" - node set: accurate=" + size); //$NON-NLS-1$
2574: size = nodeSet.possibleMatchingNodesSet == null ? 0
2575: : nodeSet.possibleMatchingNodesSet.elementSize;
2576: System.out.println(", possible=" + size); //$NON-NLS-1$
2577: }
2578: } else {
2579: this .unitScope = null;
2580: }
2581:
2582: if (nodeSet.matchingNodes.elementSize == 0)
2583: return; // no matching nodes were found
2584: this .methodHandles = new HashSet();
2585:
2586: boolean matchedUnitContainer = (this .matchContainer & PatternLocator.COMPILATION_UNIT_CONTAINER) != 0;
2587:
2588: // report references in javadoc
2589: if (unit.javadoc != null) {
2590: ASTNode[] nodes = nodeSet.matchingNodes(
2591: unit.javadoc.sourceStart, unit.javadoc.sourceEnd);
2592: if (nodes != null) {
2593: if (!matchedUnitContainer) {
2594: for (int i = 0, l = nodes.length; i < l; i++)
2595: nodeSet.matchingNodes.removeKey(nodes[i]);
2596: } else {
2597: IJavaElement element = createPackageDeclarationHandle(unit);
2598: for (int i = 0, l = nodes.length; i < l; i++) {
2599: ASTNode node = nodes[i];
2600: Integer level = (Integer) nodeSet.matchingNodes
2601: .removeKey(node);
2602: if (encloses(element))
2603: this .patternLocator.matchReportReference(
2604: node, element, null/*no binding*/,
2605: level.intValue(), this );
2606: }
2607: }
2608: }
2609: }
2610:
2611: if (matchedUnitContainer) {
2612: ImportReference pkg = unit.currentPackage;
2613: if (pkg != null && pkg.annotations != null) {
2614: IJavaElement element = createPackageDeclarationHandle(unit);
2615: if (element != null) {
2616: reportMatching(pkg.annotations, element, null,
2617: nodeSet, true, encloses(element));
2618: }
2619: }
2620:
2621: ImportReference[] imports = unit.imports;
2622: if (imports != null) {
2623: for (int i = 0, l = imports.length; i < l; i++) {
2624: ImportReference importRef = imports[i];
2625: Integer level = (Integer) nodeSet.matchingNodes
2626: .removeKey(importRef);
2627: if (level != null)
2628: this .patternLocator.matchReportImportRef(
2629: importRef, null/*no binding*/,
2630: createImportHandle(importRef), level
2631: .intValue(), this );
2632: }
2633: }
2634: }
2635:
2636: TypeDeclaration[] types = unit.types;
2637: if (types != null) {
2638: for (int i = 0, l = types.length; i < l; i++) {
2639: if (nodeSet.matchingNodes.elementSize == 0)
2640: return; // reported all the matching nodes
2641: TypeDeclaration type = types[i];
2642: Integer level = (Integer) nodeSet.matchingNodes
2643: .removeKey(type);
2644: int accuracy = (level != null && matchedUnitContainer) ? level
2645: .intValue()
2646: : -1;
2647: reportMatching(type, null, accuracy, nodeSet, 1);
2648: }
2649: }
2650:
2651: // Clear handle cache
2652: this .methodHandles = null;
2653: this .bindings.removeKey(this .pattern);
2654: this .patternLocator.mustResolve = locatorMustResolve;
2655: }
2656:
2657: /**
2658: * Visit the given field declaration and report the nodes that match exactly the
2659: * search pattern (ie. the ones in the matching nodes set)
2660: */
2661: protected void reportMatching(FieldDeclaration field,
2662: FieldDeclaration[] otherFields, TypeDeclaration type,
2663: IJavaElement parent, int accuracy, boolean typeInHierarchy,
2664: MatchingNodeSet nodeSet) throws CoreException {
2665: IJavaElement enclosingElement = null;
2666: if (accuracy > -1) {
2667: enclosingElement = createHandle(field, type, parent);
2668: if (encloses(enclosingElement)) {
2669: int offset = field.sourceStart;
2670: SearchMatch match = newDeclarationMatch(
2671: enclosingElement, field.binding, accuracy,
2672: offset, field.sourceEnd - offset + 1);
2673: if (field.initialization instanceof AllocationExpression) {
2674: reportAccurateEnumConstructorReference(match,
2675: field,
2676: (AllocationExpression) field.initialization);
2677: } else {
2678: report(match);
2679: }
2680: }
2681: }
2682:
2683: // handle the nodes for the local type first
2684: if ((field.bits & ASTNode.HasLocalType) != 0) {
2685: if (enclosingElement == null)
2686: enclosingElement = createHandle(field, type, parent);
2687: LocalDeclarationVisitor localDeclarationVisitor = new LocalDeclarationVisitor(
2688: enclosingElement, field.binding, nodeSet);
2689: try {
2690: field.traverse(localDeclarationVisitor, null);
2691: } catch (WrappedCoreException e) {
2692: throw e.coreException;
2693: }
2694: }
2695:
2696: // report annotations
2697: if (field.annotations != null) {
2698: if (enclosingElement == null) {
2699: enclosingElement = createHandle(field, type, parent);
2700: }
2701: reportMatching(field.annotations, enclosingElement,
2702: field.binding, nodeSet, true, true);
2703: }
2704:
2705: if (typeInHierarchy) {
2706: // Look at field declaration
2707: if (field.endPart1Position != 0) { // not necessary if field is an initializer
2708: ASTNode[] nodes = nodeSet.matchingNodes(
2709: field.declarationSourceStart,
2710: field.endPart1Position);
2711: if (nodes != null) {
2712: if ((this .matchContainer & PatternLocator.FIELD_CONTAINER) == 0) {
2713: for (int i = 0, l = nodes.length; i < l; i++)
2714: nodeSet.matchingNodes.removeKey(nodes[i]);
2715: } else {
2716: if (enclosingElement == null)
2717: enclosingElement = createHandle(field,
2718: type, parent);
2719: if (encloses(enclosingElement)) {
2720: for (int i = 0, l = nodes.length; i < l; i++) {
2721: ASTNode node = nodes[i];
2722: Integer level = (Integer) nodeSet.matchingNodes
2723: .removeKey(node);
2724: IJavaElement[] otherElements = null;
2725: if (otherFields != null) {
2726: int length = otherFields.length;
2727: int size = 0;
2728: while (size < length
2729: && otherFields[size] != null) {
2730: size++;
2731: }
2732: otherElements = new IJavaElement[size];
2733: for (int j = 0; j < size; j++) {
2734: otherElements[j] = createHandle(
2735: otherFields[j], type,
2736: parent);
2737: }
2738: }
2739: this .patternLocator
2740: .matchReportReference(node,
2741: enclosingElement, null,
2742: otherElements,
2743: field.binding, level
2744: .intValue(),
2745: this );
2746: }
2747: }
2748: }
2749: }
2750: }
2751:
2752: // Look in initializer
2753: int fieldEnd = field.endPart2Position == 0 ? field.declarationSourceEnd
2754: : field.endPart2Position;
2755: ASTNode[] nodes = nodeSet.matchingNodes(field.sourceStart,
2756: fieldEnd);
2757: if (nodes != null) {
2758: if ((this .matchContainer & PatternLocator.FIELD_CONTAINER) == 0) {
2759: for (int i = 0, l = nodes.length; i < l; i++)
2760: nodeSet.matchingNodes.removeKey(nodes[i]);
2761: } else {
2762: if (enclosingElement == null) {
2763: enclosingElement = createHandle(field, type,
2764: parent);
2765: }
2766: if (encloses(enclosingElement)) {
2767: for (int i = 0, l = nodes.length; i < l; i++) {
2768: ASTNode node = nodes[i];
2769: Integer level = (Integer) nodeSet.matchingNodes
2770: .removeKey(node);
2771: if (node instanceof TypeDeclaration) {
2772: // use field declaration to report match (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=88174)
2773: AllocationExpression allocation = ((TypeDeclaration) node).allocation;
2774: if (allocation != null
2775: && allocation.enumConstant != null) {
2776: node = field;
2777: }
2778: }
2779: // Set block scope for initializer in case there would have other local and other elements to report
2780: BlockScope blockScope = null;
2781: if (field.getKind() == AbstractVariableDeclaration.INITIALIZER) {
2782: Block block = ((Initializer) field).block;
2783: if (block != null)
2784: blockScope = block.scope;
2785: }
2786: this .patternLocator.matchReportReference(
2787: node, enclosingElement,
2788: field.binding, blockScope, level
2789: .intValue(), this );
2790: }
2791: }
2792: }
2793: }
2794: }
2795: }
2796:
2797: /**
2798: * Visit the given type declaration and report the nodes that match exactly the
2799: * search pattern (ie. the ones in the matching nodes set)
2800: */
2801: protected void reportMatching(TypeDeclaration type,
2802: IJavaElement parent, int accuracy, MatchingNodeSet nodeSet,
2803: int occurrenceCount) throws CoreException {
2804: // create type handle
2805: IJavaElement enclosingElement = parent;
2806: if (enclosingElement == null) {
2807: enclosingElement = createTypeHandle(new String(type.name));
2808: } else if (enclosingElement instanceof IType) {
2809: enclosingElement = ((IType) parent).getType(new String(
2810: type.name));
2811: } else if (enclosingElement instanceof IMember) {
2812: IMember member = (IMember) parent;
2813: if (member.isBinary()) {
2814: enclosingElement = ((IClassFile) this .currentPossibleMatch.openable)
2815: .getType();
2816: } else {
2817: enclosingElement = member.getType(
2818: new String(type.name), occurrenceCount);
2819: }
2820: }
2821: if (enclosingElement == null)
2822: return;
2823: boolean enclosesElement = encloses(enclosingElement);
2824:
2825: // report the type declaration
2826: if (accuracy > -1 && enclosesElement) {
2827: int offset = type.sourceStart;
2828: SearchMatch match = this .patternLocator
2829: .newDeclarationMatch(type, enclosingElement,
2830: type.binding, accuracy, type.sourceEnd
2831: - offset + 1, this );
2832: report(match);
2833: }
2834:
2835: boolean matchedClassContainer = (this .matchContainer & PatternLocator.CLASS_CONTAINER) != 0;
2836:
2837: // report the type parameters
2838: if (type.typeParameters != null) {
2839: reportMatching(type.typeParameters, enclosingElement,
2840: parent, type.binding, nodeSet);
2841: }
2842:
2843: // report annotations
2844: if (type.annotations != null) {
2845: reportMatching(type.annotations, enclosingElement,
2846: type.binding, nodeSet, matchedClassContainer,
2847: enclosesElement);
2848: }
2849:
2850: // report references in javadoc
2851: if (type.javadoc != null) {
2852: ASTNode[] nodes = nodeSet.matchingNodes(
2853: type.declarationSourceStart, type.sourceStart);
2854: if (nodes != null) {
2855: if (!matchedClassContainer) {
2856: for (int i = 0, l = nodes.length; i < l; i++)
2857: nodeSet.matchingNodes.removeKey(nodes[i]);
2858: } else {
2859: for (int i = 0, l = nodes.length; i < l; i++) {
2860: ASTNode node = nodes[i];
2861: Integer level = (Integer) nodeSet.matchingNodes
2862: .removeKey(node);
2863: if (enclosesElement) {
2864: this .patternLocator.matchReportReference(
2865: node, enclosingElement,
2866: type.binding, level.intValue(),
2867: this );
2868: }
2869: }
2870: }
2871: }
2872: }
2873:
2874: // super types
2875: if ((type.bits & ASTNode.IsAnonymousType) != 0) {
2876: TypeReference super Type = type.allocation.type;
2877: if (super Type != null) {
2878: Integer level = (Integer) nodeSet.matchingNodes
2879: .removeKey(super Type);
2880: if (level != null && matchedClassContainer)
2881: this .patternLocator.matchReportReference(super Type,
2882: enclosingElement, type.binding, level
2883: .intValue(), this );
2884: }
2885: } else {
2886: TypeReference super Class = type.super class;
2887: if (super Class != null) {
2888: reportMatchingSuper(super Class, enclosingElement,
2889: type.binding, nodeSet, matchedClassContainer);
2890: }
2891: TypeReference[] super Interfaces = type.super Interfaces;
2892: if (super Interfaces != null) {
2893: for (int i = 0, l = super Interfaces.length; i < l; i++) {
2894: reportMatchingSuper(super Interfaces[i],
2895: enclosingElement, type.binding, nodeSet,
2896: matchedClassContainer);
2897: }
2898: }
2899: }
2900:
2901: // filter out element not in hierarchy scope
2902: boolean typeInHierarchy = type.binding == null
2903: || typeInHierarchy(type.binding);
2904: matchedClassContainer = matchedClassContainer
2905: && typeInHierarchy;
2906:
2907: // Visit fields
2908: FieldDeclaration[] fields = type.fields;
2909: if (fields != null) {
2910: if (nodeSet.matchingNodes.elementSize == 0)
2911: return; // end as all matching nodes were reported
2912: FieldDeclaration[] otherFields = null;
2913: int first = -1;
2914: int length = fields.length;
2915: for (int i = 0; i < length; i++) {
2916: FieldDeclaration field = fields[i];
2917: boolean last = field.endPart2Position == 0
2918: || field.declarationEnd == field.endPart2Position;
2919: // Store first index of multiple field declaration
2920: if (!last) {
2921: if (first == -1) {
2922: first = i;
2923: }
2924: }
2925: if (first >= 0) {
2926: // Store all multiple fields but first one for other elements
2927: if (i > first) {
2928: if (otherFields == null) {
2929: otherFields = new FieldDeclaration[length
2930: - i];
2931: }
2932: otherFields[i - 1 - first] = field;
2933: }
2934: // On last field, report match with all other elements
2935: if (last) {
2936: for (int j = first; j <= i; j++) {
2937: Integer level = (Integer) nodeSet.matchingNodes
2938: .removeKey(fields[j]);
2939: int value = (level != null && matchedClassContainer) ? level
2940: .intValue()
2941: : -1;
2942: reportMatching(fields[j], otherFields,
2943: type, enclosingElement, value,
2944: typeInHierarchy, nodeSet);
2945: }
2946: first = -1;
2947: otherFields = null;
2948: }
2949: } else {
2950: // Single field, report normally
2951: Integer level = (Integer) nodeSet.matchingNodes
2952: .removeKey(field);
2953: int value = (level != null && matchedClassContainer) ? level
2954: .intValue()
2955: : -1;
2956: reportMatching(field, null, type, enclosingElement,
2957: value, typeInHierarchy, nodeSet);
2958: }
2959: }
2960: }
2961:
2962: // Visit methods
2963: AbstractMethodDeclaration[] methods = type.methods;
2964: if (methods != null) {
2965: if (nodeSet.matchingNodes.elementSize == 0)
2966: return; // end as all matching nodes were reported
2967: for (int i = 0, l = methods.length; i < l; i++) {
2968: AbstractMethodDeclaration method = methods[i];
2969: Integer level = (Integer) nodeSet.matchingNodes
2970: .removeKey(method);
2971: int value = (level != null && matchedClassContainer) ? level
2972: .intValue()
2973: : -1;
2974: reportMatching(type, method, enclosingElement, value,
2975: typeInHierarchy, nodeSet);
2976: }
2977: }
2978:
2979: // Visit types
2980: TypeDeclaration[] memberTypes = type.memberTypes;
2981: if (memberTypes != null) {
2982: for (int i = 0, l = memberTypes.length; i < l; i++) {
2983: if (nodeSet.matchingNodes.elementSize == 0)
2984: return; // end as all matching nodes were reported
2985: TypeDeclaration memberType = memberTypes[i];
2986: Integer level = (Integer) nodeSet.matchingNodes
2987: .removeKey(memberType);
2988: int value = (level != null && matchedClassContainer) ? level
2989: .intValue()
2990: : -1;
2991: reportMatching(memberType, enclosingElement, value,
2992: nodeSet, 1);
2993: }
2994: }
2995: }
2996:
2997: /**
2998: * Report matches in type parameters.
2999: */
3000: protected void reportMatching(TypeParameter[] typeParameters,
3001: IJavaElement enclosingElement, IJavaElement parent,
3002: Binding binding, MatchingNodeSet nodeSet)
3003: throws CoreException {
3004: if (typeParameters == null)
3005: return;
3006: for (int i = 0, l = typeParameters.length; i < l; i++) {
3007: TypeParameter typeParameter = typeParameters[i];
3008: if (typeParameter != null) {
3009: Integer level = (Integer) nodeSet.matchingNodes
3010: .removeKey(typeParameter);
3011: if (level != null) {
3012: if (level.intValue() > -1
3013: && encloses(enclosingElement)) {
3014: int offset = typeParameter.sourceStart;
3015: SearchMatch match = this .patternLocator
3016: .newDeclarationMatch(typeParameter,
3017: enclosingElement, binding,
3018: level.intValue(),
3019: typeParameter.sourceEnd
3020: - offset + 1, this );
3021: report(match);
3022: }
3023: }
3024: if (typeParameter.type != null) {
3025: level = (Integer) nodeSet.matchingNodes
3026: .removeKey(typeParameter.type);
3027: if (level != null) {
3028: IJavaElement localElement = createHandle(
3029: typeParameter, enclosingElement);
3030: this .patternLocator.matchReportReference(
3031: typeParameter.type, enclosingElement,
3032: localElement, null, binding, level
3033: .intValue(), this );
3034: }
3035: }
3036: if (typeParameter.bounds != null) {
3037: for (int j = 0, b = typeParameter.bounds.length; j < b; j++) {
3038: level = (Integer) nodeSet.matchingNodes
3039: .removeKey(typeParameter.bounds[j]);
3040: if (level != null) {
3041: IJavaElement localElement = createHandle(
3042: typeParameter, enclosingElement);
3043: this .patternLocator.matchReportReference(
3044: typeParameter.bounds[j],
3045: enclosingElement, localElement,
3046: null, binding, level.intValue(),
3047: this );
3048: }
3049: }
3050: }
3051: }
3052: }
3053: }
3054:
3055: protected void reportMatchingSuper(TypeReference super Reference,
3056: IJavaElement enclosingElement, Binding elementBinding,
3057: MatchingNodeSet nodeSet, boolean matchedClassContainer)
3058: throws CoreException {
3059: ASTNode[] nodes = null;
3060: if (super Reference instanceof ParameterizedSingleTypeReference
3061: || super Reference instanceof ParameterizedQualifiedTypeReference) {
3062: long lastTypeArgumentInfo = findLastTypeArgumentInfo(super Reference);
3063: nodes = nodeSet.matchingNodes(super Reference.sourceStart,
3064: (int) lastTypeArgumentInfo);
3065: }
3066: if (nodes != null) {
3067: if ((this .matchContainer & PatternLocator.CLASS_CONTAINER) == 0) {
3068: for (int i = 0, l = nodes.length; i < l; i++)
3069: nodeSet.matchingNodes.removeKey(nodes[i]);
3070: } else {
3071: if (encloses(enclosingElement))
3072: for (int i = 0, l = nodes.length; i < l; i++) {
3073: ASTNode node = nodes[i];
3074: Integer level = (Integer) nodeSet.matchingNodes
3075: .removeKey(node);
3076: this .patternLocator.matchReportReference(node,
3077: enclosingElement, elementBinding, level
3078: .intValue(), this );
3079: }
3080: }
3081: } else {
3082: Integer level = (Integer) nodeSet.matchingNodes
3083: .removeKey(super Reference);
3084: if (level != null && matchedClassContainer)
3085: this .patternLocator.matchReportReference(
3086: super Reference, enclosingElement,
3087: elementBinding, level.intValue(), this );
3088: }
3089: }
3090:
3091: protected boolean typeInHierarchy(ReferenceBinding binding) {
3092: if (this .hierarchyResolver == null)
3093: return true; // not a hierarchy scope
3094: if (this .hierarchyResolver.subOrSuperOfFocus(binding))
3095: return true;
3096:
3097: if (this .allSuperTypeNames != null) {
3098: char[][] compoundName = binding.compoundName;
3099: for (int i = 0, length = this .allSuperTypeNames.length; i < length; i++)
3100: if (CharOperation.equals(compoundName,
3101: this .allSuperTypeNames[i]))
3102: return true;
3103: }
3104: return false;
3105: }
3106: }
|