blob: f800536ba514c45a89c1096804f7482c0d8b7cb6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.search;
import java.util.*;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jdt.internal.compiler.*;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.jdt.internal.compiler.env.IGenericType;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.parser.Parser;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.core.*;
import org.eclipse.jdt.internal.core.search.indexing.*;
import org.eclipse.jdt.internal.core.search.matching.*;
import org.eclipse.jdt.internal.core.util.Messages;
/**
* Search basic engine. Public search engine (see {@link org.eclipse.jdt.core.search.SearchEngine}
* for detailed comment), now uses basic engine functionalities.
* Note that serch basic engine does not implement deprecated functionalities...
*/
public class BasicSearchEngine {
/*
* A default parser to parse non-reconciled working copies
*/
private Parser parser;
private CompilerOptions compilerOptions;
/*
* A list of working copies that take precedence over their original
* compilation units.
*/
private ICompilationUnit[] workingCopies;
/*
* A working copy owner whose working copies will take precedent over
* their original compilation units.
*/
private WorkingCopyOwner workingCopyOwner;
/**
* For tracing purpose.
*/
public static boolean VERBOSE = false;
/*
* Creates a new search basic engine.
*/
public BasicSearchEngine() {
// will use working copies of PRIMARY owner
}
/**
* @see org.eclipse.jdt.core.search.SearchEngine#SearchEngine(ICompilationUnit[]) for detailed comment.
*/
public BasicSearchEngine(ICompilationUnit[] workingCopies) {
this.workingCopies = workingCopies;
}
char convertTypeKind(int typeDeclarationKind) {
switch(typeDeclarationKind) {
case IGenericType.CLASS_DECL : return IIndexConstants.CLASS_SUFFIX;
case IGenericType.INTERFACE_DECL : return IIndexConstants.INTERFACE_SUFFIX;
case IGenericType.ENUM_DECL : return IIndexConstants.ENUM_SUFFIX;
case IGenericType.ANNOTATION_TYPE_DECL : return IIndexConstants.ANNOTATION_TYPE_SUFFIX;
default : return IIndexConstants.TYPE_SUFFIX;
}
}
/**
* @see org.eclipse.jdt.core.search.SearchEngine#SearchEngine(WorkingCopyOwner) for detailed comment.
*/
public BasicSearchEngine(WorkingCopyOwner workingCopyOwner) {
this.workingCopyOwner = workingCopyOwner;
}
/**
* @see org.eclipse.jdt.core.search.SearchEngine#createHierarchyScope(IType) for detailed comment.
*/
public static IJavaSearchScope createHierarchyScope(IType type) throws JavaModelException {
return createHierarchyScope(type, DefaultWorkingCopyOwner.PRIMARY);
}
/**
* @see org.eclipse.jdt.core.search.SearchEngine#createHierarchyScope(IType,WorkingCopyOwner) for detailed comment.
*/
public static IJavaSearchScope createHierarchyScope(IType type, WorkingCopyOwner owner) throws JavaModelException {
return new HierarchyScope(type, owner);
}
/**
* @see org.eclipse.jdt.core.search.SearchEngine#createJavaSearchScope(IJavaElement[]) for detailed comment.
*/
public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements) {
return createJavaSearchScope(elements, true);
}
/**
* @see org.eclipse.jdt.core.search.SearchEngine#createJavaSearchScope(IJavaElement[], boolean) for detailed comment.
*/
public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements, boolean includeReferencedProjects) {
int includeMask = IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SYSTEM_LIBRARIES;
if (includeReferencedProjects) {
includeMask |= IJavaSearchScope.REFERENCED_PROJECTS;
}
return createJavaSearchScope(elements, includeMask);
}
/**
* @see org.eclipse.jdt.core.search.SearchEngine#createJavaSearchScope(IJavaElement[], int) for detailed comment.
*/
public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements, int includeMask) {
JavaSearchScope scope = new JavaSearchScope();
HashSet visitedProjects = new HashSet(2);
for (int i = 0, length = elements.length; i < length; i++) {
IJavaElement element = elements[i];
if (element != null) {
try {
if (element instanceof JavaProject) {
scope.add((JavaProject)element, includeMask, visitedProjects);
} else {
scope.add(element);
}
} catch (JavaModelException e) {
// ignore
}
}
}
return scope;
}
/**
* Returns a Java search scope with the workspace as the only limit.
*
* @return a new workspace scope
*/
public static IJavaSearchScope createWorkspaceScope() {
return JavaModelManager.getJavaModelManager().getWorkspaceScope();
}
/**
* Searches for matches to a given query. Search queries can be created using helper
* methods (from a String pattern or a Java element) and encapsulate the description of what is
* being searched (for example, search method declarations in a case sensitive way).
*
* @param scope the search result has to be limited to the given scope
* @param requestor a callback object to which each match is reported
*/
public void findMatches(SearchPattern pattern, SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
/* initialize progress monitor */
if (monitor != null)
monitor.beginTask(Messages.engine_searching, 100);
if (BasicSearchEngine.VERBOSE) {
System.out.println("Searching for pattern: " + pattern.toString()); //$NON-NLS-1$
System.out.println(scope); //$NON-NLS-1$
}
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
try {
requestor.beginReporting();
for (int i = 0, l = participants == null ? 0 : participants.length; i < l; i++) {
if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
SearchParticipant participant = participants[i];
SubProgressMonitor subMonitor= monitor==null ? null : new SubProgressMonitor(monitor, 1000);
if (subMonitor != null) subMonitor.beginTask("", 1000); //$NON-NLS-1$
try {
if (subMonitor != null) subMonitor.subTask(Messages.bind(Messages.engine_searching_indexing, new String[] {participant.getDescription()}));
participant.beginSearching();
requestor.enterParticipant(participant);
PathCollector pathCollector = new PathCollector();
indexManager.performConcurrentJob(
new PatternSearchJob(pattern, participant, scope, pathCollector),
IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
subMonitor);
if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
// locate index matches if any (note that all search matches could have been issued during index querying)
if (subMonitor != null) subMonitor.subTask(Messages.bind(Messages.engine_searching_matching, new String[] {participant.getDescription()}));
String[] indexMatchPaths = pathCollector.getPaths();
pathCollector = null; // release
int indexMatchLength = indexMatchPaths == null ? 0 : indexMatchPaths.length;
SearchDocument[] indexMatches = new SearchDocument[indexMatchLength];
for (int j = 0; j < indexMatchLength; j++)
indexMatches[j] = participant.getDocument(indexMatchPaths[j]);
SearchDocument[] matches = MatchLocator.addWorkingCopies(pattern, indexMatches, getWorkingCopies(), participant);
participant.locateMatches(matches, pattern, scope, requestor, subMonitor);
} finally {
requestor.exitParticipant(participant);
participant.doneSearching();
}
}
} finally {
requestor.endReporting();
if (monitor != null)
monitor.done();
}
}
/**
* Returns a new default Java search participant.
*
* @return a new default Java search participant
* @since 3.0
*/
public static SearchParticipant getDefaultSearchParticipant() {
return new JavaSearchParticipant();
}
private Parser getParser() {
if (this.parser == null) {
this.compilerOptions = new CompilerOptions(JavaCore.getOptions());
ProblemReporter problemReporter =
new ProblemReporter(
DefaultErrorHandlingPolicies.proceedWithAllProblems(),
this.compilerOptions,
new DefaultProblemFactory());
this.parser = new Parser(problemReporter, true);
}
return this.parser;
}
/**
* Returns the underlying resource of the given element.
* @param element an IJavaElement
* @return an IResource
*/
private IResource getResource(IJavaElement element) {
if (element instanceof IMember) {
ICompilationUnit cu = ((IMember)element).getCompilationUnit();
if (cu != null) {
return cu.getResource();
}
}
return element.getResource();
}
/*
* Returns the list of working copies used by this search engine.
* Returns null if none.
*/
private ICompilationUnit[] getWorkingCopies() {
ICompilationUnit[] copies;
if (this.workingCopies != null) {
if (this.workingCopyOwner == null) {
copies = JavaModelManager.getJavaModelManager().getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY, false/*don't add primary WCs a second time*/);
if (copies == null) {
copies = this.workingCopies;
} else {
HashMap pathToCUs = new HashMap();
for (int i = 0, length = copies.length; i < length; i++) {
ICompilationUnit unit = copies[i];
pathToCUs.put(unit.getPath(), unit);
}
for (int i = 0, length = this.workingCopies.length; i < length; i++) {
ICompilationUnit unit = this.workingCopies[i];
pathToCUs.put(unit.getPath(), unit);
}
int length = pathToCUs.size();
copies = new ICompilationUnit[length];
pathToCUs.values().toArray(copies);
}
} else {
copies = this.workingCopies;
}
} else if (this.workingCopyOwner != null) {
copies = JavaModelManager.getJavaModelManager().getWorkingCopies(this.workingCopyOwner, true/*add primary WCs*/);
} else {
copies = JavaModelManager.getJavaModelManager().getWorkingCopies(DefaultWorkingCopyOwner.PRIMARY, false/*don't add primary WCs a second time*/);
}
if (copies == null) return null;
// filter out primary working copies that are saved
ICompilationUnit[] result = null;
int length = copies.length;
int index = 0;
for (int i = 0; i < length; i++) {
CompilationUnit copy = (CompilationUnit)copies[i];
try {
if (!copy.isPrimary()
|| copy.hasUnsavedChanges()
|| copy.hasResourceChanged()) {
if (result == null) {
result = new ICompilationUnit[length];
}
result[index++] = copy;
}
} catch (JavaModelException e) {
// copy doesn't exist: ignore
}
}
if (index != length && result != null) {
System.arraycopy(result, 0, result = new ICompilationUnit[index], 0, index);
}
return result;
}
/**
* Returns the list of working copies used to do the search on the given Java element.
* @param element an IJavaElement
* @return an array of ICompilationUnit
*/
private ICompilationUnit[] getWorkingCopies(IJavaElement element) {
if (element instanceof IMember) {
ICompilationUnit cu = ((IMember)element).getCompilationUnit();
if (cu != null && cu.isWorkingCopy()) {
ICompilationUnit[] copies = getWorkingCopies();
int length = copies == null ? 0 : copies.length;
if (length > 0) {
ICompilationUnit[] newWorkingCopies = new ICompilationUnit[length+1];
System.arraycopy(copies, 0, newWorkingCopies, 0, length);
newWorkingCopies[length] = cu;
return newWorkingCopies;
}
return new ICompilationUnit[] {cu};
}
}
return getWorkingCopies();
}
boolean match(char patternTypeSuffix, int modifiers) {
switch(patternTypeSuffix) {
case IIndexConstants.CLASS_SUFFIX :
return (modifiers & (Flags.AccAnnotation | Flags.AccInterface | Flags.AccEnum)) == 0;
case IIndexConstants.CLASS_AND_INTERFACE_SUFFIX:
return (modifiers & (Flags.AccAnnotation | Flags.AccEnum)) == 0;
case IIndexConstants.CLASS_AND_ENUM_SUFFIX:
return (modifiers & (Flags.AccAnnotation | Flags.AccInterface)) == 0;
case IIndexConstants.INTERFACE_SUFFIX :
return (modifiers & Flags.AccInterface) != 0;
case IIndexConstants.ENUM_SUFFIX :
return (modifiers & Flags.AccEnum) != 0;
case IIndexConstants.ANNOTATION_TYPE_SUFFIX :
return (modifiers & Flags.AccAnnotation) != 0;
}
return true;
}
boolean match(char patternTypeSuffix, char[] patternPkg, char[] patternTypeName, int matchRule, int typeKind, char[] pkg, char[] typeName) {
switch(patternTypeSuffix) {
case IIndexConstants.CLASS_SUFFIX :
if (typeKind != IGenericType.CLASS_DECL) return false;
break;
case IIndexConstants.CLASS_AND_INTERFACE_SUFFIX:
if (typeKind != IGenericType.CLASS_DECL && typeKind != IGenericType.INTERFACE_DECL) return false;
break;
case IIndexConstants.CLASS_AND_ENUM_SUFFIX:
if (typeKind != IGenericType.CLASS_DECL && typeKind != IGenericType.ENUM_DECL) return false;
break;
case IIndexConstants.INTERFACE_SUFFIX :
if (typeKind != IGenericType.INTERFACE_DECL) return false;
break;
case IIndexConstants.ENUM_SUFFIX :
if (typeKind != IGenericType.ENUM_DECL) return false;
break;
case IIndexConstants.ANNOTATION_TYPE_SUFFIX :
if (typeKind != IGenericType.ANNOTATION_TYPE_DECL) return false;
break;
case IIndexConstants.TYPE_SUFFIX : // nothing
}
boolean isCaseSensitive = (matchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
if (patternPkg != null && !CharOperation.equals(patternPkg, pkg, isCaseSensitive))
return false;
if (patternTypeName != null) {
int matchMode = matchRule - (isCaseSensitive ? SearchPattern.R_CASE_SENSITIVE : 0);
if (!isCaseSensitive) {
patternTypeName = CharOperation.toLowerCase(patternTypeName);
}
switch(matchMode) {
case SearchPattern.R_EXACT_MATCH :
return CharOperation.equals(patternTypeName, typeName, isCaseSensitive);
case SearchPattern.R_PREFIX_MATCH :
return CharOperation.prefixEquals(patternTypeName, typeName, isCaseSensitive);
case SearchPattern.R_PATTERN_MATCH :
return CharOperation.match(patternTypeName, typeName, isCaseSensitive);
}
}
return true;
}
/**
* Searches for matches of a given search pattern. Search patterns can be created using helper
* methods (from a String pattern or a Java element) and encapsulate the description of what is
* being searched (for example, search method declarations in a case sensitive way).
*
* @param pattern the pattern to search
* @param participants the particpants in the search
* @param scope the search scope
* @param requestor the requestor to report the matches to
* @param monitor the progress monitor used to report progress
* @exception CoreException if the search failed. Reasons include:
* <ul>
* <li>the classpath is incorrectly set</li>
* </ul>
*@since 3.0
*/
public void search(SearchPattern pattern, SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
if (VERBOSE) {
System.out.println("BasicSearchEngine.search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor)"); //$NON-NLS-1$
}
findMatches(pattern, participants, scope, requestor, monitor);
}
/**
* Searches for all top-level types and member types in the given scope.
* The search can be selecting specific types (given a package or a type name
* prefix and match modes).
*
* @param packageName the full name of the package of the searched types, or a prefix for this
* package, or a wild-carded string for this package.
* @param typeName the dot-separated qualified name of the searched type (the qualification include
* the enclosing types if the searched type is a member type), or a prefix
* for this type, or a wild-carded string for this type.
* @param matchRule one of
* <ul>
* <li><code>SearchPattern.R_EXACT_MATCH</code> if the package name and type name are the full names
* of the searched types.</li>
* <li><code>SearchPattern.R_PREFIX_MATCH</code> if the package name and type name are prefixes of the names
* of the searched types.</li>
* <li><code>SearchPattern.R_PATTERN_MATCH</code> if the package name and type name contain wild-cards.</li>
* </ul>
* combined with <code>SearchPattern.R_CASE_SENSITIVE</code>,
* e.g. <code>R_EXACT_MATCH | R_CASE_SENSITIVE</code> if an exact and case sensitive match is requested,
* or <code>R_PREFIX_MATCH</code> if a prefix non case sensitive match is requested.
* @param searchFor determines the nature of the searched elements
* <ul>
* <li>{@link IJavaSearchConstants#CLASS}: only look for classes</li>
* <li>{@link IJavaSearchConstants#INTERFACE}: only look for interfaces</li>
* <li>{@link IJavaSearchConstants#ENUM}: only look for enumeration</li>
* <li>{@link IJavaSearchConstants#ANNOTATION_TYPE}: only look for annotation type</li>
* <li>{@link IJavaSearchConstants#CLASS_AND_ENUM}: only look for classes and enumerations</li>
* <li>{@link IJavaSearchConstants#CLASS_AND_INTERFACE}: only look for classes and interfaces</li>
* <li>{@link IJavaSearchConstants#TYPE}: look for all types (ie. classes, interfaces, enum and annotation types)</li>
* </ul>
* @param scope the scope to search in
* @param nameRequestor the requestor that collects the results of the search
* @param waitingPolicy one of
* <ul>
* <li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the search should start immediately</li>
* <li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if the search should be cancelled if the
* underlying indexer has not finished indexing the workspace</li>
* <li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the search should wait for the
* underlying indexer to finish indexing the workspace</li>
* </ul>
* @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
* monitor is provided
* @exception JavaModelException if the search failed. Reasons include:
* <ul>
* <li>the classpath is incorrectly set</li>
* </ul>
* @since 3.0
*/
public void searchAllTypeNames(
final char[] packageName,
final char[] typeName,
final int matchRule,
int searchFor,
IJavaSearchScope scope,
final IRestrictedAccessTypeRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
if (VERBOSE) {
System.out.println("BasicSearchEngine.searchAllTypeNames(char[], char[], int, int, IJavaSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
System.out.println(" - package name: "+(packageName==null?"null":new String(packageName))); //$NON-NLS-1$ //$NON-NLS-2$
System.out.println(" - type name: "+(typeName==null?"null":new String(typeName))); //$NON-NLS-1$ //$NON-NLS-2$
System.out.println(" - match rule: "+matchRule); //$NON-NLS-1$
System.out.println(" - search for: "+searchFor); //$NON-NLS-1$
System.out.println(" - scope: "+scope); //$NON-NLS-1$
}
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
final char typeSuffix;
switch(searchFor){
case IJavaSearchConstants.CLASS :
typeSuffix = IIndexConstants.CLASS_SUFFIX;
break;
case IJavaSearchConstants.CLASS_AND_INTERFACE :
typeSuffix = IIndexConstants.CLASS_AND_INTERFACE_SUFFIX;
break;
case IJavaSearchConstants.CLASS_AND_ENUM :
typeSuffix = IIndexConstants.CLASS_AND_ENUM_SUFFIX;
break;
case IJavaSearchConstants.INTERFACE :
typeSuffix = IIndexConstants.INTERFACE_SUFFIX;
break;
case IJavaSearchConstants.ENUM :
typeSuffix = IIndexConstants.ENUM_SUFFIX;
break;
case IJavaSearchConstants.ANNOTATION_TYPE :
typeSuffix = IIndexConstants.ANNOTATION_TYPE_SUFFIX;
break;
default :
typeSuffix = IIndexConstants.TYPE_SUFFIX;
break;
}
final TypeDeclarationPattern pattern = new TypeDeclarationPattern(
packageName,
null, // do find member types
typeName,
typeSuffix,
matchRule);
final HashSet workingCopyPaths = new HashSet();
ICompilationUnit[] copies = getWorkingCopies();
if (copies != null) {
for (int i = 0, length = copies.length; i < length; i++) {
ICompilationUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
TypeDeclarationPattern record = (TypeDeclarationPattern)indexRecord;
AccessRestriction accessRestriction = null;
if (record.enclosingTypeNames != IIndexConstants.ONE_ZERO_CHAR // filter out local and anonymous classes
&& !workingCopyPaths.contains(documentPath)) { // filter out working copies
if (access != null) {
// Compute document relative path
int pkgLength = (record.pkg==null || record.pkg.length==0) ? 0 : record.pkg.length+1;
int nameLength = record.simpleName==null ? 0 : record.simpleName.length;
char[] path = new char[pkgLength+nameLength];
int pos = 0;
if (pkgLength > 0) {
System.arraycopy(record.pkg, 0, path, pos, pkgLength-1);
CharOperation.replace(path, '.', '/');
path[pkgLength-1] = '/';
pos += pkgLength;
}
if (nameLength > 0) {
System.arraycopy(record.simpleName, 0, path, pos, nameLength);
pos += nameLength;
}
// Update access restriction if path is not empty
if (pos > 0) {
accessRestriction = access.getViolatedRestriction(path);
}
}
if (match(record.typeSuffix, record.modifiers)) {
nameRequestor.acceptType(record.modifiers, record.pkg, record.simpleName, record.enclosingTypeNames, documentPath, accessRestriction);
}
}
return true;
}
};
try {
if (progressMonitor != null) {
progressMonitor.beginTask(Messages.engine_searching, 100);
}
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
searchRequestor),
waitingPolicy,
progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 100));
// add type names from working copies
if (copies != null) {
for (int i = 0, length = copies.length; i < length; i++) {
ICompilationUnit workingCopy = copies[i];
final String path = workingCopy.getPath().toString();
if (workingCopy.isConsistent()) {
IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
IType[] allTypes = workingCopy.getAllTypes();
for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
IType type = allTypes[j];
IJavaElement parent = type.getParent();
char[][] enclosingTypeNames;
if (parent instanceof IType) {
char[] parentQualifiedName = ((IType)parent).getTypeQualifiedName('.').toCharArray();
enclosingTypeNames = CharOperation.splitOn('.', parentQualifiedName);
} else {
enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
}
char[] simpleName = type.getElementName().toCharArray();
int kind;
if (type.isEnum()) {
kind = IGenericType.ENUM_DECL;
} else if (type.isAnnotation()) {
kind = IGenericType.ANNOTATION_TYPE_DECL;
} else if (type.isClass()) {
kind = IGenericType.CLASS_DECL;
} else /*if (type.isInterface())*/ {
kind = IGenericType.INTERFACE_DECL;
}
if (match(typeSuffix, packageName, typeName, matchRule, kind, packageDeclaration, simpleName)) {
nameRequestor.acceptType(type.getFlags(), packageDeclaration, simpleName, enclosingTypeNames, path, null);
}
}
} else {
Parser basicParser = getParser();
final char[] contents = workingCopy.getBuffer().getCharacters();
org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
public char[] getContents() {
return contents;
}
public char[] getMainTypeName() {
return null;
}
public char[][] getPackageName() {
return null;
}
public char[] getFileName() {
return null;
}
};
CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
if (parsedUnit != null) {
final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
class AllTypeDeclarationsVisitor extends ASTVisitor {
public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
return false; // no local/anonymous type
}
public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
if (match(typeSuffix, packageName, typeName, matchRule, typeDeclaration.kind(), packageDeclaration, typeDeclaration.name)) {
nameRequestor.acceptType(typeDeclaration.modifiers, packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path, null);
}
return true;
}
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
if (match(typeSuffix, packageName, typeName, matchRule, memberTypeDeclaration.kind(), packageDeclaration, memberTypeDeclaration.name)) {
// compute encloising type names
TypeDeclaration enclosing = memberTypeDeclaration.enclosingType;
char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
while (enclosing != null) {
enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
if ((enclosing.bits & ASTNode.IsMemberTypeMASK) != 0) {
enclosing = enclosing.enclosingType;
} else {
enclosing = null;
}
}
// report
nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
}
return true;
}
}
parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
}
}
}
}
} finally {
if (progressMonitor != null) {
progressMonitor.done();
}
}
}
/**
* Searches for all top-level types and member types in the given scope using a case sensitive exact match
* with the given qualified names and type names.
*
* @param qualifications the qualified name of the package/enclosing type of the searched types
* @param typeNames the simple names of the searched types
* @param scope the scope to search in
* @param nameRequestor the requestor that collects the results of the search
* @param waitingPolicy one of
* <ul>
* <li><code>IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH</code> if the search should start immediately</li>
* <li><code>IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH</code> if the search should be cancelled if the
* underlying indexer has not finished indexing the workspace</li>
* <li><code>IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH</code> if the search should wait for the
* underlying indexer to finish indexing the workspace</li>
* </ul>
* @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
* monitor is provided
* @exception JavaModelException if the search failed. Reasons include:
* <ul>
* <li>the classpath is incorrectly set</li>
* </ul>
* @since 3.0
*/
public void searchAllTypeNames(
final char[][] qualifications,
final char[][] typeNames,
final int matchRule,
int searchFor,
IJavaSearchScope scope,
final IRestrictedAccessTypeRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
if (VERBOSE) {
System.out.println("BasicSearchEngine.searchAllTypeNames(char[][], char[][], int, int, IJavaSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
System.out.println(" - package name: "+(qualifications==null?"null":new String(CharOperation.concatWith(qualifications, ',')))); //$NON-NLS-1$ //$NON-NLS-2$
System.out.println(" - type name: "+(typeNames==null?"null":new String(CharOperation.concatWith(typeNames, ',')))); //$NON-NLS-1$ //$NON-NLS-2$
System.out.println(" - match rule: "+matchRule); //$NON-NLS-1$
System.out.println(" - search for: "+searchFor); //$NON-NLS-1$
System.out.println(" - scope: "+scope); //$NON-NLS-1$
}
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
final char typeSuffix;
switch(searchFor){
case IJavaSearchConstants.CLASS :
typeSuffix = IIndexConstants.CLASS_SUFFIX;
break;
case IJavaSearchConstants.CLASS_AND_INTERFACE :
typeSuffix = IIndexConstants.CLASS_AND_INTERFACE_SUFFIX;
break;
case IJavaSearchConstants.CLASS_AND_ENUM :
typeSuffix = IIndexConstants.CLASS_AND_ENUM_SUFFIX;
break;
case IJavaSearchConstants.INTERFACE :
typeSuffix = IIndexConstants.INTERFACE_SUFFIX;
break;
case IJavaSearchConstants.ENUM :
typeSuffix = IIndexConstants.ENUM_SUFFIX;
break;
case IJavaSearchConstants.ANNOTATION_TYPE :
typeSuffix = IIndexConstants.ANNOTATION_TYPE_SUFFIX;
break;
default :
typeSuffix = IIndexConstants.TYPE_SUFFIX;
break;
}
final MultiTypeDeclarationPattern pattern = new MultiTypeDeclarationPattern(qualifications, typeNames, typeSuffix, matchRule);
final HashSet workingCopyPaths = new HashSet();
ICompilationUnit[] copies = getWorkingCopies();
if (copies != null) {
for (int i = 0, length = copies.length; i < length; i++) {
ICompilationUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
if (!workingCopyPaths.contains(documentPath)) { // filter out working copies
QualifiedTypeDeclarationPattern record = (QualifiedTypeDeclarationPattern) indexRecord;
AccessRestriction accessRestriction = null;
if (access != null) {
// Compute document relative path
int qualificationLength = (record.qualification == null || record.qualification.length == 0) ? 0 : record.qualification.length + 1;
int nameLength = record.simpleName == null ? 0 : record.simpleName.length;
char[] path = new char[qualificationLength + nameLength];
int pos = 0;
if (qualificationLength > 0) {
System.arraycopy(record.qualification, 0, path, pos, qualificationLength - 1);
CharOperation.replace(path, '.', '/');
path[qualificationLength-1] = '/';
pos += qualificationLength;
}
if (nameLength > 0) {
System.arraycopy(record.simpleName, 0, path, pos, nameLength);
pos += nameLength;
}
// Update access restriction if path is not empty
if (pos > 0) {
accessRestriction = access.getViolatedRestriction(path);
}
}
nameRequestor.acceptType(record.modifiers, record.getPackageName(), record.simpleName, record.getEnclosingTypeNames(), documentPath, accessRestriction);
}
return true;
}
};
try {
if (progressMonitor != null) {
progressMonitor.beginTask(Messages.engine_searching, 100);
}
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
searchRequestor),
waitingPolicy,
progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 100));
// add type names from working copies
if (copies != null) {
for (int i = 0, length = copies.length; i < length; i++) {
ICompilationUnit workingCopy = copies[i];
final String path = workingCopy.getPath().toString();
if (workingCopy.isConsistent()) {
IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
IType[] allTypes = workingCopy.getAllTypes();
for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
IType type = allTypes[j];
IJavaElement parent = type.getParent();
char[][] enclosingTypeNames;
char[] qualification = packageDeclaration;
if (parent instanceof IType) {
char[] parentQualifiedName = ((IType)parent).getTypeQualifiedName('.').toCharArray();
enclosingTypeNames = CharOperation.splitOn('.', parentQualifiedName);
qualification = CharOperation.concat(qualification, parentQualifiedName);
} else {
enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
}
char[] simpleName = type.getElementName().toCharArray();
char suffix = IIndexConstants.TYPE_SUFFIX;
if (type.isClass()) {
suffix = IIndexConstants.CLASS_SUFFIX;
} else if (type.isInterface()) {
suffix = IIndexConstants.INTERFACE_SUFFIX;
} else if (type.isEnum()) {
suffix = IIndexConstants.ENUM_SUFFIX;
} else if (type.isAnnotation()) {
suffix = IIndexConstants.ANNOTATION_TYPE_SUFFIX;
}
if (pattern.matchesDecodedKey(new QualifiedTypeDeclarationPattern(qualification, simpleName, suffix, matchRule))) {
nameRequestor.acceptType(type.getFlags(), packageDeclaration, simpleName, enclosingTypeNames, path, null);
}
}
} else {
Parser basicParser = getParser();
final char[] contents = workingCopy.getBuffer().getCharacters();
org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = new org.eclipse.jdt.internal.compiler.env.ICompilationUnit() {
public char[] getContents() {
return contents;
}
public char[] getMainTypeName() {
return null;
}
public char[][] getPackageName() {
return null;
}
public char[] getFileName() {
return null;
}
};
CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
if (parsedUnit != null) {
final char[] packageDeclaration = parsedUnit.currentPackage == null
? CharOperation.NO_CHAR
: CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
class AllTypeDeclarationsVisitor extends ASTVisitor {
public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
return false; // no local/anonymous type
}
public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
SearchPattern decodedPattern =
new QualifiedTypeDeclarationPattern(packageDeclaration, typeDeclaration.name, convertTypeKind(typeDeclaration.kind()), matchRule);
if (pattern.matchesDecodedKey(decodedPattern)) {
nameRequestor.acceptType(typeDeclaration.modifiers, packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path, null);
}
return true;
}
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
// compute encloising type names
char[] qualification = packageDeclaration;
TypeDeclaration enclosing = memberTypeDeclaration.enclosingType;
char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
while (enclosing != null) {
qualification = CharOperation.concat(qualification, enclosing.name, '.');
enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
if ((enclosing.bits & ASTNode.IsMemberTypeMASK) != 0) {
enclosing = enclosing.enclosingType;
} else {
enclosing = null;
}
}
SearchPattern decodedPattern =
new QualifiedTypeDeclarationPattern(qualification, memberTypeDeclaration.name, convertTypeKind(memberTypeDeclaration.kind()), matchRule);
if (pattern.matchesDecodedKey(decodedPattern)) {
nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
}
return true;
}
}
parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
}
}
}
}
} finally {
if (progressMonitor != null) {
progressMonitor.done();
}
}
}
public void searchDeclarations(IJavaElement enclosingElement, SearchRequestor requestor, SearchPattern pattern, IProgressMonitor monitor) throws JavaModelException {
if (VERBOSE) {
System.out.println(" - java element: "+enclosingElement); //$NON-NLS-1$
}
IJavaSearchScope scope = createJavaSearchScope(new IJavaElement[] {enclosingElement});
IResource resource = this.getResource(enclosingElement);
try {
if (resource instanceof IFile) {
try {
requestor.beginReporting();
if (VERBOSE) {
System.out.println("Searching for " + pattern + " in " + resource.getFullPath()); //$NON-NLS-1$//$NON-NLS-2$
}
SearchParticipant participant = getDefaultSearchParticipant();
SearchDocument[] documents = MatchLocator.addWorkingCopies(
pattern,
new SearchDocument[] {new JavaSearchDocument(enclosingElement.getPath().toString(), participant)},
getWorkingCopies(enclosingElement),
participant);
participant.locateMatches(
documents,
pattern,
scope,
requestor,
monitor);
} finally {
requestor.endReporting();
}
} else {
search(
pattern,
new SearchParticipant[] {getDefaultSearchParticipant()},
scope,
requestor,
monitor);
}
} catch (CoreException e) {
if (e instanceof JavaModelException)
throw (JavaModelException) e;
throw new JavaModelException(e);
}
}
/**
* Searches for all declarations of the fields accessed in the given element.
* The element can be a compilation unit, a source type, or a source method.
* Reports the field declarations using the given requestor.
* <p>
* Consider the following code:
* <code>
* <pre>
* class A {
* int field1;
* }
* class B extends A {
* String value;
* }
* class X {
* void test() {
* B b = new B();
* System.out.println(b.value + b.field1);
* };
* }
* </pre>
* </code>
* then searching for declarations of accessed fields in method
* <code>X.test()</code> would collect the fields
* <code>B.value</code> and <code>A.field1</code>.
* </p>
*
* @param enclosingElement the method, type, or compilation unit to be searched in
* @param requestor a callback object to which each match is reported
* @param monitor the progress monitor used to report progress
* @exception JavaModelException if the search failed. Reasons include:
* <ul>
* <li>the element doesn't exist</li>
* <li>the classpath is incorrectly set</li>
* </ul>
* @since 3.0
*/
public void searchDeclarationsOfAccessedFields(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
if (VERBOSE) {
System.out.println("BasicSearchEngine.searchDeclarationsOfAccessedFields(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
}
SearchPattern pattern = new DeclarationOfAccessedFieldsPattern(enclosingElement);
searchDeclarations(enclosingElement, requestor, pattern, monitor);
}
/**
* Searches for all declarations of the types referenced in the given element.
* The element can be a compilation unit, a source type, or a source method.
* Reports the type declarations using the given requestor.
* <p>
* Consider the following code:
* <code>
* <pre>
* class A {
* }
* class B extends A {
* }
* interface I {
* int VALUE = 0;
* }
* class X {
* void test() {
* B b = new B();
* this.foo(b, I.VALUE);
* };
* }
* </pre>
* </code>
* then searching for declarations of referenced types in method <code>X.test()</code>
* would collect the class <code>B</code> and the interface <code>I</code>.
* </p>
*
* @param enclosingElement the method, type, or compilation unit to be searched in
* @param requestor a callback object to which each match is reported
* @param monitor the progress monitor used to report progress
* @exception JavaModelException if the search failed. Reasons include:
* <ul>
* <li>the element doesn't exist</li>
* <li>the classpath is incorrectly set</li>
* </ul>
* @since 3.0
*/
public void searchDeclarationsOfReferencedTypes(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
if (VERBOSE) {
System.out.println("BasicSearchEngine.searchDeclarationsOfReferencedTypes(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
}
SearchPattern pattern = new DeclarationOfReferencedTypesPattern(enclosingElement);
searchDeclarations(enclosingElement, requestor, pattern, monitor);
}
/**
* Searches for all declarations of the methods invoked in the given element.
* The element can be a compilation unit, a source type, or a source method.
* Reports the method declarations using the given requestor.
* <p>
* Consider the following code:
* <code>
* <pre>
* class A {
* void foo() {};
* void bar() {};
* }
* class B extends A {
* void foo() {};
* }
* class X {
* void test() {
* A a = new B();
* a.foo();
* B b = (B)a;
* b.bar();
* };
* }
* </pre>
* </code>
* then searching for declarations of sent messages in method
* <code>X.test()</code> would collect the methods
* <code>A.foo()</code>, <code>B.foo()</code>, and <code>A.bar()</code>.
* </p>
*
* @param enclosingElement the method, type, or compilation unit to be searched in
* @param requestor a callback object to which each match is reported
* @param monitor the progress monitor used to report progress
* @exception JavaModelException if the search failed. Reasons include:
* <ul>
* <li>the element doesn't exist</li>
* <li>the classpath is incorrectly set</li>
* </ul>
* @since 3.0
*/
public void searchDeclarationsOfSentMessages(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
if (VERBOSE) {
System.out.println("BasicSearchEngine.searchDeclarationsOfSentMessages(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
}
SearchPattern pattern = new DeclarationOfReferencedMethodsPattern(enclosingElement);
searchDeclarations(enclosingElement, requestor, pattern, monitor);
}
}