/*******************************************************************************
* Copyright (c) 2000, 2011 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.wst.jsdt.internal.core.search;
import java.util.HashMap;
import java.util.HashSet;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.wst.jsdt.core.IField;
import org.eclipse.wst.jsdt.core.IFunction;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptUnit;
import org.eclipse.wst.jsdt.core.IMember;
import org.eclipse.wst.jsdt.core.IPackageFragmentRoot;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.WorkingCopyOwner;
import org.eclipse.wst.jsdt.core.compiler.CharOperation;
import org.eclipse.wst.jsdt.core.infer.InferredAttribute;
import org.eclipse.wst.jsdt.core.infer.InferredMethod;
import org.eclipse.wst.jsdt.core.infer.InferredType;
import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchConstants;
import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchScope;
import org.eclipse.wst.jsdt.core.search.SearchDocument;
import org.eclipse.wst.jsdt.core.search.SearchParticipant;
import org.eclipse.wst.jsdt.core.search.SearchPattern;
import org.eclipse.wst.jsdt.core.search.SearchRequestor;
import org.eclipse.wst.jsdt.core.search.TypeNameMatch;
import org.eclipse.wst.jsdt.internal.compiler.ASTVisitor;
import org.eclipse.wst.jsdt.internal.compiler.CompilationResult;
import org.eclipse.wst.jsdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.wst.jsdt.internal.compiler.ast.ASTNode;
import org.eclipse.wst.jsdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.wst.jsdt.internal.compiler.env.AccessRestriction;
import org.eclipse.wst.jsdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.wst.jsdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.wst.jsdt.internal.compiler.lookup.Binding;
import org.eclipse.wst.jsdt.internal.compiler.lookup.BlockScope;
import org.eclipse.wst.jsdt.internal.compiler.lookup.ClassScope;
import org.eclipse.wst.jsdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.wst.jsdt.internal.compiler.lookup.Scope;
import org.eclipse.wst.jsdt.internal.compiler.parser.Parser;
import org.eclipse.wst.jsdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.wst.jsdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.wst.jsdt.internal.core.CompilationUnit;
import org.eclipse.wst.jsdt.internal.core.DefaultWorkingCopyOwner;
import org.eclipse.wst.jsdt.internal.core.JavaModelManager;
import org.eclipse.wst.jsdt.internal.core.JavaProject;
import org.eclipse.wst.jsdt.internal.core.search.indexing.IIndexConstants;
import org.eclipse.wst.jsdt.internal.core.search.indexing.IndexManager;
import org.eclipse.wst.jsdt.internal.core.search.matching.ConstructorDeclarationPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.DeclarationOfAccessedFieldsPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.DeclarationOfReferencedMethodsPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.DeclarationOfReferencedTypesPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.JavaSearchPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.LocalVariablePattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.MatchLocator;
import org.eclipse.wst.jsdt.internal.core.search.matching.MethodPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.MultiTypeDeclarationPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.OrPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.QualifiedTypeDeclarationPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.SecondaryTypeDeclarationPattern;
import org.eclipse.wst.jsdt.internal.core.search.matching.TypeDeclarationPattern;
import org.eclipse.wst.jsdt.internal.core.util.Messages;
import org.eclipse.wst.jsdt.internal.core.util.Util;
/**
* Search basic engine. Public search engine (see {@link org.eclipse.wst.jsdt.core.search.SearchEngine}
* for detailed comment), now uses basic engine functionalities.
* Note that search basic engine does not implement depreciated 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 IJavaScriptUnit[] 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.wst.jsdt.core.search.SearchEngine#SearchEngine(IJavaScriptUnit[]) for detailed comment.
*/
public BasicSearchEngine(IJavaScriptUnit[] workingCopies) {
this.workingCopies = workingCopies;
}
char convertTypeKind(int typeDeclarationKind) {
switch(typeDeclarationKind) {
case TypeDeclaration.CLASS_DECL : return IIndexConstants.CLASS_SUFFIX;
default : return IIndexConstants.TYPE_SUFFIX;
}
}
/**
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#SearchEngine(WorkingCopyOwner) for detailed comment.
*/
public BasicSearchEngine(WorkingCopyOwner workingCopyOwner) {
this.workingCopyOwner = workingCopyOwner;
}
/**
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#createHierarchyScope(IType) for detailed comment.
*/
public static IJavaScriptSearchScope createHierarchyScope(IType type) throws JavaScriptModelException {
return createHierarchyScope(type, DefaultWorkingCopyOwner.PRIMARY);
}
/**
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#createHierarchyScope(IType,WorkingCopyOwner) for detailed comment.
*/
public static IJavaScriptSearchScope createHierarchyScope(IType type, WorkingCopyOwner owner) throws JavaScriptModelException {
return new HierarchyScope(type, owner);
}
/**
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#createJavaSearchScope(IJavaScriptElement[]) for detailed comment.
*/
public static IJavaScriptSearchScope createJavaSearchScope(IJavaScriptElement[] elements) {
return createJavaSearchScope(elements, true);
}
/**
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#createJavaSearchScope(IJavaScriptElement[], boolean) for detailed comment.
*/
public static IJavaScriptSearchScope createJavaSearchScope(IJavaScriptElement[] elements, boolean includeReferencedProjects) {
int includeMask = IJavaScriptSearchScope.SOURCES | IJavaScriptSearchScope.APPLICATION_LIBRARIES | IJavaScriptSearchScope.SYSTEM_LIBRARIES;
if (includeReferencedProjects) {
includeMask |= IJavaScriptSearchScope.REFERENCED_PROJECTS;
}
return createJavaSearchScope(elements, includeMask);
}
/**
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#createJavaSearchScope(IJavaScriptElement[], int) for detailed comment.
*/
public static IJavaScriptSearchScope createJavaSearchScope(IJavaScriptElement[] elements, int includeMask) {
JavaSearchScope scope = new JavaSearchScope();
HashSet visitedProjects = new HashSet(2);
for (int i = 0, length = elements.length; i < length; i++) {
IJavaScriptElement element = elements[i];
if (element != null) {
try {
if (element instanceof JavaProject) {
scope.add((JavaProject)element, includeMask, visitedProjects);
} else {
scope.add(element);
}
} catch (JavaScriptModelException e) {
// ignore
}
}
}
return scope;
}
/**
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#createTypeNameMatch(IType, int) for detailed comment.
*/
public static TypeNameMatch createTypeNameMatch(IType type, int modifiers) {
return new JavaSearchTypeNameMatch(type, modifiers);
}
/**
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#createWorkspaceScope() for detailed comment.
*/
public static IJavaScriptSearchScope 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
*/
void findMatches(SearchPattern pattern, SearchParticipant[] participants, IJavaScriptSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
try {
if (VERBOSE) {
Util.verbose("Searching for pattern: " + pattern.toString()); //$NON-NLS-1$
Util.verbose(scope.toString());
}
if (participants == null) {
if (VERBOSE) Util.verbose("No participants => do nothing!"); //$NON-NLS-1$
return;
}
/* initialize progress monitor */
int length = participants.length;
if (monitor != null)
monitor.beginTask(Messages.engine_searching, 100 * length);
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
requestor.beginReporting();
for (int i = 0; i < length; i++) {
if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
SearchParticipant participant = participants[i];
try {
if (monitor != null) monitor.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),
IJavaScriptSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
monitor==null ? null : new SubProgressMonitor(monitor, 50));
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 (monitor != null) monitor.subTask(Messages.bind(Messages.engine_searching_matching, new String[] {participant.getDescription()}));
String[] indexMatchPaths = pathCollector.getPaths();
if (indexMatchPaths != null) {
pathCollector = null; // release
int indexMatchLength = 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, monitor==null ? null : new SubProgressMonitor(monitor, 50));
}
} 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();
}
/**
* @param matchRule
*/
public static String getMatchRuleString(final int matchRule) {
if (matchRule == 0) {
return "R_EXACT_MATCH"; //$NON-NLS-1$
}
StringBuffer buffer = new StringBuffer();
for (int i=1; i<=8; i++) {
int bit = matchRule & (1<<(i-1));
if (bit != 0 && buffer.length()>0) buffer.append(" | "); //$NON-NLS-1$
switch (bit) {
case SearchPattern.R_PREFIX_MATCH:
buffer.append("R_PREFIX_MATCH"); //$NON-NLS-1$
break;
case SearchPattern.R_CASE_SENSITIVE:
buffer.append("R_CASE_SENSITIVE"); //$NON-NLS-1$
break;
case SearchPattern.R_EQUIVALENT_MATCH:
buffer.append("R_EQUIVALENT_MATCH"); //$NON-NLS-1$
break;
case SearchPattern.R_ERASURE_MATCH:
buffer.append("R_ERASURE_MATCH"); //$NON-NLS-1$
break;
case SearchPattern.R_FULL_MATCH:
buffer.append("R_FULL_MATCH"); //$NON-NLS-1$
break;
case SearchPattern.R_PATTERN_MATCH:
buffer.append("R_PATTERN_MATCH"); //$NON-NLS-1$
break;
case SearchPattern.R_REGEXP_MATCH:
buffer.append("R_REGEXP_MATCH"); //$NON-NLS-1$
break;
case SearchPattern.R_CAMELCASE_MATCH:
buffer.append("R_CAMELCASE_MATCH"); //$NON-NLS-1$
break;
}
}
return buffer.toString();
}
/**
* Return kind of search corresponding to given value.
*
* @param searchFor
*/
public static String getSearchForString(final int searchFor) {
switch (searchFor) {
case IJavaScriptSearchConstants.TYPE:
return ("TYPE"); //$NON-NLS-1$
case IJavaScriptSearchConstants.METHOD:
return ("METHOD"); //$NON-NLS-1$
case IJavaScriptSearchConstants.PACKAGE:
return ("PACKAGE"); //$NON-NLS-1$
case IJavaScriptSearchConstants.CONSTRUCTOR:
return ("CONSTRUCTOR"); //$NON-NLS-1$
case IJavaScriptSearchConstants.FIELD:
return ("FIELD"); //$NON-NLS-1$
case IJavaScriptSearchConstants.CLASS:
return ("CLASS"); //$NON-NLS-1$
case IJavaScriptSearchConstants.VAR:
return ("VAR"); //$NON-NLS-1$
case IJavaScriptSearchConstants.FUNCTION:
return ("FUNCTION"); //$NON-NLS-1$
}
return "UNKNOWN"; //$NON-NLS-1$
}
private Parser getParser() {
if (this.parser == null) {
this.compilerOptions = new CompilerOptions(JavaScriptCore.getOptions());
ProblemReporter problemReporter =
new ProblemReporter(
DefaultErrorHandlingPolicies.proceedWithAllProblems(),
this.compilerOptions,
new DefaultProblemFactory());
this.parser = new Parser(problemReporter, true);
}
return this.parser;
}
/*
* Returns the list of working copies used by this search engine.
* Returns null if none.
*/
private IJavaScriptUnit[] getWorkingCopies() {
IJavaScriptUnit[] 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++) {
IJavaScriptUnit unit = copies[i];
pathToCUs.put(unit.getPath(), unit);
}
for (int i = 0, length = this.workingCopies.length; i < length; i++) {
IJavaScriptUnit unit = this.workingCopies[i];
pathToCUs.put(unit.getPath(), unit);
}
int length = pathToCUs.size();
copies = new IJavaScriptUnit[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
IJavaScriptUnit[] 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 IJavaScriptUnit[length];
}
result[index++] = copy;
}
} catch (JavaScriptModelException e) {
// copy doesn't exist: ignore
}
}
if (index != length && result != null) {
System.arraycopy(result, 0, result = new IJavaScriptUnit[index], 0, index);
}
return result;
}
/*
* Returns the list of working copies used to do the search on the given Java element.
*/
private IJavaScriptUnit[] getWorkingCopies(IJavaScriptElement element) {
if (element instanceof IMember) {
IJavaScriptUnit cu = ((IMember)element).getJavaScriptUnit();
if (cu != null && cu.isWorkingCopy()) {
IJavaScriptUnit[] copies = getWorkingCopies();
int length = copies == null ? 0 : copies.length;
if (length > 0) {
IJavaScriptUnit[] newWorkingCopies = new IJavaScriptUnit[length+1];
System.arraycopy(copies, 0, newWorkingCopies, 0, length);
newWorkingCopies[length] = cu;
return newWorkingCopies;
}
return new IJavaScriptUnit[] {cu};
}
}
return getWorkingCopies();
}
boolean match(char patternTypeSuffix, int modifiers) {
switch(patternTypeSuffix) {
case IIndexConstants.CLASS_SUFFIX :
return modifiers == 0;
}
return true;
}
boolean match(char patternTypeSuffix, char[] patternPkg, char[] patternTypeName, int matchRule, int typeKind, char[] pkg, char[] typeName) {
if (typeName==null)
typeName=CharOperation.NO_CHAR;
switch(patternTypeSuffix) {
case IIndexConstants.CLASS_SUFFIX :
if (typeKind != TypeDeclaration.CLASS_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) {
boolean isCamelCase = (matchRule & SearchPattern.R_CAMELCASE_MATCH) != 0;
int matchMode = matchRule & JavaSearchPattern.MATCH_MODE_MASK;
if (!isCaseSensitive && !isCamelCase) {
patternTypeName = CharOperation.toLowerCase(patternTypeName);
}
boolean matchFirstChar = !isCaseSensitive || patternTypeName[0] == typeName[0];
if (isCamelCase && matchFirstChar && CharOperation.camelCaseMatch(patternTypeName, typeName)) {
return true;
}
switch(matchMode) {
case SearchPattern.R_EXACT_MATCH :
if (!isCamelCase) {
return matchFirstChar && CharOperation.equals(patternTypeName, typeName, isCaseSensitive);
}
// fall through next case to match as prefix if camel case failed
case SearchPattern.R_PREFIX_MATCH :
return matchFirstChar && CharOperation.prefixEquals(patternTypeName, typeName, isCaseSensitive);
case SearchPattern.R_PATTERN_MATCH :
return CharOperation.match(patternTypeName, typeName, isCaseSensitive);
case SearchPattern.R_REGEXP_MATCH :
// TODO (frederic) implement regular expression match
break;
}
}
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).
*
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#search(SearchPattern, SearchParticipant[], IJavaScriptSearchScope, SearchRequestor, IProgressMonitor)
* for detailed comment
*/
public void search(SearchPattern pattern, SearchParticipant[] participants, IJavaScriptSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
if (VERBOSE) {
Util.verbose("BasicSearchEngine.search(SearchPattern, SearchParticipant[], IJavaScriptSearchScope, SearchRequestor, IProgressMonitor)"); //$NON-NLS-1$
}
findMatches(pattern, participants, scope, requestor, monitor);
}
public void searchAllBindingNames(
final char[] packageName,
final char[] bindingName,
final int bindingType,
final int matchRule,
IJavaScriptSearchScope scope,
final IRestrictedAccessBindingRequestor nameRequestor,
int waitingPolicy,
boolean doParse,
IProgressMonitor progressMonitor) throws JavaScriptModelException {
if (VERBOSE) {
Util.verbose("BasicSearchEngine.searchAllBindingNames(char[], char[], int, int, IJavaScriptSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
Util.verbose(" - package name: "+(packageName==null?"null":new String(packageName))); //$NON-NLS-1$ //$NON-NLS-2$
Util.verbose(" - type name: "+(bindingName==null?"null":new String(bindingName))); //$NON-NLS-1$ //$NON-NLS-2$
Util.verbose(" - match rule: "+getMatchRuleString(matchRule)); //$NON-NLS-1$
Util.verbose(" - bindingType for: "+bindingType); //$NON-NLS-1$
Util.verbose(" - scope: "+scope); //$NON-NLS-1$
}
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
SearchPattern searchPattern=null;
char suffix=0;
switch(bindingType){
case Binding.TYPE :
{
suffix = IIndexConstants.CLASS_SUFFIX;
searchPattern = new TypeDeclarationPattern(
packageName,
null, // do find member types
bindingName,
suffix,
matchRule);
break;
}
case Binding.VARIABLE :
case Binding.LOCAL :
case Binding.FIELD :
{
searchPattern = new LocalVariablePattern(true, false, false,bindingName, matchRule);
}
break;
case Binding.METHOD:
{
searchPattern = new MethodPattern(
true,false,true,
bindingName,
null,null,null,null,
null,null,null,
matchRule);
}
break;
default: // some combination
{
if ((bindingType & Binding.METHOD) >0)
{
searchPattern = new MethodPattern(
true,false,true,
bindingName,
null,null,null,null,
null,null,null,
matchRule);
}
if ((bindingType & (Binding.VARIABLE |Binding.LOCAL |Binding.FIELD )) >0)
{
LocalVariablePattern localVariablePattern = new LocalVariablePattern(true, false, false,bindingName, matchRule);
if (searchPattern==null)
searchPattern=localVariablePattern;
else
searchPattern=new OrPattern(searchPattern,localVariablePattern);
}
if ((bindingType & Binding.TYPE) >0)
{
suffix = IIndexConstants.CLASS_SUFFIX;
TypeDeclarationPattern typeDeclarationPattern = new TypeDeclarationPattern(
packageName,
null, // do find member types
bindingName,
suffix,
matchRule);
if (searchPattern==null)
searchPattern=typeDeclarationPattern;
else
searchPattern=new OrPattern(searchPattern,typeDeclarationPattern);
}
}
}
final SearchPattern pattern =searchPattern;
final char typeSuffix=suffix;
// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
final HashSet workingCopyPaths = new HashSet();
String workingCopyPath = null;
IJavaScriptUnit[] copies = getWorkingCopies();
final int copiesLength = copies == null ? 0 : copies.length;
if (copies != null) {
if (copiesLength == 1) {
workingCopyPath = copies[0].getPath().toString();
} else {
for (int i = 0; i < copiesLength; i++) {
IJavaScriptUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
// Filter unexpected types
JavaSearchPattern record = (JavaSearchPattern)indexRecord;
// Accept document path
AccessRestriction accessRestriction = null;
int modifiers=ClassFileConstants.AccPublic;
char[] packageName=null;
char[] simpleBindingName=null;
if (record instanceof MethodPattern) {
MethodPattern methodPattern = (MethodPattern) record;
simpleBindingName=methodPattern.selector;
Path path = new Path(documentPath);
String string = path.lastSegment();
if (path.hasTrailingSeparator()) // is library
{
packageName=string.toCharArray();
}
}
else if (record instanceof LocalVariablePattern)
{
LocalVariablePattern localVariablePattern = (LocalVariablePattern) record;
simpleBindingName=localVariablePattern.name;
Path path = new Path(documentPath);
String string = path.lastSegment();
if (path.hasTrailingSeparator()) // is library
{
packageName=string.toCharArray();
}
}else if (record instanceof TypeDeclarationPattern) {
TypeDeclarationPattern typeDecPattern = (TypeDeclarationPattern)record;
simpleBindingName=typeDecPattern.simpleName;
Path path = new Path(documentPath);
String string = path.lastSegment();
if (path.hasTrailingSeparator()) // is library
{
packageName=string.toCharArray();
}
}
nameRequestor.acceptBinding( bindingType,modifiers, packageName, simpleBindingName, 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 && doParse) {
for (int i = 0; i < copiesLength; i++) {
IJavaScriptUnit workingCopy = copies[i];
if (!scope.encloses(workingCopy)) continue;
final String path = workingCopy.getPath().toString();
if (workingCopy.isConsistent()) {
char[] packageDeclaration = CharOperation.NO_CHAR;
switch (bindingType)
{
case Binding.TYPE:
{
IType[] allTypes = workingCopy.getAllTypes();
for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
IType type = allTypes[j];
IJavaScriptElement 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 = TypeDeclaration.CLASS_DECL;
if (match(typeSuffix, packageName, bindingName, matchRule, kind, packageDeclaration, simpleName)) {
nameRequestor.acceptBinding(bindingType,type.getFlags(), packageDeclaration, simpleName, path, null);
}
}
}
case Binding.METHOD:
{
IFunction[] allMethods = workingCopy.getFunctions();
for (int j = 0, allMethodsLength = allMethods.length; j < allMethodsLength; j++) {
IFunction method = allMethods[j];
IJavaScriptElement parent = method.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 = method.getElementName().toCharArray();
// int kind;
if (match(typeSuffix, packageName, bindingName, matchRule, 0, packageDeclaration, simpleName)) {
nameRequestor.acceptBinding(bindingType,method.getFlags(), packageDeclaration, simpleName, path, null);
}
}
}
break;
case Binding.VARIABLE :
case Binding.LOCAL :
case Binding.FIELD :
{
IField[] allFields = workingCopy.getFields ();
for (int j = 0, allFieldsLength = allFields.length; j < allFieldsLength; j++) {
IField field = allFields[j];
IJavaScriptElement parent = field.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 = field.getElementName().toCharArray();
int kind;
if (match(typeSuffix, packageName, bindingName, matchRule, 0, packageDeclaration, simpleName)) {
nameRequestor.acceptBinding(bindingType,field.getFlags(), packageDeclaration, simpleName, path, null);
}
}
}
break;
}
} else {
Parser basicParser = getParser();
org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit) workingCopy;
CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
if (parsedUnit != null) {
basicParser.inferTypes(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, Scope blockScope) {
// return false; // no local/anonymous type
// }
public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
if (bindingType==Binding.TYPE &&
match(typeSuffix, packageName, bindingName, matchRule, TypeDeclaration.kind(typeDeclaration.modifiers), packageDeclaration, typeDeclaration.name)) {
nameRequestor.acceptBinding(bindingType,typeDeclaration.modifiers, packageDeclaration, typeDeclaration.name, path, null);
}
return true;
}
public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) {
if ((scope instanceof CompilationUnitScope) && (bindingType==Binding.LOCAL || bindingType==Binding.FIELD || bindingType==Binding.VARIABLE )&&
match(typeSuffix, packageName, bindingName, matchRule,0, packageDeclaration, localDeclaration.name)) {
nameRequestor.acceptBinding(bindingType,localDeclaration.modifiers, packageDeclaration, localDeclaration.name, path, null);
}
return true;
}
public boolean visit(MethodDeclaration methodDeclaration, Scope scope) {
if (bindingType==Binding.METHOD && methodDeclaration.selector!=null &&
match(typeSuffix, packageName, bindingName, matchRule,0, packageDeclaration, methodDeclaration.selector)) {
nameRequestor.acceptBinding(bindingType,methodDeclaration.modifiers, packageDeclaration, methodDeclaration.selector, path, null);
}
return true;
}
// public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
// if (match(typeSuffix, packageName, bindingName, matchRule, TypeDeclaration.kind(memberTypeDeclaration.modifiers), 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.IsMemberType) != 0) {
// enclosing = enclosing.enclosingType;
// } else {
// enclosing = null;
// }
// }
// // report
// nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
// }
// return true;
// }
public boolean visit(InferredType inferredType, BlockScope scope) {
if (bindingType==Binding.TYPE &&
match(typeSuffix, packageName, bindingName, matchRule, TypeDeclaration.kind(0), packageDeclaration, inferredType.getName())) {
nameRequestor.acceptBinding(bindingType,0, packageDeclaration, inferredType.getName(), path, null);
}
return true;
}
public boolean visit(InferredAttribute inferredField, BlockScope scope) {
if ((scope instanceof CompilationUnitScope) && (bindingType==Binding.LOCAL || bindingType==Binding.FIELD || bindingType==Binding.VARIABLE )&&
match(typeSuffix, packageName, bindingName, matchRule,0, packageDeclaration, inferredField.name)) {
nameRequestor.acceptBinding(bindingType,inferredField.modifiers, packageDeclaration, inferredField.name, path, null);
}
return true;
}
public boolean visit(InferredMethod inferredMethod, BlockScope scope) {
if (bindingType==Binding.METHOD && inferredMethod.name!=null &&
match(typeSuffix, packageName, bindingName, matchRule,0, packageDeclaration, inferredMethod.name)) {
nameRequestor.acceptBinding(bindingType,((MethodDeclaration)inferredMethod.getFunctionDeclaration()).modifiers, packageDeclaration, inferredMethod.name, path, null);
}
return true;
}
}
parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
}
}
}
}
} finally {
if (progressMonitor != null) {
progressMonitor.done();
}
}
}
/**
* Searches for all secondary types in the given scope.
* The search can be selecting specific types (given a package or a type name
* prefix and match modes).
*/
public void searchAllSecondaryTypeNames(
IPackageFragmentRoot[] sourceFolders,
final IRestrictedAccessTypeRequestor nameRequestor,
boolean waitForIndexes,
IProgressMonitor progressMonitor) throws JavaScriptModelException {
if (VERBOSE) {
Util.verbose("BasicSearchEngine.searchAllSecondaryTypeNames(IPackageFragmentRoot[], IRestrictedAccessTypeRequestor, boolean, IProgressMonitor)"); //$NON-NLS-1$
StringBuffer buffer = new StringBuffer(" - source folders: "); //$NON-NLS-1$
int length = sourceFolders.length;
for (int i=0; i<length; i++) {
if (i==0) {
buffer.append('[');
} else {
buffer.append(',');
}
buffer.append(sourceFolders[i].getElementName());
}
buffer.append("]\n - waitForIndexes: "); //$NON-NLS-1$
buffer.append(waitForIndexes);
Util.verbose(buffer.toString());
}
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
final TypeDeclarationPattern pattern = new SecondaryTypeDeclarationPattern();
// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
final HashSet workingCopyPaths = new HashSet();
String workingCopyPath = null;
IJavaScriptUnit[] copies = getWorkingCopies();
final int copiesLength = copies == null ? 0 : copies.length;
if (copies != null) {
if (copiesLength == 1) {
workingCopyPath = copies[0].getPath().toString();
} else {
for (int i = 0; i < copiesLength; i++) {
IJavaScriptUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
// Filter unexpected types
TypeDeclarationPattern record = (TypeDeclarationPattern)indexRecord;
if (!record.secondary) {
return true; // filter maint types
}
if (record.enclosingTypeNames == IIndexConstants.ONE_ZERO_CHAR) {
return true; // filter out local and anonymous classes
}
switch (copiesLength) {
case 0:
break;
case 1:
if (singleWkcpPath.equals(documentPath)) {
return true; // fliter out *the* working copy
}
break;
default:
if (workingCopyPaths.contains(documentPath)) {
return true; // filter out working copies
}
break;
}
// Accept document path
AccessRestriction accessRestriction = null;
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);
}
}
nameRequestor.acceptType(record.modifiers, record.pkg, record.simpleName, record.enclosingTypeNames, documentPath, accessRestriction);
return true;
}
};
// add type names from indexes
try {
if (progressMonitor != null) {
progressMonitor.beginTask(Messages.engine_searching, 100);
}
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
createJavaSearchScope(sourceFolders),
searchRequestor),
waitForIndexes
? IJavaScriptSearchConstants.WAIT_UNTIL_READY_TO_SEARCH
: IJavaScriptSearchConstants.FORCE_IMMEDIATE_SEARCH,
progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 100));
} catch (OperationCanceledException oce) {
// do nothing
} finally {
if (progressMonitor != null) {
progressMonitor.done();
}
}
}
/**
* 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).
*
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#searchAllTypeNames(char[], int, char[], int, int, IJavaScriptSearchScope, org.eclipse.wst.jsdt.core.search.TypeNameRequestor, int, IProgressMonitor)
* for detailed comment
*/
public void searchAllTypeNames(
final char[] packageName,
final int packageMatchRule,
final char[] typeName,
final int typeMatchRule,
int searchFor,
IJavaScriptSearchScope scope,
final IRestrictedAccessTypeRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaScriptModelException {
if (VERBOSE) {
Util.verbose("BasicSearchEngine.searchAllTypeNames(char[], char[], int, int, IJavaScriptSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
Util.verbose(" - package name: "+(packageName==null?"null":new String(packageName))); //$NON-NLS-1$ //$NON-NLS-2$
Util.verbose(" - match rule: "+getMatchRuleString(packageMatchRule)); //$NON-NLS-1$
Util.verbose(" - type name: "+(typeName==null?"null":new String(typeName))); //$NON-NLS-1$ //$NON-NLS-2$
Util.verbose(" - match rule: "+getMatchRuleString(typeMatchRule)); //$NON-NLS-1$
Util.verbose(" - search for: "+searchFor); //$NON-NLS-1$
Util.verbose(" - scope: "+scope); //$NON-NLS-1$
}
// Create pattern
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
final char typeSuffix;
switch(searchFor){
case IJavaScriptSearchConstants.CLASS :
typeSuffix = IIndexConstants.CLASS_SUFFIX;
break;
default :
typeSuffix = IIndexConstants.TYPE_SUFFIX;
break;
}
final TypeDeclarationPattern pattern = packageMatchRule == SearchPattern.R_EXACT_MATCH
? new TypeDeclarationPattern(
packageName,
null,
typeName,
typeSuffix,
typeMatchRule)
: new QualifiedTypeDeclarationPattern(
packageName,
packageMatchRule,
typeName,
typeSuffix,
typeMatchRule);
// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
final HashSet workingCopyPaths = new HashSet();
String workingCopyPath = null;
IJavaScriptUnit[] copies = getWorkingCopies();
final int copiesLength = copies == null ? 0 : copies.length;
if (copies != null) {
if (copiesLength == 1) {
workingCopyPath = copies[0].getPath().toString();
} else {
for (int i = 0; i < copiesLength; i++) {
IJavaScriptUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
// Filter unexpected types
TypeDeclarationPattern record = (TypeDeclarationPattern)indexRecord;
if (record.enclosingTypeNames == IIndexConstants.ONE_ZERO_CHAR) {
return true; // filter out local and anonymous classes
}
switch (copiesLength) {
case 0:
break;
case 1:
if (singleWkcpPath.equals(documentPath)) {
return true; // fliter out *the* working copy
}
break;
default:
if (workingCopyPaths.contains(documentPath)) {
return true; // filter out working copies
}
break;
}
// Accept document path
AccessRestriction accessRestriction = null;
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; i < copiesLength; i++) {
final IJavaScriptUnit workingCopy = copies[i];
if (!scope.encloses(workingCopy)) continue;
final String path = workingCopy.getPath().toString();
if (workingCopy.isConsistent()) {
char[] packageDeclaration = CharOperation.NO_CHAR;
IType[] allTypes = workingCopy.getAllTypes();
for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
IType type = allTypes[j];
IJavaScriptElement 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 = TypeDeclaration.CLASS_DECL;
if (match(typeSuffix, packageName, typeName, typeMatchRule, kind, packageDeclaration, simpleName)) {
if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, type.getFlags()));
} else {
nameRequestor.acceptType(type.getFlags(), packageDeclaration, simpleName, enclosingTypeNames, path, null);
}
}
}
} else {
Parser basicParser = getParser();
org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit) workingCopy;
CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
if (parsedUnit != null) {
basicParser.inferTypes(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, typeMatchRule, TypeDeclaration.kind(typeDeclaration.modifiers), packageDeclaration, typeDeclaration.name)) {
if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
IType type = workingCopy.getType(new String(typeName));
((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, typeDeclaration.modifiers));
} else {
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, typeMatchRule, TypeDeclaration.kind(memberTypeDeclaration.modifiers), 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.IsMemberType) != 0) {
enclosing = enclosing.enclosingType;
} else {
enclosing = null;
}
}
// report
if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
IType type = workingCopy.getType(new String(enclosingTypeNames[0]));
for (int j=1, l=enclosingTypeNames.length; j<l; j++) {
type = type.getType(new String(enclosingTypeNames[j]));
}
((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, 0));
} else {
nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
}
}
return true;
}
public boolean visit(InferredType inferredType, BlockScope scope) {
if (match(typeSuffix, packageName, typeName, typeMatchRule, TypeDeclaration.kind(0), packageDeclaration, inferredType.getName())) {
if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
IType type = workingCopy.getType(new String(typeName));
((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, 0));
} else {
nameRequestor.acceptType(0, packageDeclaration, inferredType.getName(), CharOperation.NO_CHAR_CHAR, 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.
*
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#searchAllTypeNames(char[][], char[][], IJavaScriptSearchScope, org.eclipse.wst.jsdt.core.search.TypeNameRequestor, int, IProgressMonitor)
* for detailed comment
*/
public void searchAllTypeNames(
final char[][] qualifications,
final char[][] typeNames,
final int matchRule,
int searchFor,
IJavaScriptSearchScope scope,
final IRestrictedAccessTypeRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaScriptModelException {
if (VERBOSE) {
Util.verbose("BasicSearchEngine.searchAllTypeNames(char[][], char[][], int, int, IJavaScriptSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
Util.verbose(" - package name: "+(qualifications==null?"null":new String(CharOperation.concatWith(qualifications, ',')))); //$NON-NLS-1$ //$NON-NLS-2$
Util.verbose(" - type name: "+(typeNames==null?"null":new String(CharOperation.concatWith(typeNames, ',')))); //$NON-NLS-1$ //$NON-NLS-2$
Util.verbose(" - match rule: "+matchRule); //$NON-NLS-1$
Util.verbose(" - search for: "+searchFor); //$NON-NLS-1$
Util.verbose(" - scope: "+scope); //$NON-NLS-1$
}
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
final char typeSuffix;
switch(searchFor){
case IJavaScriptSearchConstants.CLASS :
typeSuffix = IIndexConstants.CLASS_SUFFIX;
break;
default :
typeSuffix = IIndexConstants.TYPE_SUFFIX;
break;
}
final MultiTypeDeclarationPattern pattern = new MultiTypeDeclarationPattern(qualifications, typeNames, typeSuffix, matchRule);
// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
final HashSet workingCopyPaths = new HashSet();
String workingCopyPath = null;
IJavaScriptUnit[] copies = getWorkingCopies();
final int copiesLength = copies == null ? 0 : copies.length;
if (copies != null) {
if (copiesLength == 1) {
workingCopyPath = copies[0].getPath().toString();
} else {
for (int i = 0; i < copiesLength; i++) {
IJavaScriptUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
// Filter unexpected types
QualifiedTypeDeclarationPattern record = (QualifiedTypeDeclarationPattern) indexRecord;
if (record.enclosingTypeNames == IIndexConstants.ONE_ZERO_CHAR) {
return true; // filter out local and anonymous classes
}
switch (copiesLength) {
case 0:
break;
case 1:
if (singleWkcpPath.equals(documentPath)) {
return true; // fliter out *the* working copy
}
break;
default:
if (workingCopyPaths.contains(documentPath)) {
return true; // filter out working copies
}
break;
}
// Accept document path
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.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++) {
IJavaScriptUnit workingCopy = copies[i];
final String path = workingCopy.getPath().toString();
if (workingCopy.isConsistent()) {
char[] packageDeclaration = CharOperation.NO_CHAR;
IType[] allTypes = workingCopy.getAllTypes();
for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
IType type = allTypes[j];
IJavaScriptElement 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;
}
if (pattern.matchesDecodedKey(new QualifiedTypeDeclarationPattern(qualification, simpleName, suffix, matchRule))) {
nameRequestor.acceptType(type.getFlags(), packageDeclaration, simpleName, enclosingTypeNames, path, null);
}
}
} else {
Parser basicParser = getParser();
org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit) workingCopy;
CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
if (parsedUnit != null) {
basicParser.inferTypes(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(typeDeclaration.modifiers)), 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.IsMemberType) != 0) {
enclosing = enclosing.enclosingType;
} else {
enclosing = null;
}
}
SearchPattern decodedPattern =
new QualifiedTypeDeclarationPattern(qualification, memberTypeDeclaration.name, convertTypeKind(TypeDeclaration.kind(memberTypeDeclaration.modifiers)), matchRule);
if (pattern.matchesDecodedKey(decodedPattern)) {
nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
}
return true;
}
public boolean visit(InferredType inferredType, BlockScope scope) {
SearchPattern decodedPattern =
new QualifiedTypeDeclarationPattern(packageDeclaration, inferredType.getName(), convertTypeKind(TypeDeclaration.kind(0)), matchRule);
if (pattern.matchesDecodedKey(decodedPattern)) {
nameRequestor.acceptType(0, packageDeclaration, inferredType.getName(), CharOperation.NO_CHAR_CHAR, path, null);
}
return true;
}
}
parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
}
}
}
}
} finally {
if (progressMonitor != null) {
progressMonitor.done();
}
}
}
public void searchDeclarations(IJavaScriptElement enclosingElement, SearchRequestor requestor, SearchPattern pattern, IProgressMonitor monitor) throws JavaScriptModelException {
if (VERBOSE) {
Util.verbose(" - java element: "+enclosingElement); //$NON-NLS-1$
}
IJavaScriptSearchScope scope = createJavaSearchScope(new IJavaScriptElement[] {enclosingElement});
IResource resource = enclosingElement.getResource();
if (enclosingElement instanceof IMember) {
IMember member = (IMember) enclosingElement;
IJavaScriptUnit cu = member.getJavaScriptUnit();
if (cu != null) {
resource = cu.getResource();
} else if (member.isBinary()) {
// binary member resource cannot be used as this
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=148215
resource = null;
}
}
try {
if (resource instanceof IFile) {
try {
requestor.beginReporting();
if (VERBOSE) {
Util.verbose("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 JavaScriptModelException)
throw (JavaScriptModelException) e;
throw new JavaScriptModelException(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.
*
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#searchDeclarationsOfAccessedFields(IJavaScriptElement, SearchRequestor, IProgressMonitor)
* for detailed comment
*/
public void searchDeclarationsOfAccessedFields(IJavaScriptElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaScriptModelException {
if (VERBOSE) {
Util.verbose("BasicSearchEngine.searchDeclarationsOfAccessedFields(IJavaScriptElement, 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.
*
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#searchDeclarationsOfReferencedTypes(IJavaScriptElement, SearchRequestor, IProgressMonitor)
* for detailed comment
*/
public void searchDeclarationsOfReferencedTypes(IJavaScriptElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaScriptModelException {
if (VERBOSE) {
Util.verbose("BasicSearchEngine.searchDeclarationsOfReferencedTypes(IJavaScriptElement, 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.
*
* @see org.eclipse.wst.jsdt.core.search.SearchEngine#searchDeclarationsOfSentMessages(IJavaScriptElement, SearchRequestor, IProgressMonitor)
* for detailed comment
*/
public void searchDeclarationsOfSentMessages(IJavaScriptElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaScriptModelException {
if (VERBOSE) {
Util.verbose("BasicSearchEngine.searchDeclarationsOfSentMessages(IJavaScriptElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
}
SearchPattern pattern = new DeclarationOfReferencedMethodsPattern(enclosingElement);
searchDeclarations(enclosingElement, requestor, pattern, monitor);
}
/**
* <p>Used to search all constructor declarations for ones that match the given type name using the given role,
* in the given scope, reporting to the given requester.</p>
*
* @param typeNamePattern type name pattern to search for
* @param typeMatchRule Search pattern matching rule to use with the given <code>typeNamePattern</code>
* @param scope scope of the search
* @param nameRequester requester to report findings to
* @param waitingPolicy Policy to use when waiting for the index
* @param progressMonitor monitor to report index search progress to
*
* @see SearchPattern#R_CAMELCASE_MATCH
* @see SearchPattern#R_CASE_SENSITIVE
* @see SearchPattern#R_EQUIVALENT_MATCH
* @see SearchPattern#R_EXACT_MATCH
* @see SearchPattern#R_FULL_MATCH
* @see SearchPattern#R_PATTERN_MATCH
* @see SearchPattern#R_PREFIX_MATCH
* @see SearchPattern#R_REGEXP_MATCH
*
* @see IJavaScriptSearchConstants#FORCE_IMMEDIATE_SEARCH
* @see IJavaScriptSearchConstants#CANCEL_IF_NOT_READY_TO_SEARCH
* @see IJavaScriptSearchConstants#WAIT_UNTIL_READY_TO_SEARCH
*/
public void searchAllConstructorDeclarations(
final char[] typeNamePattern,
final int typeMatchRule,
IJavaScriptSearchScope scope,
final IConstructorRequestor nameRequester,
int waitingPolicy,
IProgressMonitor progressMonitor) {
// Debug
if (VERBOSE) {
Util.verbose("BasicSearchEngine.searchAllConstructorDeclarations(char[], char[], int, IJavaSearchScope, IRestrictedAccessConstructorRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
Util.verbose(" - type name: "+(typeNamePattern==null?"null":new String(typeNamePattern))); //$NON-NLS-1$ //$NON-NLS-2$
Util.verbose(" - type match rule: "+getMatchRuleString(typeMatchRule)); //$NON-NLS-1$
Util.verbose(" - scope: "+scope); //$NON-NLS-1$
}
// Create pattern
IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager();
final ConstructorDeclarationPattern pattern = new ConstructorDeclarationPattern(
typeNamePattern,
typeMatchRule);
// Index requester
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
// Filter unexpected types
ConstructorDeclarationPattern record = (ConstructorDeclarationPattern)indexRecord;
// Accept document path
AccessRestriction accessRestriction = null;
if (access != null) {
// Compute document relative path
int nameLength = record.declaringSimpleName==null ? 0 : record.declaringSimpleName.length;
char[] path = new char[nameLength];
int pos = 0;
if (nameLength > 0) {
System.arraycopy(record.declaringSimpleName, 0, path, pos, nameLength);
pos += nameLength;
}
// Update access restriction if path is not empty
if (pos > 0) {
accessRestriction = access.getViolatedRestriction(path);
}
}
nameRequester.acceptConstructor(
record.modifiers,
record.declaringSimpleName,
record.parameterCount,
record.parameterTypes,
record.parameterNames,
documentPath,
accessRestriction);
return true;
}
};
try {
if (progressMonitor != null) {
progressMonitor.beginTask(Messages.engine_searching, 1000);
}
// Find constructor declarations from index
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // JavaScript search only
scope,
searchRequestor),
waitingPolicy,
progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 1000));
} finally {
if (progressMonitor != null) {
progressMonitor.done();
}
}
}
}