/******************************************************************************* * Copyright (c) 2000, 2007 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * xored software, Inc. - initial API and Implementation * xored software, Inc. - Search All occurences bugfix, * hilight only class name when class is in search results ( Alex Panchenko <alex@xored.com>) *******************************************************************************/ package org.eclipse.dltk.core.search.matching; import java.io.IOException; import java.util.HashSet; import java.util.Set; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.dltk.ast.ASTNode; import org.eclipse.dltk.ast.declarations.FieldDeclaration; import org.eclipse.dltk.ast.declarations.MethodDeclaration; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.declarations.TypeDeclaration; import org.eclipse.dltk.compiler.env.INameEnvironment; import org.eclipse.dltk.compiler.env.ISourceType; import org.eclipse.dltk.compiler.env.lookup.Scope; import org.eclipse.dltk.compiler.util.SimpleLookupTable; import org.eclipse.dltk.compiler.util.SimpleSet; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.DLTKLanguageManager; import org.eclipse.dltk.core.IDLTKLanguageToolkit; import org.eclipse.dltk.core.IField; import org.eclipse.dltk.core.IMember; import org.eclipse.dltk.core.IMethod; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IModelStatusConstants; import org.eclipse.dltk.core.IParent; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ISearchableEnvironment; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.core.search.BasicSearchEngine; import org.eclipse.dltk.core.search.FieldDeclarationMatch; import org.eclipse.dltk.core.search.FieldReferenceMatch; import org.eclipse.dltk.core.search.IDLTKSearchScope; import org.eclipse.dltk.core.search.IMatchLocatorParser; import org.eclipse.dltk.core.search.MethodDeclarationMatch; import org.eclipse.dltk.core.search.MethodReferenceMatch; import org.eclipse.dltk.core.search.SearchDocument; import org.eclipse.dltk.core.search.SearchMatch; import org.eclipse.dltk.core.search.SearchParticipant; import org.eclipse.dltk.core.search.SearchPattern; import org.eclipse.dltk.core.search.SearchRequestor; import org.eclipse.dltk.core.search.TypeDeclarationMatch; import org.eclipse.dltk.core.search.TypeReferenceMatch; import org.eclipse.dltk.core.search.index.Index; import org.eclipse.dltk.internal.compiler.env.AccessRestriction; import org.eclipse.dltk.internal.compiler.impl.ITypeRequestor; import org.eclipse.dltk.internal.compiler.lookup.LookupEnvironment; import org.eclipse.dltk.internal.compiler.lookup.SourceModuleScope; import org.eclipse.dltk.internal.core.ArchiveProjectFragment; import org.eclipse.dltk.internal.core.ModelElement; import org.eclipse.dltk.internal.core.ModelManager; import org.eclipse.dltk.internal.core.ModelStatus; import org.eclipse.dltk.internal.core.NameLookup; import org.eclipse.dltk.internal.core.Openable; import org.eclipse.dltk.internal.core.ScriptProject; import org.eclipse.dltk.internal.core.SourceModule; import org.eclipse.dltk.internal.core.SourceRefElement; import org.eclipse.dltk.internal.core.search.IndexQueryRequestor; import org.eclipse.dltk.internal.core.search.matching.AndPattern; import org.eclipse.dltk.internal.core.search.matching.InternalSearchPattern; import org.eclipse.dltk.internal.core.search.matching.MatchingNodeSet; import org.eclipse.dltk.internal.core.search.matching.OrPattern; import org.eclipse.dltk.internal.core.util.HandleFactory; import org.eclipse.dltk.internal.core.util.Util; public class MatchLocator implements IMatchLocator, ITypeRequestor { public static final int MAX_AT_ONCE; static { long maxMemory = Runtime.getRuntime().maxMemory(); int ratio = (int) Math.round(((double) maxMemory) / (64 * 0x100000)); switch (ratio) { case 0: case 1: MAX_AT_ONCE = 100; break; case 2: MAX_AT_ONCE = 200; break; case 3: MAX_AT_ONCE = 300; break; default: MAX_AT_ONCE = 400; break; } } // permanent state public SearchPattern pattern; public PatternLocator patternLocator; public int matchContainer; public SearchRequestor requestor; public IDLTKSearchScope scope; private IProgressMonitor progressMonitor; public org.eclipse.dltk.core.ISourceModule[] workingCopies; private HandleFactory handleFactory; // cache of all super type names if scope is hierarchy scope public char[][][] allSuperTypeNames; // the following is valid for the current project public IMatchLocatorParser parser; // private Parser basicParser; public INameEnvironment nameEnvironment; public NameLookup nameLookup; public LookupEnvironment lookupEnvironment; // management of PossibleMatch to be processed public int numberOfMatches; // (numberOfMatches - 1) is the last unit in // matchesToProcess public PossibleMatch[] matchesToProcess; public PossibleMatch currentPossibleMatch; /* * Time spent in the IJavaSearchResultCollector */ public long resultCollectorTime = 0; // Progress information protected int progressStep; protected int progressWorked; // Binding resolution and cache protected SourceModuleScope unitScope; protected SimpleLookupTable bindings; // Cache for handles private HashSet handles; static public class WrappedCoreException extends RuntimeException { private static final long serialVersionUID = 8354329870126121212L; // backward // compatible public CoreException coreException; public WrappedCoreException(CoreException coreException) { this.coreException = coreException; } } public static void setFocus(InternalSearchPattern pattern, IModelElement focus) { pattern.focus = focus; if (pattern instanceof OrPattern) { for (SearchPattern child : ((OrPattern) pattern).getPatterns()) { child.focus = focus; } } } public static SearchPattern createAndPattern( final SearchPattern leftPattern, final SearchPattern rightPattern) { Assert.isNotNull(leftPattern.getToolkit()); Assert.isTrue(leftPattern.getToolkit() .equals(rightPattern.getToolkit())); return new AndPattern(0/* no kind */, 0/* no rule */, leftPattern .getToolkit()) { SearchPattern current = leftPattern; public SearchPattern currentPattern() { return this.current; } public boolean hasNextQuery() { if (this.current == leftPattern) { this.current = rightPattern; return true; } return false; } public void resetQuery() { this.current = leftPattern; } }; } /** * Query a given index for matching entries. Assumes the sender has opened * the index and will close when finished. */ public static void findIndexMatches(InternalSearchPattern pattern, Index index, IndexQueryRequestor requestor, SearchParticipant participant, IDLTKSearchScope scope, IProgressMonitor monitor) throws IOException { pattern.findIndexMatches(index, requestor, participant, scope, monitor); } public static IModelElement getProjectOrArchive(IModelElement element) { while (!(element instanceof IScriptProject) && !(element instanceof ArchiveProjectFragment)) { element = element.getParent(); } return element; } public static boolean isPolymorphicSearch(InternalSearchPattern pattern) { return pattern.isPolymorphicSearch(); } public static IModelElement projectOrArchiveFocus( InternalSearchPattern pattern) { return pattern == null || pattern.focus == null ? null : getProjectOrArchive(pattern.focus); } public MatchLocator() { } public void initialize(SearchPattern pattern, IDLTKSearchScope scope) { this.pattern = pattern; this.patternLocator = PatternLocator.patternLocator(this.pattern, scope .getLanguageToolkit()); this.matchContainer = this.patternLocator.matchContainer(); this.scope = scope; } public void setRequestor(SearchRequestor requestor) { this.requestor = requestor; } public void setProgressMonitor(IProgressMonitor progressMonitor) { this.progressMonitor = progressMonitor; } /** * Add an additional compilation unit into the loop -> build compilation * unit declarations, their bindings and record their results. */ public void accept(ISourceModule sourceUnit, AccessRestriction accessRestriction) { } /** * Add additional source types */ public void accept(ISourceType[] sourceTypes, AccessRestriction accessRestriction) { } /* * / Computes the super type names of the focus type if any. */ protected char[][][] computeSuperTypeNames(IType focusType) { return null; } /** * Creates an IMethod from the given method declaration and type. */ protected IModelElement createHandle(MethodDeclaration method, IModelElement parent) { // if (!(parent instanceof IType)) return parent; if (parent instanceof IType) { IType type = (IType) parent; return createMethodHandle(type, method.getName()); } else if (parent instanceof ISourceModule) { return createMethodHandle((ISourceModule) parent, method.getName()); } return null; } /** * Creates an IMethod from the given method declaration and type. */ protected IModelElement createHandle(FieldDeclaration field, IModelElement parent) { // if (!(parent instanceof IType)) return parent; if (parent instanceof IType) { IType type = (IType) parent; return createFieldHandle(type, field.getName()); } else if (parent instanceof ISourceModule) { return createFieldHandle((ISourceModule) parent, field.getName()); } return null; } /* * Create method handle. Store occurences for create handle to retrieve * possible duplicate ones. */ protected IModelElement createMethodHandle(IType type, String methodName) { IMethod methodHandle = type.getMethod(methodName); resolveDuplicates(methodHandle); return methodHandle; } /** * Increment the {@link SourceRefElement#occurrenceCount} until the * specified handle is unique. * * @param handle */ protected void resolveDuplicates(IMember handle) { if (handle instanceof SourceRefElement) { while (this.handles.contains(handle)) { ((SourceRefElement) handle).occurrenceCount++; } this.handles.add(handle); } } protected IModelElement createTypeHandle(IType parent, String name) { final IType typeHandle = parent.getType(name); resolveDuplicates(typeHandle); return typeHandle; } /* * Create method handle. Store occurrences for create handle to retrieve * possible duplicate ones. */ protected IModelElement createMethodHandle(ISourceModule module, String methodName) { IMethod methodHandle = module.getMethod(methodName); resolveDuplicates(methodHandle); return methodHandle; } /* * Create method handle. Store occurences for create handle to retrieve * possible duplicate ones. */ protected IModelElement createFieldHandle(IType type, String methodName) { IField fieldHandle = type.getField(methodName); resolveDuplicates(fieldHandle); return fieldHandle; } /* * Create method handle. Store occurences for create handle to retrieve * possible duplicate ones. */ protected IModelElement createFieldHandle(ISourceModule module, String methodName) { IField fieldHandle = module.getField(methodName); resolveDuplicates(fieldHandle); return fieldHandle; } /** * Creates an IType from the given simple top level type name. */ protected IType createTypeHandle(String simpleTypeName) { Openable openable = this.currentPossibleMatch.openable; IType type = null; if (openable instanceof ISourceModule) type = ((ISourceModule) openable).getType(simpleTypeName); resolveDuplicates(type); return type; } /** * Creates an IType from the given simple top level type name. */ protected ISourceModule createSourceModuleHandle() { Openable openable = this.currentPossibleMatch.openable; if (openable instanceof ISourceModule) return ((ISourceModule) openable); return null; } /** * Creates an IType from the given simple top level type name. */ protected IMethod createMethodHandle(String simpleTypeName) { Openable openable = this.currentPossibleMatch.openable; IMethod method = null; if (openable instanceof ISourceModule) method = ((ISourceModule) openable).getMethod(simpleTypeName); resolveDuplicates(method); return method; } /** * Creates an IType from the given simple top level type name. */ protected IField createFieldHandle(String simpleTypeName) { Openable openable = this.currentPossibleMatch.openable; IField field; if (openable instanceof ISourceModule) { field = ((SourceModule) openable).getField(simpleTypeName); } else { field = null; } resolveDuplicates(field); return field; } protected boolean encloses(IModelElement element) { return element != null && this.scope.encloses(element); } protected void getMethodBodies(ModuleDeclaration unit, MatchingNodeSet nodeSet) { try { this.parser.setNodeSet(nodeSet); this.parser.parseBodies(unit); } finally { this.parser.setNodeSet(null); } } /** * Create a new parser for the given project, as well as a lookup * environment. * * @since 2.0 */ public void initialize(IScriptProject project, int possibleMatchSize) throws ModelException { // clean up name environment only if there are several possible match as // it is // reused // when only one possible match (bug 58581) if (this.nameEnvironment != null && possibleMatchSize != 1) this.nameEnvironment.cleanup(); ISearchableEnvironment searchableEnvironment = ((ScriptProject) project) .newSearchableNameEnvironment(this.workingCopies); // if only one possible match, a file name environment costs too much, // so use the existing searchable environment which will populate the // scriptmodel // only for this possible match and its required types. this.nameEnvironment = possibleMatchSize == 1 ? (INameEnvironment) searchableEnvironment : null;// (INameEnvironment) this.lookupEnvironment = new LookupEnvironment(this, /* problemReporter, */ this.nameEnvironment); IDLTKLanguageToolkit tk = null; tk = DLTKLanguageManager.getLanguageToolkit(project); if (tk == null) { throw new ModelException(new ModelStatus( IModelStatusConstants.INVALID_PROJECT, project, Messages.MatchLocator_languageToolkitNotFoundForProject)); } this.parser = DLTKLanguageManager.createMatchParser(tk.getNatureId(), this); // remember project's name lookup this.nameLookup = searchableEnvironment.getNameLookup(); // initialize queue of units this.numberOfMatches = 0; this.matchesToProcess = new PossibleMatch[possibleMatchSize]; } /** * @since 2.0 */ protected void locateMatches(IScriptProject scriptProject, PossibleMatch[] possibleMatches, int start, int length) throws CoreException { initialize(scriptProject, length); // create and resolve binding (equivalent to beginCompilation() in // Compiler) for (int i = start, maxUnits = start + length; i < maxUnits; i++) { PossibleMatch possibleMatch = possibleMatches[i]; try { if (!parse(possibleMatch)) continue; worked(); process(possibleMatch); if (this.numberOfMatches > 0 && this.matchesToProcess[this.numberOfMatches - 1] == possibleMatch) { // forget last possible match as it was processed this.numberOfMatches--; } } finally { possibleMatch.cleanUp(); } } } private boolean parse(PossibleMatch possibleMatch) { if (this.progressMonitor != null && this.progressMonitor.isCanceled()) throw new OperationCanceledException(); try { if (BasicSearchEngine.VERBOSE) System.out .println("Parsing " + possibleMatch.openable.toStringWithAncestors()); //$NON-NLS-1$ this.parser.setNodeSet(possibleMatch.nodeSet); ModuleDeclaration parsedUnit = this.parser.parse(possibleMatch); if (parsedUnit != null) { // if (hasAlreadyDefinedType(parsedUnit)) return false; // skip // type has it is hidden so not visible getMethodBodies(parsedUnit, possibleMatch.nodeSet); // add the possibleMatch with its parsedUnit to matchesToProcess possibleMatch.parsedUnit = parsedUnit; int size = this.matchesToProcess.length; if (this.numberOfMatches == size) System .arraycopy( this.matchesToProcess, 0, this.matchesToProcess = new PossibleMatch[size == 0 ? 1 : size * 2], 0, this.numberOfMatches); this.matchesToProcess[this.numberOfMatches++] = possibleMatch; } } finally { this.parser.setNodeSet(null); } return true; } /** * Locate the matches amongst the possible matches. * * @noreference This method is not intended to be referenced by clients. */ protected void locateMatches(IScriptProject scriptProject, PossibleMatchSet matchSet, int expected) throws CoreException { PossibleMatch[] possibleMatches = matchSet .getPossibleMatches(scriptProject.getProjectFragments()); int length = possibleMatches.length; // increase progress from duplicate matches not stored in matchSet while // adding... if (this.progressMonitor != null && expected > length) { this.progressWorked += expected - length; this.progressMonitor.worked(expected - length); } // locate matches (processed matches are limited to avoid problem while // using Interpreter default memory heap size) for (int index = 0; index < length;) { int max = Math.min(MAX_AT_ONCE, length - index); locateMatches(scriptProject, possibleMatches, index, max); index += max; } this.patternLocator.clear(); } /** * Locate the matches in the given files and report them using the search * requestor. */ public void locateMatches(SearchDocument[] searchDocuments) throws CoreException { int docsLength = searchDocuments.length; if (BasicSearchEngine.VERBOSE) { System.out.println("Locating matches in documents ["); //$NON-NLS-1$ for (int i = 0; i < docsLength; i++) System.out.println("\t" + searchDocuments[i]); //$NON-NLS-1$ System.out.println("]"); //$NON-NLS-1$ } // init infos for progress increasing int n = docsLength < 1000 ? Math.min(Math.max(docsLength / 200 + 1, 2), 4) : 5 * (docsLength / 1000); this.progressStep = docsLength < n ? 1 : docsLength / n; // step // should // not be 0 this.progressWorked = 0; // extract working copies this.workingCopies = ModuleFactory.selectWorkingCopies(searchDocuments); ModelManager manager = ModelManager.getModelManager(); this.bindings = new SimpleLookupTable(); try { // optimize access to zip files during search operation manager.cacheZipFiles(); // initialize handle factory (used as a cache of handles so as to // optimize space) if (this.handleFactory == null) this.handleFactory = new HandleFactory(); final ModuleFactory moduleFactory = new ModuleFactory( handleFactory, this.scope); if (this.progressMonitor != null) { this.progressMonitor.beginTask("", searchDocuments.length); //$NON-NLS-1$ } // initialize pattern for polymorphic search (ie. method reference // pattern) this.patternLocator.initializePolymorphicSearch(this); IScriptProject previousScriptProject = null; PossibleMatchSet matchSet = new PossibleMatchSet(); Util.sort(searchDocuments, new Util.Comparer() { public int compare(Object a, Object b) { return ((SearchDocument) a).getPath().compareTo( ((SearchDocument) b).getPath()); } }); int displayed = 0; // progress worked displayed final Set<String> previousPaths = new HashSet<String>(); for (int i = 0; i < docsLength; i++) { if (this.progressMonitor != null && this.progressMonitor.isCanceled()) { throw new OperationCanceledException(); } // skip duplicate paths SearchDocument searchDocument = searchDocuments[i]; searchDocuments[i] = null; // free current document if (!previousPaths.add(searchDocument.getPath())) { worked(); displayed++; continue; } final ISourceModule openable = moduleFactory .create(searchDocument); if (openable == null) { worked(); displayed++; continue; // match is outside buildpath } // create new parser and lookup environment if this is a new // project IScriptProject scriptProject = openable.getScriptProject(); IResource resource = openable.getResource(); if (resource == null) resource = scriptProject.getProject(); // case of a file in // an external jar if (!scriptProject.equals(previousScriptProject)) { // locate matches in previous project if (previousScriptProject != null) { try { locateMatches(previousScriptProject, matchSet, i - displayed); displayed = i; } catch (ModelException e) { // problem with buildpath in this project -> skip it DLTKCore.error("error in locateMatches", e); //$NON-NLS-1$ } matchSet.reset(); } previousScriptProject = scriptProject; } matchSet.add(new PossibleMatch(this, resource, openable, searchDocument)); } // last project if (previousScriptProject != null) { try { locateMatches(previousScriptProject, matchSet, docsLength - displayed); } catch (ModelException e) { // problem with buildpath in last project -> ignore DLTKCore.error("error in locateMatches", e); //$NON-NLS-1$ } } if (this.progressMonitor != null) this.progressMonitor.done(); } finally { if (this.nameEnvironment != null) this.nameEnvironment.cleanup(); manager.flushZipFiles(); this.bindings = null; } } private void worked() { if (this.progressMonitor != null) { this.progressWorked++; if ((this.progressWorked % this.progressStep) == 0) this.progressMonitor.worked(this.progressStep); } } public SearchMatch newDeclarationMatch(IModelElement element, int accuracy, int offset, int length) { SearchParticipant participant = getParticipant(); IResource resource = this.currentPossibleMatch.resource; return newDeclarationMatch(element, accuracy, offset, length, participant, resource); } public SearchMatch newDeclarationMatch(IModelElement element, int accuracy, int offset, int length, SearchParticipant participant, IResource resource) { switch (element.getElementType()) { case IModelElement.TYPE: return new TypeDeclarationMatch(element, accuracy, offset, length, participant, resource); case IModelElement.FIELD: return new FieldDeclarationMatch(element, accuracy, offset, length, participant, resource); case IModelElement.METHOD: return new MethodDeclarationMatch(element, accuracy, offset, length, participant, resource); default: return null; } } public SearchMatch newFieldReferenceMatch(IModelElement enclosingElement, int accuracy, int offset, int length, ASTNode reference) { SearchParticipant participant = getParticipant(); IResource resource = this.currentPossibleMatch.resource; boolean insideDocComment = false; boolean isReadAccess = false; boolean isWriteAccess = false; if (enclosingElement instanceof IParent && reference instanceof FieldDeclaration) { IParent parent = (IParent) enclosingElement; IModelElement[] children; try { FieldDeclaration decl = (FieldDeclaration) reference; children = parent.getChildren(); boolean found = false; for (int i = 0; i < children.length; i++) { if (children[i].getElementName().equals(decl.getName()) && children[i] instanceof IField) { enclosingElement = children[i]; found = true; break; } } if (!found) { return null; } } catch (ModelException e) { return null; } } return new FieldReferenceMatch(enclosingElement, reference, accuracy, offset, length, isReadAccess, isWriteAccess, insideDocComment, participant, resource); } public SearchMatch newMethodReferenceMatch(IModelElement enclosingElement, int accuracy, int offset, int length, boolean isConstructor, boolean isSynthetic, ASTNode reference) { SearchParticipant participant = getParticipant(); IResource resource = this.currentPossibleMatch.resource; return new MethodReferenceMatch(enclosingElement, accuracy, offset, length, isConstructor, isSynthetic, false, participant, resource, reference); } public TypeReferenceMatch newTypeReferenceMatch( IModelElement enclosingElement, int accuracy, int offset, int length, ASTNode reference) { SearchParticipant participant = getParticipant(); IResource resource = this.currentPossibleMatch.resource; return new TypeReferenceMatch(enclosingElement, accuracy, offset, length, false, participant, resource); } public TypeReferenceMatch newTypeReferenceMatch( IModelElement enclosingElement, int accuracy, ASTNode reference) { return newTypeReferenceMatch(enclosingElement, accuracy, reference .sourceStart(), reference.sourceEnd() - reference.sourceStart() + 1, reference); } /* * Process a compilation unit already parsed and build. */ protected void process(PossibleMatch possibleMatch) throws CoreException { this.currentPossibleMatch = possibleMatch; ModuleDeclaration unit = possibleMatch.parsedUnit; try { if (unit == null || unit.isEmpty()) { return; } reportMatching(unit); } finally { this.currentPossibleMatch = null; } } public SearchParticipant getParticipant() { return this.currentPossibleMatch.document.getParticipant(); } protected void report(SearchMatch match) throws CoreException { long start = -1; if (BasicSearchEngine.VERBOSE) { start = System.currentTimeMillis(); System.out.println("Reporting match"); //$NON-NLS-1$ System.out.println("\tResource: " + match.getResource());//$NON-NLS-1$ System.out .println("\tPositions: [offset=" + match.getOffset() + ", length=" + match.getLength() + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ try { ModelElement modelElement = (ModelElement) match.getElement(); System.out .println("\tJava element: " + modelElement.toStringWithAncestors()); //$NON-NLS-1$ if (!modelElement.exists()) System.out .println("\t\tWARNING: this element does NOT exist!"); //$NON-NLS-1$ } catch (Exception e) { // it's just for debug purposes... ignore all exceptions in this // area } if (match instanceof TypeReferenceMatch) { try { TypeReferenceMatch typeRefMatch = (TypeReferenceMatch) match; ModelElement local = (ModelElement) typeRefMatch .getLocalElement(); if (local != null) { System.out .println("\tLocal element: " + local.toStringWithAncestors()); //$NON-NLS-1$ } IModelElement[] others = typeRefMatch.getOtherElements(); if (others != null) { int length = others.length; if (length > 0) { System.out.println("\tOther elements:"); //$NON-NLS-1$ for (int i = 0; i < length; i++) { ModelElement other = (ModelElement) others[i]; System.out .println("\t\t- " + other.toStringWithAncestors()); //$NON-NLS-1$ } } } } catch (Exception e) { // it's just for debug purposes... ignore all exceptions in // this area } } System.out .println(match.getAccuracy() == SearchMatch.A_ACCURATE ? "\tAccuracy: EXACT_MATCH" //$NON-NLS-1$ : "\tAccuracy: POTENTIAL_MATCH"); //$NON-NLS-1$ System.out.print("\tRule: "); //$NON-NLS-1$ if (match.isExact()) { System.out.println("EXACT"); //$NON-NLS-1$ } else if (match.isEquivalent()) { System.out.println("EQUIVALENT"); //$NON-NLS-1$ } else if (match.isErasure()) { System.out.println("ERASURE"); //$NON-NLS-1$ } else { System.out.println("INVALID RULE"); //$NON-NLS-1$ } System.out.println("\tRaw: " + match.isRaw()); //$NON-NLS-1$ } if (this.requestor != null) { this.requestor.acceptSearchMatch(match); } if (BasicSearchEngine.VERBOSE) this.resultCollectorTime += System.currentTimeMillis() - start; } private void resolvePotentialMatches(MatchingNodeSet nodeSet) { Object[] nodes = nodeSet.possibleMatchingNodesSet.values; for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = (ASTNode) nodes[i]; if (node != null) { nodeSet.addMatch(node, PatternLocator.ACCURATE_MATCH); /** * FIXME originally it was * * <pre> * nodeSet.addMatch(node, this.patternLocator.resolveLevel(node)); * </pre> * * but resolveLevel() are not ported */ } } nodeSet.possibleMatchingNodesSet = new SimpleSet(3); if (BasicSearchEngine.VERBOSE) { int size = nodeSet.matchingNodes == null ? 0 : nodeSet.matchingNodes.elementSize; System.out.print(" - node set: accurate=" + size); //$NON-NLS-1$ size = nodeSet.possibleMatchingNodesSet == null ? 0 : nodeSet.possibleMatchingNodesSet.elementSize; System.out.println(", possible=" + size); //$NON-NLS-1$ } } /** * Visit the given resolved parse tree and report the nodes that match the * search pattern. */ protected void reportMatching(ModuleDeclaration unit) throws CoreException { MatchingNodeSet nodeSet = this.currentPossibleMatch.nodeSet; if (BasicSearchEngine.VERBOSE) { System.out.println("Report matching: "); //$NON-NLS-1$ int size = nodeSet.matchingNodes == null ? 0 : nodeSet.matchingNodes.elementSize; System.out.print(" - node set: accurate=" + size); //$NON-NLS-1$ size = nodeSet.possibleMatchingNodesSet == null ? 0 : nodeSet.possibleMatchingNodesSet.elementSize; System.out.println(", possible=" + size); //$NON-NLS-1$ } /* * move the possible matching nodes that exactly match the search * pattern to the matching nodes set */ resolvePotentialMatches(nodeSet); this.unitScope = null; if (nodeSet.matchingNodes.elementSize == 0) return; // no matching nodes were found this.handles = new HashSet(); boolean matchedUnitContainer = (this.matchContainer & PatternLocator.COMPILATION_UNIT_CONTAINER) != 0; // report references in javadoc TypeDeclaration[] types = unit.getTypes(); if (types != null) { for (int i = 0, l = types.length; i < l; i++) { if (nodeSet.matchingNodes.elementSize == 0) return; // reported all the matching nodes TypeDeclaration type = types[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(parser.processType(type)); int accuracy = (level != null && matchedUnitContainer) ? level .intValue() : -1; reportMatching(type, null, accuracy, nodeSet, 1); } } // Visit functions MethodDeclaration[] methods = unit.getFunctions(); if (methods != null) { for (int i = 0, l = methods.length; i < l; i++) { if (nodeSet.matchingNodes.elementSize == 0) return; // reported all the matching nodes MethodDeclaration method = methods[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(parser.processMethod(method)); int accuracy = (level != null && matchedUnitContainer) ? level .intValue() : -1; reportMatching(unit, method, null, accuracy, nodeSet); } } // Visit global variables FieldDeclaration[] fields = unit.getVariables(); if (fields != null) { for (int i = 0, l = fields.length; i < l; i++) { if (nodeSet.matchingNodes.elementSize == 0) return; // reported all the matching nodes FieldDeclaration method = fields[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(method); int accuracy = (level != null && matchedUnitContainer) ? level .intValue() : -1; reportMatching(unit, method, null, accuracy, nodeSet); } } // references in this module ASTNode[] nodes = nodeSet.matchingNodes(unit.sourceStart(), unit .sourceEnd()); if (nodes != null) { if ((this.matchContainer & PatternLocator.COMPILATION_UNIT_CONTAINER) != 0) { ISourceModule enclosingElement = createSourceModuleHandle(); if (encloses(enclosingElement)) { for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = nodes[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(node); if (DLTKCore.DEBUG) { System.out .println("TODO: Searching. Add scope support."); //$NON-NLS-1$ } this.patternLocator.matchReportReference(node, enclosingElement, (Scope) null, level .intValue(), this); } } } for (int i = 0, l = nodes.length; i < l; i++) nodeSet.matchingNodes.removeKey(nodes[i]); } // Clear handle cache this.handles = null; this.bindings.removeKey(this.pattern); } /** * type Visit the given type declaration and report the nodes that match * exactly the search pattern (ie. the ones in the matching nodes set) */ protected void reportMatching(TypeDeclaration type, IModelElement parent, int accuracy, MatchingNodeSet nodeSet, int occurrenceCount) throws CoreException { // create type handle IModelElement enclosingElement = parent; if (enclosingElement == null) { enclosingElement = createTypeHandle(type.getName()); } else if (enclosingElement instanceof IType) { enclosingElement = createTypeHandle((IType) parent, type.getName()); } else if (enclosingElement instanceof IMember) { IMember member = (IMember) parent; enclosingElement = member.getType(type.getName(), occurrenceCount); } if (enclosingElement == null) return; boolean enclosesElement = encloses(enclosingElement); // report the type declaration if (accuracy > -1 && enclosesElement) { SearchMatch match = this.patternLocator.newDeclarationMatch(type, enclosingElement, accuracy, this); report(match); } boolean matchedClassContainer = (this.matchContainer & PatternLocator.CLASS_CONTAINER) != 0; // filter out element not in hierarchy scope if (DLTKCore.DEBUG) { System.out .println("TODO: Searching. add variable handling here..."); //$NON-NLS-1$ } boolean typeInHierarchy = true;// type.binding == null || // Visit methods MethodDeclaration[] methods = type.getMethods(); if (methods != null) { if (nodeSet.matchingNodes.elementSize == 0) return; // end as all matching nodes were reported for (int i = 0, l = methods.length; i < l; i++) { MethodDeclaration method = methods[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(parser.processMethod(method)); int value = (level != null && matchedClassContainer) ? level .intValue() : -1; reportMatching(type, method, enclosingElement, value, true, nodeSet); } } // Visit types TypeDeclaration[] memberTypes = type.getTypes(); if (memberTypes != null) { for (int i = 0, l = memberTypes.length; i < l; i++) { if (nodeSet.matchingNodes.elementSize == 0) return; // end as all matching nodes were reported TypeDeclaration memberType = memberTypes[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(parser.processType(memberType)); int value = (level != null && matchedClassContainer) ? level .intValue() : -1; reportMatching(memberType, enclosingElement, value, nodeSet, 1); } } // Visit variables FieldDeclaration[] fields = type.getVariables(); if (fields != null) { for (int i = 0, l = fields.length; i < l; i++) { if (nodeSet.matchingNodes.elementSize == 0) return; // reported all the matching nodes FieldDeclaration field = fields[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(field); int value = (level != null && matchedClassContainer) ? level .intValue() : -1; reportMatching(type, field, enclosingElement, value, true, nodeSet); } } // references in this type if (typeInHierarchy) { ASTNode[] nodes = nodeSet.matchingNodes(type.sourceStart(), type .sourceEnd()); if (nodes != null) { if ((this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0) { if (encloses(enclosingElement)) { for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = nodes[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(node); if (DLTKCore.DEBUG) { System.out .println("TODO: Searching. Add scope support."); //$NON-NLS-1$ } this.patternLocator.matchReportReference(node, enclosingElement, (Scope) null, level .intValue(), this); } return; } } for (int i = 0, l = nodes.length; i < l; i++) nodeSet.matchingNodes.removeKey(nodes[i]); } } } /** * Visit the given method declaration and report the nodes that match * exactly the search pattern (ie. the ones in the matching nodes set) Note * that the method declaration has already been checked. */ protected void reportMatching(TypeDeclaration type, MethodDeclaration method, IModelElement parent, int accuracy, boolean typeInHierarchy, MatchingNodeSet nodeSet) throws CoreException { IModelElement enclosingElement = null; if (accuracy > -1) { enclosingElement = createHandle(method, parent); if (enclosingElement != null) { // skip if unable to find method if (encloses(enclosingElement)) { SearchMatch match = null; if (DLTKCore.DEBUG) { System.out .println("TODO: AST Add constructor support."); //$NON-NLS-1$ } match = this.patternLocator.newDeclarationMatch(method, enclosingElement, accuracy, this); // } if (match != null) { report(match); } } } } // references in this method if (typeInHierarchy) { ASTNode[] nodes = nodeSet.matchingNodes(method.sourceStart(), method.sourceEnd()); if (nodes != null) { if ((this.matchContainer & PatternLocator.CLASS_CONTAINER) != 0) { if (enclosingElement == null) enclosingElement = createHandle(method, parent); if (encloses(enclosingElement)) { for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = nodes[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(node); if (DLTKCore.DEBUG) { System.out .println("TODO: Searching. Add scope support."); //$NON-NLS-1$ } this.patternLocator.matchReportReference(node, enclosingElement, (Scope) null, level .intValue(), this); } return; } } for (int i = 0, l = nodes.length; i < l; i++) nodeSet.matchingNodes.removeKey(nodes[i]); } } } /** * Visit the given method declaration and report the nodes that match * exactly the search pattern (ie. the ones in the matching nodes set) Note * that the method declaration has already been checked. */ protected void reportMatching(TypeDeclaration type, FieldDeclaration field, IModelElement parent, int accuracy, boolean typeInHierarchy, MatchingNodeSet nodeSet) throws CoreException { IModelElement enclosingElement = null; if (accuracy > -1) { enclosingElement = createHandle(field, parent); if (enclosingElement != null) { // skip if unable to find method if (encloses(enclosingElement)) { SearchMatch match = null; if (DLTKCore.DEBUG) { System.out .println("TODO: AST Add constructor support."); //$NON-NLS-1$ } match = this.patternLocator.newDeclarationMatch(field, enclosingElement, accuracy, this); // } if (match != null) { report(match); } } } } // references in this method if (typeInHierarchy) { ASTNode[] nodes = nodeSet.matchingNodes(field.sourceStart(), field .sourceEnd()); if (nodes != null) { if ((this.matchContainer & PatternLocator.CLASS_CONTAINER) != 0) { if (enclosingElement == null) enclosingElement = createHandle(field, parent); if (encloses(enclosingElement)) { for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = nodes[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(node); if (DLTKCore.DEBUG) { System.out .println("TODO: Searching. Add scope support."); //$NON-NLS-1$ } this.patternLocator.matchReportReference(node, enclosingElement, (Scope) null, level .intValue(), this); } return; } } for (int i = 0, l = nodes.length; i < l; i++) nodeSet.matchingNodes.removeKey(nodes[i]); } } } /** * Visit the given method declaration and report the nodes that match * exactly the search pattern (ie. the ones in the matching nodes set) Note * that the method declaration has already been checked. */ protected void reportMatching(ModuleDeclaration module, FieldDeclaration field, IModelElement parent, int accuracy, MatchingNodeSet nodeSet) throws CoreException { IModelElement enclosingElement = null; if (accuracy > -1) { if (parent == null) { parent = createSourceModuleHandle(); } enclosingElement = createHandle(field, parent); if (enclosingElement == null) { enclosingElement = createFieldHandle(field.getName()); } if (enclosingElement != null) { // skip if unable to find method if (encloses(enclosingElement)) { SearchMatch match = null; if (DLTKCore.DEBUG) { System.out .println("TODO: AST Add constructor support."); //$NON-NLS-1$ } match = this.patternLocator.newDeclarationMatch(field, enclosingElement, accuracy, this); // } if (match != null) { report(match); } } } } // references in this method ASTNode[] nodes = nodeSet.matchingNodes(field.sourceStart(), field .sourceEnd()); if (nodes != null) { if (parent == null) { parent = createSourceModuleHandle(); } if ((this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0) { if (enclosingElement == null) enclosingElement = createHandle(field, parent); if (encloses(enclosingElement)) { for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = nodes[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(node); if (DLTKCore.DEBUG) { System.out .println("TODO: Searching. Add scope support."); //$NON-NLS-1$ } this.patternLocator.matchReportReference(node, enclosingElement, (Scope) null, level .intValue(), this); } return; } } for (int i = 0, l = nodes.length; i < l; i++) nodeSet.matchingNodes.removeKey(nodes[i]); } } protected void reportMatching(ModuleDeclaration module, MethodDeclaration method, IModelElement parent, int accuracy, MatchingNodeSet nodeSet) throws CoreException { IModelElement enclosingElement = null; if (accuracy > -1) { if (parent == null) { parent = createSourceModuleHandle(); } enclosingElement = createHandle(method, parent); if (enclosingElement == null) { enclosingElement = createMethodHandle(method.getName()); } if (enclosingElement != null) { // skip if unable to find method if (encloses(enclosingElement)) { SearchMatch match = null; if (DLTKCore.DEBUG) { System.out .println("TODO: AST Add constructor support."); //$NON-NLS-1$ } match = this.patternLocator.newDeclarationMatch(method, enclosingElement, accuracy, this); // } if (match != null) { report(match); } } } } // references in this method ASTNode[] nodes = nodeSet.matchingNodes(method.sourceStart(), method .sourceEnd()); if (nodes != null) { if (parent == null) { parent = createSourceModuleHandle(); } if ((this.matchContainer & PatternLocator.METHOD_CONTAINER) != 0) { if (enclosingElement == null) enclosingElement = createHandle(method, parent); if (encloses(enclosingElement)) { for (int i = 0, l = nodes.length; i < l; i++) { ASTNode node = nodes[i]; Integer level = (Integer) nodeSet.matchingNodes .removeKey(node); if (DLTKCore.DEBUG) { System.out .println("TODO: Searching. Add scope support."); //$NON-NLS-1$ } this.patternLocator.matchReportReference(node, enclosingElement, (Scope) null, level .intValue(), this); } return; } } for (int i = 0, l = nodes.length; i < l; i++) nodeSet.matchingNodes.removeKey(nodes[i]); } } protected IType findTypeFrom(IModelElement[] childs, String name, String parentName, char delimiter) { try { for (int i = 0; i < childs.length; ++i) { if (childs[i] instanceof IType) { IType type = (IType) childs[i]; String qname = name + delimiter + type.getElementName(); if (qname.equals(parentName)) { return type; } IType val = findTypeFrom(type.getChildren(), qname, parentName, delimiter); if (val != null) { return val; } } } } catch (ModelException e) { if (DLTKCore.DEBUG) { e.printStackTrace(); } } return null; } }