org.eclipse.jdt.internal.core.search.BasicSearchEngine Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2000, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Stephan Herrmann - Contributions for bug 215139 and bug 295894
* Microsoft Corporation - Contribution for bug 575562 - improve completion search performance
*******************************************************************************/
package org.eclipse.jdt.internal.core.search;
import static org.eclipse.jdt.internal.core.JavaModelManager.trace;
import java.util.*;
import java.util.regex.Pattern;
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.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 search 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 SearchEngine#SearchEngine(ICompilationUnit[]) for detailed comment.
*/
public BasicSearchEngine(ICompilationUnit[] workingCopies) {
this.workingCopies = workingCopies;
}
char convertTypeKind(int typeDeclarationKind) {
switch(typeDeclarationKind) {
case TypeDeclaration.CLASS_DECL : return IIndexConstants.CLASS_SUFFIX;
case TypeDeclaration.INTERFACE_DECL : return IIndexConstants.INTERFACE_SUFFIX;
case TypeDeclaration.ENUM_DECL : return IIndexConstants.ENUM_SUFFIX;
case TypeDeclaration.ANNOTATION_TYPE_DECL : return IIndexConstants.ANNOTATION_TYPE_SUFFIX;
default : return IIndexConstants.TYPE_SUFFIX;
}
}
/**
* @see SearchEngine#SearchEngine(WorkingCopyOwner) for detailed comment.
*/
public BasicSearchEngine(WorkingCopyOwner workingCopyOwner) {
this.workingCopyOwner = workingCopyOwner;
}
/**
* @see SearchEngine#createHierarchyScope(IType) for detailed comment.
*/
public static IJavaSearchScope createHierarchyScope(IType type) throws JavaModelException {
return createHierarchyScope(type, DefaultWorkingCopyOwner.PRIMARY);
}
/**
* @see SearchEngine#createHierarchyScope(IType,WorkingCopyOwner) for detailed comment.
*/
public static IJavaSearchScope createHierarchyScope(IType type, WorkingCopyOwner owner) throws JavaModelException {
return new HierarchyScope(type, owner);
}
/**
* @see SearchEngine#createStrictHierarchyScope(IJavaProject,IType,boolean,boolean,WorkingCopyOwner) for detailed comment.
*/
public static IJavaSearchScope createStrictHierarchyScope(IJavaProject project, IType type, boolean onlySubtypes, boolean includeFocusType, WorkingCopyOwner owner) throws JavaModelException {
return new HierarchyScope(project, type, owner, onlySubtypes, true, includeFocusType);
}
/**
* @see SearchEngine#createJavaSearchScope(IJavaElement[]) for detailed comment.
*/
public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements) {
return createJavaSearchScope(false, elements, true);
}
public static IJavaSearchScope createJavaSearchScope(boolean excludeTestCode, IJavaElement[] elements) {
return createJavaSearchScope(excludeTestCode, elements, true);
}
public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements, boolean includeReferencedProjects) {
return createJavaSearchScope(false, elements, includeReferencedProjects);
}
/**
* @see SearchEngine#createJavaSearchScope(boolean, IJavaElement[], boolean) for detailed comment.
*/
public static IJavaSearchScope createJavaSearchScope(boolean excludeTestCode, IJavaElement[] elements, boolean includeReferencedProjects) {
int includeMask = IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.SYSTEM_LIBRARIES;
if (includeReferencedProjects) {
includeMask |= IJavaSearchScope.REFERENCED_PROJECTS;
}
return createJavaSearchScope(excludeTestCode, elements, includeMask);
}
public static IJavaSearchScope createJavaSearchScope(IJavaElement[] elements, int includeMask) {
return createJavaSearchScope(false, elements, includeMask);
}
/**
* @see SearchEngine#createJavaSearchScope(boolean, IJavaElement[], int) for detailed comment.
*/
public static IJavaSearchScope createJavaSearchScope(boolean excludeTestCode, IJavaElement[] elements, int includeMask) {
Set projectsToBeAdded = new HashSet<>(2);
for (int i = 0, length = elements.length; i < length; i++) {
IJavaElement element = elements[i];
if (element instanceof JavaProject p) {
projectsToBeAdded.add(p);
}
}
JavaSearchScope scope = new JavaSearchScope(excludeTestCode);
for (int i = 0, length = elements.length; i < length; i++) {
IJavaElement element = elements[i];
if (element != null) {
try {
if (projectsToBeAdded.contains(element)) {
scope.add((JavaProject)element, includeMask, projectsToBeAdded);
} else {
scope.add(element);
}
} catch (JavaModelException e) {
// ignore
}
}
}
return scope;
}
/**
* @see SearchEngine#createTypeNameMatch(IType, int) for detailed comment.
*/
public static TypeNameMatch createTypeNameMatch(IType type, int modifiers) {
return new JavaSearchTypeNameMatch(type, modifiers);
}
/**
* @see SearchEngine#createMethodNameMatch(IMethod, int) for detailed comment.
*/
public static MethodNameMatch createMethodNameMatch(IMethod method, int modifiers) {
return new JavaSearchMethodNameMatch(method, modifiers);
}
/**
* @see SearchEngine#createWorkspaceScope() for detailed comment.
*/
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
*/
void findMatches(SearchPattern pattern, SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
try {
if (VERBOSE) {
trace("Searching for pattern: " + pattern.toString()); //$NON-NLS-1$
trace(scope.toString());
}
if (participants == null) {
if (VERBOSE) {
trace("No participants => do nothing!"); //$NON-NLS-1$
}
return;
}
/* initialize progress monitor */
int length = participants.length;
SubMonitor loopMonitor = SubMonitor.convert(monitor, Messages.engine_searching, length);
IndexManager indexManager = JavaModelManager.getIndexManager();
requestor.beginReporting();
for (int i = 0; i < length; i++) {
SubMonitor iterationMonitor = loopMonitor.split(1).setWorkRemaining(100);
SearchParticipant participant = participants[i];
try {
iterationMonitor.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,
iterationMonitor.split(50));
// locate index matches if any (note that all search matches could have been issued during index querying)
iterationMonitor.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, iterationMonitor.split(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();
}
public static String getMatchRuleString(final int matchRule) {
if (matchRule == 0) {
return "R_EXACT_MATCH"; //$NON-NLS-1$
}
StringBuilder buffer = new StringBuilder();
for (int i=1; i<=16; 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;
case SearchPattern.R_CAMELCASE_SAME_PART_COUNT_MATCH:
buffer.append("R_CAMELCASE_SAME_PART_COUNT_MATCH"); //$NON-NLS-1$
break;
}
}
return buffer.toString();
}
/**
* Return kind of search corresponding to given value.
*/
public static String getSearchForString(final int searchFor) {
switch (searchFor) {
case IJavaSearchConstants.TYPE:
return ("TYPE"); //$NON-NLS-1$
case IJavaSearchConstants.METHOD:
return ("METHOD"); //$NON-NLS-1$
case IJavaSearchConstants.PACKAGE:
return ("PACKAGE"); //$NON-NLS-1$
case IJavaSearchConstants.CONSTRUCTOR:
return ("CONSTRUCTOR"); //$NON-NLS-1$
case IJavaSearchConstants.FIELD:
return ("FIELD"); //$NON-NLS-1$
case IJavaSearchConstants.CLASS:
return ("CLASS"); //$NON-NLS-1$
case IJavaSearchConstants.INTERFACE:
return ("INTERFACE"); //$NON-NLS-1$
case IJavaSearchConstants.ENUM:
return ("ENUM"); //$NON-NLS-1$
case IJavaSearchConstants.ANNOTATION_TYPE:
return ("ANNOTATION_TYPE"); //$NON-NLS-1$
case IJavaSearchConstants.CLASS_AND_ENUM:
return ("CLASS_AND_ENUM"); //$NON-NLS-1$
case IJavaSearchConstants.CLASS_AND_INTERFACE:
return ("CLASS_AND_INTERFACE"); //$NON-NLS-1$
case IJavaSearchConstants.INTERFACE_AND_ANNOTATION:
return ("INTERFACE_AND_ANNOTATION"); //$NON-NLS-1$
}
return "UNKNOWN"; //$NON-NLS-1$
}
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 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 {
Map 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 working copy to use to do the search on the given Java element.
*/
private ICompilationUnit[] getWorkingCopies(IJavaElement element) {
if (element instanceof IMember) {
ICompilationUnit cu = ((IMember)element).getCompilationUnit();
if (cu != null && cu.isWorkingCopy()) {
return new ICompilationUnit[] { cu };
}
} else if (element instanceof ICompilationUnit) {
return new ICompilationUnit[] { (ICompilationUnit) element };
}
return null;
}
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.INTERFACE_AND_ANNOTATION_SUFFIX:
return (modifiers & (Flags.AccInterface | Flags.AccAnnotation)) != 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, int matchRulePkg, char[] patternTypeName, int matchRuleType, int typeKind, char[] pkg, char[] typeName) {
switch(patternTypeSuffix) {
case IIndexConstants.CLASS_SUFFIX :
if (typeKind != TypeDeclaration.CLASS_DECL) return false;
break;
case IIndexConstants.CLASS_AND_INTERFACE_SUFFIX:
if (typeKind != TypeDeclaration.CLASS_DECL && typeKind != TypeDeclaration.INTERFACE_DECL) return false;
break;
case IIndexConstants.CLASS_AND_ENUM_SUFFIX:
if (typeKind != TypeDeclaration.CLASS_DECL && typeKind != TypeDeclaration.ENUM_DECL) return false;
break;
case IIndexConstants.INTERFACE_SUFFIX :
if (typeKind != TypeDeclaration.INTERFACE_DECL) return false;
break;
case IIndexConstants.INTERFACE_AND_ANNOTATION_SUFFIX:
if (typeKind != TypeDeclaration.INTERFACE_DECL && typeKind != TypeDeclaration.ANNOTATION_TYPE_DECL) return false;
break;
case IIndexConstants.ENUM_SUFFIX :
if (typeKind != TypeDeclaration.ENUM_DECL) return false;
break;
case IIndexConstants.ANNOTATION_TYPE_SUFFIX :
if (typeKind != TypeDeclaration.ANNOTATION_TYPE_DECL) return false;
break;
case IIndexConstants.TYPE_SUFFIX : // nothing
}
boolean isPkgCaseSensitive = (matchRulePkg & SearchPattern.R_CASE_SENSITIVE) != 0;
if (patternPkg != null && !CharOperation.equals(patternPkg, pkg, isPkgCaseSensitive))
return false;
boolean isCaseSensitive = (matchRuleType & SearchPattern.R_CASE_SENSITIVE) != 0;
if (patternTypeName != null) {
boolean isCamelCase = (matchRuleType & (SearchPattern.R_CAMELCASE_MATCH | SearchPattern.R_CAMELCASE_SAME_PART_COUNT_MATCH)) != 0;
if ((matchRuleType & SearchPattern.R_SUBSTRING_MATCH) != 0 && CharOperation.substringMatch(patternTypeName, typeName))
return true;
if ((matchRuleType & SearchPattern.R_SUBWORD_MATCH) != 0 && CharOperation.subWordMatch(patternTypeName, typeName))
return true;
int matchMode = matchRuleType & JavaSearchPattern.MATCH_MODE_MASK;
if (!isCaseSensitive && !isCamelCase) {
patternTypeName = CharOperation.toLowerCase(patternTypeName);
}
boolean matchFirstChar = !isCaseSensitive || patternTypeName[0] == typeName[0];
switch(matchMode) {
case SearchPattern.R_EXACT_MATCH :
return matchFirstChar && CharOperation.equals(patternTypeName, typeName, isCaseSensitive);
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 :
return Pattern.matches(new String(patternTypeName), new String(typeName));
case SearchPattern.R_CAMELCASE_MATCH:
if (matchFirstChar && CharOperation.camelCaseMatch(patternTypeName, typeName, false)) {
return true;
}
return !isCaseSensitive && matchFirstChar && CharOperation.prefixEquals(patternTypeName, typeName, false);
case SearchPattern.R_CAMELCASE_SAME_PART_COUNT_MATCH:
return matchFirstChar && CharOperation.camelCaseMatch(patternTypeName, typeName, true);
}
}
return true;
}
boolean match(char[] patternName, int matchRule, char[] name) {
boolean isCaseSensitive = (matchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
if (patternName != null) {
boolean isCamelCase = (matchRule & (SearchPattern.R_CAMELCASE_MATCH | SearchPattern.R_CAMELCASE_SAME_PART_COUNT_MATCH)) != 0;
int matchMode = matchRule & JavaSearchPattern.MATCH_MODE_MASK;
if (!isCaseSensitive && !isCamelCase) {
patternName = CharOperation.toLowerCase(patternName);
}
boolean matchFirstChar = !isCaseSensitive || patternName[0] == name[0];
switch(matchMode) {
case SearchPattern.R_EXACT_MATCH :
return matchFirstChar && CharOperation.equals(patternName, name, isCaseSensitive);
case SearchPattern.R_PREFIX_MATCH :
return matchFirstChar && CharOperation.prefixEquals(patternName, name, isCaseSensitive);
case SearchPattern.R_PATTERN_MATCH :
return CharOperation.match(patternName, name, isCaseSensitive);
case SearchPattern.R_REGEXP_MATCH :
return Pattern.matches(new String(patternName), new String(name));
case SearchPattern.R_CAMELCASE_MATCH:
if (matchFirstChar && CharOperation.camelCaseMatch(patternName, name, false)) {
return true;
}
return !isCaseSensitive && matchFirstChar && CharOperation.prefixEquals(patternName, name, false);
case SearchPattern.R_CAMELCASE_SAME_PART_COUNT_MATCH:
return matchFirstChar && CharOperation.camelCaseMatch(patternName, name, true);
}
}
return true;
}
boolean match(char[] patternPkg, int matchRulePkg,
char[] patternDeclaringQualifier, int matchRuleDeclaringQualifier,
char[] patternDeclaringSimpleName, int matchRuleDeclaringSimpleName,
char[] patternMethodName, int methodMatchRule,
char[] packageName, char[] declaringQualifier, char[] declaringSimpleName, char[] methodName) {
if (patternPkg != null && !CharOperation.equals(patternPkg, packageName, (matchRulePkg & SearchPattern.R_CASE_SENSITIVE) != 0))
return false;
return match(patternDeclaringQualifier, matchRuleDeclaringQualifier, declaringQualifier) &&
match(patternDeclaringSimpleName, matchRuleDeclaringSimpleName, declaringSimpleName) &&
match(patternMethodName, methodMatchRule, methodName);
}
boolean match(char[] patternFusedQualifier, int matchRuleFusedQualifier,
char[] patternMethodName, int methodMatchRule,
char[] packageName, char[] declaringQualifier, char[] declaringSimpleName, char[] methodName) {
char[] q = packageName != null ? packageName : CharOperation.NO_CHAR;
if (declaringQualifier != null && declaringQualifier.length > 0) {
q = q.length > 0 ? CharOperation.concat(q, declaringQualifier, '.') : declaringQualifier;
}
if (declaringSimpleName != null && declaringSimpleName.length > 0) {
q = q.length > 0 ? CharOperation.concat(q, declaringSimpleName, '.') : declaringSimpleName;
}
return match(patternFusedQualifier, matchRuleFusedQualifier, q) &&
match(patternMethodName, methodMatchRule, methodName);
}
/**
* 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 SearchEngine#search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor)
* for detailed comment
*/
public void search(SearchPattern pattern, SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
if (VERBOSE) {
trace("BasicSearchEngine.search(SearchPattern, SearchParticipant[], IJavaSearchScope, SearchRequestor, IProgressMonitor)"); //$NON-NLS-1$
}
findMatches(pattern, participants, scope, requestor, monitor);
}
public void searchAllConstructorDeclarations(
final char[] packageName,
final char[] typeName,
final int typeMatchRule,
IJavaSearchScope scope,
final IRestrictedAccessConstructorRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
searchAllConstructorDeclarations(
packageName,
typeName,
typeMatchRule,
scope,
true,
nameRequestor,
waitingPolicy,
progressMonitor);
}
/**
*
* Searches for constructor declarations in the given scope.
*
* @param resolveDocumentName used to tell SearchEngine whether to resolve
* the document name for each result entry.
*/
public void searchAllConstructorDeclarations(
final char[] packageName,
final char[] typeName,
final int typeMatchRule,
IJavaSearchScope scope,
final boolean resolveDocumentName,
final IRestrictedAccessConstructorRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
try {
// Validate match rule first
final int validatedTypeMatchRule = SearchPattern.validateMatchRule(typeName == null ? null : new String (typeName), typeMatchRule);
final int pkgMatchRule = SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE;
final char NoSuffix = IIndexConstants.TYPE_SUFFIX; // Used as TYPE_SUFFIX has no effect in method #match(char, char[] , int, char[], int , int, char[], char[])
// Debug
if (VERBOSE) {
trace("BasicSearchEngine.searchAllConstructorDeclarations(char[], char[], int, IJavaSearchScope, IRestrictedAccessConstructorRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
trace(" - package name: "+(packageName==null?"null":new String(packageName))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - type name: "+(typeName==null?"null":new String(typeName))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - type match rule: "+getMatchRuleString(typeMatchRule)); //$NON-NLS-1$
if (validatedTypeMatchRule != typeMatchRule) {
trace(" - validated type match rule: "+getMatchRuleString(validatedTypeMatchRule)); //$NON-NLS-1$
}
trace(" - scope: "+scope); //$NON-NLS-1$
}
if (validatedTypeMatchRule == -1) return; // invalid match rule => return no results
// Create pattern
IndexManager indexManager = JavaModelManager.getIndexManager();
final ConstructorDeclarationPattern pattern = new ConstructorDeclarationPattern(
packageName,
typeName,
validatedTypeMatchRule);
// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
final Set workingCopyPaths = new HashSet<>();
String workingCopyPath = null;
ICompilationUnit[] 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++) {
ICompilationUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
@Override
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
// Filter unexpected types
ConstructorDeclarationPattern record = (ConstructorDeclarationPattern)indexRecord;
if ((record.extraFlags & ExtraFlags.IsMemberType) != 0) {
return true; // filter out member classes
}
if ((record.extraFlags & ExtraFlags.IsLocalType) != 0) {
return true; // filter out local and anonymous classes
}
switch (copiesLength) {
case 0:
break;
case 1:
if (singleWkcpPath.equals(documentPath)) {
return true; // filter 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.declaringPackageName==null || record.declaringPackageName.length==0) ? 0 : record.declaringPackageName.length+1;
int nameLength = record.declaringSimpleName==null ? 0 : record.declaringSimpleName.length;
char[] path = new char[pkgLength+nameLength];
int pos = 0;
if (pkgLength > 0) {
System.arraycopy(record.declaringPackageName, 0, path, pos, pkgLength-1);
CharOperation.replace(path, '.', '/');
path[pkgLength-1] = '/';
pos += pkgLength;
}
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);
}
}
nameRequestor.acceptConstructor(
record.modifiers,
record.declaringSimpleName,
record.parameterCount,
record.signature,
record.parameterTypes,
record.parameterNames,
record.declaringTypeModifiers,
record.declaringPackageName,
record.extraFlags,
documentPath,
accessRestriction);
return true;
}
};
SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
resolveDocumentName,
true,
searchRequestor),
waitingPolicy,
subMonitor.split(Math.max(1000-copiesLength, 0)));
// add type names from working copies
if (copies != null) {
for (int i = 0; i < copiesLength; i++) {
SubMonitor iterationMonitor = subMonitor.split(1);
final ICompilationUnit workingCopy = copies[i];
if (scope instanceof HierarchyScope) {
if (!((HierarchyScope)scope).encloses(workingCopy, iterationMonitor)) continue;
} else {
if (!scope.encloses(workingCopy)) continue;
}
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];
char[] simpleName = type.getElementName().toCharArray();
if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, simpleName) && !type.isMember()) {
int extraFlags = ExtraFlags.getExtraFlags(type);
boolean hasConstructor = false;
IMethod[] methods = type.getMethods();
for (int k = 0; k < methods.length; k++) {
IMethod method = methods[k];
if (method.isConstructor()) {
hasConstructor = true;
String[] stringParameterNames = method.getParameterNames();
String[] stringParameterTypes = method.getParameterTypes();
int length = stringParameterNames.length;
char[][] parameterNames = new char[length][];
char[][] parameterTypes = new char[length][];
for (int l = 0; l < length; l++) {
parameterNames[l] = stringParameterNames[l].toCharArray();
parameterTypes[l] = Signature.toCharArray(Signature.getTypeErasure(stringParameterTypes[l]).toCharArray());
}
nameRequestor.acceptConstructor(
method.getFlags(),
simpleName,
parameterNames.length,
null,// signature is not used for source type
parameterTypes,
parameterNames,
type.getFlags(),
packageDeclaration,
extraFlags,
path,
null);
}
}
if (!hasConstructor) {
nameRequestor.acceptConstructor(
Flags.AccPublic,
simpleName,
-1,
null, // signature is not used for source type
CharOperation.NO_CHAR_CHAR,
CharOperation.NO_CHAR_CHAR,
type.getFlags(),
packageDeclaration,
extraFlags,
path,
null);
}
}
}
} else {
Parser basicParser = getParser();
org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
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 AllConstructorDeclarationsVisitor extends ASTVisitor {
private TypeDeclaration[] declaringTypes = new TypeDeclaration[0];
private int declaringTypesPtr = -1;
private void endVisit(TypeDeclaration typeDeclaration) {
if (!hasConstructor(typeDeclaration) && typeDeclaration.enclosingType == null) {
if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, typeDeclaration.name)) {
nameRequestor.acceptConstructor(
Flags.AccPublic,
typeName,
-1,
null, // signature is not used for source type
CharOperation.NO_CHAR_CHAR,
CharOperation.NO_CHAR_CHAR,
typeDeclaration.modifiers,
packageDeclaration,
ExtraFlags.getExtraFlags(typeDeclaration),
path,
null);
}
}
this.declaringTypes[this.declaringTypesPtr] = null;
this.declaringTypesPtr--;
}
@Override
public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
endVisit(typeDeclaration);
}
@Override
public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
endVisit(memberTypeDeclaration);
}
private boolean hasConstructor(TypeDeclaration typeDeclaration) {
AbstractMethodDeclaration[] methods = typeDeclaration.methods;
int length = methods == null ? 0 : methods.length;
for (int j = 0; j < length; j++) {
if (methods[j].isConstructor()) {
return true;
}
}
return false;
}
@Override
public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope classScope) {
TypeDeclaration typeDeclaration = this.declaringTypes[this.declaringTypesPtr];
if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, typeDeclaration.name)) {
Argument[] arguments = constructorDeclaration.arguments;
int length = arguments == null ? 0 : arguments.length;
char[][] parameterNames = new char[length][];
char[][] parameterTypes = new char[length][];
for (int l = 0; l < length; l++) {
Argument argument = arguments[l];
parameterNames[l] = argument.name;
if (argument.type instanceof SingleTypeReference) {
parameterTypes[l] = ((SingleTypeReference)argument.type).token;
} else {
parameterTypes[l] = CharOperation.concatWith(((QualifiedTypeReference)argument.type).tokens, '.');
}
}
TypeDeclaration enclosing = typeDeclaration.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;
}
}
nameRequestor.acceptConstructor(
constructorDeclaration.modifiers,
typeName,
parameterNames.length,
null, // signature is not used for source type
parameterTypes,
parameterNames,
typeDeclaration.modifiers,
packageDeclaration,
ExtraFlags.getExtraFlags(typeDeclaration),
path,
null);
}
return false; // no need to find constructors from local/anonymous type
}
@Override
public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
return false;
}
private boolean visit(TypeDeclaration typeDeclaration) {
if(this.declaringTypes.length <= ++this.declaringTypesPtr) {
int length = this.declaringTypesPtr;
System.arraycopy(this.declaringTypes, 0, this.declaringTypes = new TypeDeclaration[length * 2 + 1], 0, length);
}
this.declaringTypes[this.declaringTypesPtr] = typeDeclaration;
return true;
}
@Override
public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
return visit(typeDeclaration);
}
@Override
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
return visit(memberTypeDeclaration);
}
}
parsedUnit.traverse(new AllConstructorDeclarationsVisitor(), parsedUnit.scope);
}
}
}
}
} finally {
if (progressMonitor != null) {
progressMonitor.done();
}
}
}
/**
* Searches for all method declarations in the given scope.
* *
* Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
* comment is removed.
*
*
* @see SearchEngine#searchAllMethodNames(char[], int, char[], int, IJavaSearchScope, MethodNameMatchRequestor, int, IProgressMonitor)
* for detailed comments
*/
public void searchAllMethodNames(
final char[] qualifier,
final int qualifierMatchRule,
final char[] methodName,
final int methodMatchRule,
IJavaSearchScope scope,
final IRestrictedAccessMethodRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
// Validate match rule first
final int validatedMethodMatchRule = SearchPattern.validateMatchRule(methodName == null ? null : new String (methodName), methodMatchRule);
// Debug
if (VERBOSE) {
trace("BasicSearchEngine.searchAllMethodDeclarations(char[] qualifier, "//$NON-NLS-1$
+ "char[] methodName, int methodMatchRule, IJavaSearchScope, IRestrictedAccessConstructorRequestor, int waitingPolicy, IProgressMonitor)"); //$NON-NLS-1$
trace(" - qualifier name: "+(qualifier==null?"null":new String(qualifier))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - method name: "+(methodName==null?"null":new String(methodName))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - method match rule: "+getMatchRuleString(methodMatchRule)); //$NON-NLS-1$
if (validatedMethodMatchRule != methodMatchRule) {
trace(" - validated method match rule: "+getMatchRuleString(validatedMethodMatchRule)); //$NON-NLS-1$
}
trace(" - scope: "+scope); //$NON-NLS-1$
}
if (validatedMethodMatchRule == -1) return; // invalid match rule => return no results
// Create pattern
IndexManager indexManager = JavaModelManager.getIndexManager();
final MethodDeclarationPattern pattern = new MethodDeclarationPattern(qualifier, methodName, methodMatchRule);
// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
Set workingCopyPaths = new HashSet<>();
String workingCopyPath = null;
ICompilationUnit[] 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++) {
ICompilationUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
@Override
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
MethodDeclarationPattern record = (MethodDeclarationPattern)indexRecord;
if ((record.extraFlags & ExtraFlags.IsLocalType) != 0) {
return true; // filter out local and anonymous classes
}
switch (copiesLength) {
case 0:
break;
case 1:
if (singleWkcpPath.equals(documentPath)) {
return true; // filter 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.declaringPackageName==null || record.declaringPackageName.length==0) ? 0 : record.declaringPackageName.length+1;
int qualificationLength = (record.declaringQualification == null || record.declaringQualification.length == 0) ? 0 : record.declaringQualification.length;
int nameLength = record.declaringSimpleName==null ? 0 : record.declaringSimpleName.length;
char[] path = new char[pkgLength + qualificationLength + nameLength];
int pos = 0;
if (pkgLength > 0) {
System.arraycopy(record.declaringPackageName, 0, path, pos, pkgLength-1);
CharOperation.replace(path, '.', '/');
path[pkgLength-1] = '/';
pos += pkgLength;
}
if (qualificationLength > 0) {
System.arraycopy(record.declaringQualification, 0, path, pos, qualificationLength);
}
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);
}
}
if (match(qualifier, qualifierMatchRule, methodName, methodMatchRule,
record.declaringPackageName, record.declaringQualification, record.declaringSimpleName, record.selector)) {
nameRequestor.acceptMethod(
record.selector,
record.parameterCount,
record.declaringQualification,
record.declaringSimpleName,
record.declaringTypeModifiers,
record.declaringPackageName,
record.signature,
record.parameterTypes,
record.parameterNames,
record.returnSimpleName,
record.modifiers,
documentPath,
accessRestriction,
-1 /* method index not applicable as there is no IType here */);
}
return true;
}
};
SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
searchRequestor),
waitingPolicy,
subMonitor.split(Math.max(1000-copiesLength, 0)));
// add type names from working copies
if (copies != null) {
for (int i = 0; i < copiesLength; i++) {
SubMonitor iterationMonitor = subMonitor.split(1);
final ICompilationUnit workingCopy = copies[i];
if (scope instanceof HierarchyScope) {
if (!((HierarchyScope)scope).encloses(workingCopy, iterationMonitor)) continue;
} else {
if (!scope.encloses(workingCopy)) continue;
}
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[] rDeclaringQualification = parent instanceof IType ? ((IType) parent).getTypeQualifiedName('.').toCharArray() : CharOperation.NO_CHAR;
char[] rSimpleName = type.getElementName().toCharArray();
char[] q = CharOperation.concatNonEmpty(packageDeclaration, '.', rDeclaringQualification, '.', rSimpleName);
if (!match(qualifier, qualifierMatchRule, q))
continue;
reportMatchingMethods(methodName, methodMatchRule, nameRequestor, path,
packageDeclaration, type, rDeclaringQualification, rSimpleName);
}
} else {
Parser basicParser = getParser();
org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
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 AllMethodDeclarationVisitor extends ASTVisitor {
class TypeInfo {
public TypeDeclaration typeDecl;
public IType type;
public boolean visitMethods;
public char[] enclosingTypeName;
TypeInfo(TypeDeclaration typeDecl, boolean visitMethods, char[] enclosingTypeName) {
this.typeDecl = typeDecl;
this.type = workingCopy.getType(new String(typeDecl.name));
this.visitMethods = visitMethods;
this.enclosingTypeName = enclosingTypeName;
}
}
Stack typeInfoStack = new Stack<>();
IType getCurrentType() {
int l = this.typeInfoStack.size();
if (l <= 0) return null;
TypeInfo typeInfo = this.typeInfoStack.get(0);
IType type = typeInfo.type;
if (type == null) {
TypeInfo ti = this.typeInfoStack.get(0);
ti.type = ti.type == null ? workingCopy.getType(new String(ti.typeDecl.name)) : ti.type;
type = ti.type;
for (int j = 1; j < l && type != null; ++j) {
ti = this.typeInfoStack.get(j);
if (ti.type == null) {
ti.type = type.getType(new String(ti.typeDecl.name));
}
type = ti.type;
}
}
return type;
}
private void addStackEntry(TypeDeclaration typeDeclaration, char[] enclosingTypeName) {
char[] q = CharOperation.concatNonEmpty(packageDeclaration, '.', enclosingTypeName, '.', typeDeclaration.name);
boolean visitMethods = match(qualifier, qualifierMatchRule, q);
this.typeInfoStack.push(new TypeInfo(typeDeclaration, visitMethods, enclosingTypeName));
}
@Override
public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
this.typeInfoStack.pop();
}
@Override
public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
this.typeInfoStack.pop();
}
@Override
public boolean visit(MethodDeclaration methodDeclaration, ClassScope classScope) {
TypeInfo typeInfo = this.typeInfoStack.peek();
if (typeInfo.visitMethods &&
match(methodName, methodMatchRule, methodDeclaration.selector)) {
reportMatchingMethod(path, packageDeclaration,
typeInfo.enclosingTypeName,
typeInfo.typeDecl,
methodDeclaration,
getCurrentType(),
nameRequestor);
}
return false; // no need to find methods from local/anonymous type
}
@Override
public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
return false; // do not visit local/anonymous types
}
@Override
public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
addStackEntry(typeDeclaration, CharOperation.NO_CHAR);
return true;
}
@Override
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
TypeInfo typeInfo = this.typeInfoStack.peek();
addStackEntry(memberTypeDeclaration, typeInfo.enclosingTypeName == CharOperation.NO_CHAR ? typeInfo.typeDecl.name :
CharOperation.concat(typeInfo.enclosingTypeName, typeInfo.typeDecl.name, '.'));
return true;
}
}
parsedUnit.traverse(new AllMethodDeclarationVisitor(), parsedUnit.scope);
}
}
}
}
}
/**
* Searches for all method declarations in the given scope.
* *
* Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
* comment is removed.
*
*
* @see SearchEngine#searchAllMethodNames(char[], int, char[], int, char[], int, char[], int, IJavaSearchScope, MethodNameMatchRequestor, int, IProgressMonitor)
* for detailed comments
*/
public void searchAllMethodNames(
final char[] packageName,
final int pkgMatchRule,
final char[] declaringQualification,
final int declQualificationMatchRule,
final char[] declaringSimpleName,
final int declSimpleNameMatchRule,
final char[] methodName,
final int methodMatchRule,
IJavaSearchScope scope,
final IRestrictedAccessMethodRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
// Validate match rule first
final int validatedMethodMatchRule = SearchPattern.validateMatchRule(methodName == null ? null : new String (methodName), methodMatchRule);
// Debug
if (VERBOSE) {
trace("BasicSearchEngine.searchAllMethodDeclarations(char[] packageName, char[] declaringQualification, char[] declaringSimpleName, "//$NON-NLS-1$
+ "char[] methodName, int methodMatchRule, IJavaSearchScope, IRestrictedAccessConstructorRequestor, int waitingPolicy, IProgressMonitor)"); //$NON-NLS-1$
trace(" - package name: "+(packageName==null?"null":new String(packageName))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - declaringQualification name: "+(declaringQualification==null?"null":new String(declaringQualification))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - declaringSimple name: "+(declaringSimpleName==null?"null":new String(declaringSimpleName))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - method name: "+(methodName==null?"null":new String(methodName))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - method match rule: "+getMatchRuleString(methodMatchRule)); //$NON-NLS-1$
if (validatedMethodMatchRule != methodMatchRule) {
trace(" - validated method match rule: "+getMatchRuleString(validatedMethodMatchRule)); //$NON-NLS-1$
}
trace(" - scope: "+scope); //$NON-NLS-1$
}
if (validatedMethodMatchRule == -1) return; // invalid match rule => return no results
// Create pattern
IndexManager indexManager = JavaModelManager.getIndexManager();
final MethodDeclarationPattern pattern = new MethodDeclarationPattern(packageName, declaringQualification, declaringSimpleName, methodName, methodMatchRule);
// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
Set workingCopyPaths = new HashSet<>();
String workingCopyPath = null;
ICompilationUnit[] 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++) {
ICompilationUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
@Override
public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
MethodDeclarationPattern record = (MethodDeclarationPattern)indexRecord;
if ((record.extraFlags & ExtraFlags.IsLocalType) != 0) {
return true; // filter out local and anonymous classes
}
switch (copiesLength) {
case 0:
break;
case 1:
if (singleWkcpPath.equals(documentPath)) {
return true; // filter 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.declaringPackageName==null || record.declaringPackageName.length==0) ? 0 : record.declaringPackageName.length+1;
int qualificationLength = (record.declaringQualification == null || record.declaringQualification.length == 0) ? 0 : record.declaringQualification.length;
int nameLength = record.declaringSimpleName==null ? 0 : record.declaringSimpleName.length;
char[] path = new char[pkgLength + qualificationLength + nameLength];
int pos = 0;
if (pkgLength > 0) {
System.arraycopy(record.declaringPackageName, 0, path, pos, pkgLength-1);
CharOperation.replace(path, '.', '/');
path[pkgLength-1] = '/';
pos += pkgLength;
}
if (qualificationLength > 0) {
System.arraycopy(record.declaringQualification, 0, path, pos, qualificationLength);
}
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);
}
}
if (match(packageName, pkgMatchRule, declaringQualification, declQualificationMatchRule, declaringSimpleName, declSimpleNameMatchRule, methodName, methodMatchRule,
record.declaringPackageName, record.declaringQualification, record.declaringSimpleName, record.selector)) {
nameRequestor.acceptMethod(
record.selector,
record.parameterCount,
record.declaringQualification,
record.declaringSimpleName,
record.declaringTypeModifiers,
record.declaringPackageName,
record.signature,
record.parameterTypes,
record.parameterNames,
record.returnSimpleName,
record.modifiers,
documentPath,
accessRestriction,
-1 /* method index not applicable as there is no IType here */);
}
return true;
}
};
SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
searchRequestor),
waitingPolicy,
subMonitor.split(Math.max(1000-copiesLength, 0)));
// add type names from working copies
if (copies != null) {
boolean isPkgCaseSensitive = (pkgMatchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
for (int i = 0; i < copiesLength; i++) {
SubMonitor iterationMonitor = subMonitor.split(1);
final ICompilationUnit workingCopy = copies[i];
if (scope instanceof HierarchyScope) {
if (!((HierarchyScope)scope).encloses(workingCopy, iterationMonitor)) continue;
} else {
if (!scope.encloses(workingCopy)) continue;
}
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();
if (packageName != null && !CharOperation.equals(packageName, packageDeclaration, isPkgCaseSensitive))
continue;
IType[] allTypes = workingCopy.getAllTypes();
for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
IType type = allTypes[j];
IJavaElement parent = type.getParent();
char[] rDeclaringQualification = parent instanceof IType ? ((IType) parent).getTypeQualifiedName('.').toCharArray() : CharOperation.NO_CHAR;
char[] rSimpleName = type.getElementName().toCharArray();
if (!match(declaringQualification, declQualificationMatchRule, rDeclaringQualification) ||
!match(declaringSimpleName, declSimpleNameMatchRule, rSimpleName))
continue;
reportMatchingMethods(methodName, methodMatchRule, nameRequestor, path,
packageDeclaration, type, rDeclaringQualification, rSimpleName);
}
} else {
Parser basicParser = getParser();
org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
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 AllMethodDeclarationVisitor extends ASTVisitor {
class TypeInfo {
public TypeDeclaration typeDecl;
public IType type;
public boolean visitMethods;
public char[] enclosingTypeName;
TypeInfo(TypeDeclaration typeDecl, boolean visitMethods, char[] enclosingTypeName) {
this.typeDecl = typeDecl;
this.type = workingCopy.getType(new String(typeDecl.name));
this.visitMethods = visitMethods;
this.enclosingTypeName = enclosingTypeName;
}
}
Stack typeInfoStack = new Stack<>();
IType getCurrentType() {
int l = this.typeInfoStack.size();
if (l <= 0) return null;
TypeInfo typeInfo = this.typeInfoStack.get(0);
IType type = typeInfo.type;
if (type == null) {
TypeInfo ti = this.typeInfoStack.get(0);
ti.type = ti.type == null ? workingCopy.getType(new String(ti.typeDecl.name)) : ti.type;
type = ti.type;
for (int j = 1; j < l && type != null; ++j) {
ti = this.typeInfoStack.get(j);
if (ti.type == null) {
ti.type = type.getType(new String(ti.typeDecl.name));
}
type = ti.type;
}
}
return type;
}
private void addStackEntry(TypeDeclaration typeDeclaration, char[] enclosingTypeName) {
boolean visitMethods = match(declaringQualification, declQualificationMatchRule, enclosingTypeName) &&
match(declaringSimpleName, declSimpleNameMatchRule, typeDeclaration.name);
this.typeInfoStack.push(new TypeInfo(typeDeclaration, visitMethods, enclosingTypeName));
}
@Override
public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
this.typeInfoStack.pop();
}
@Override
public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
this.typeInfoStack.pop();
}
@Override
public boolean visit(MethodDeclaration methodDeclaration, ClassScope classScope) {
TypeInfo typeInfo = this.typeInfoStack.peek();
if (typeInfo.visitMethods &&
match(methodName, methodMatchRule, methodDeclaration.selector)) {
reportMatchingMethod(path, packageDeclaration,
typeInfo.enclosingTypeName,
typeInfo.typeDecl,
methodDeclaration,
getCurrentType(),
nameRequestor);
}
return false; // no need to find methods from local/anonymous type
}
@Override
public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
return false; // do not visit local/anonymous types
}
@Override
public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
addStackEntry(typeDeclaration, CharOperation.NO_CHAR);
return true;
}
@Override
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
TypeInfo typeInfo = this.typeInfoStack.peek();
addStackEntry(memberTypeDeclaration, typeInfo.enclosingTypeName == CharOperation.NO_CHAR ? typeInfo.typeDecl.name :
CharOperation.concat(typeInfo.enclosingTypeName, typeInfo.typeDecl.name, '.'));
return true;
}
}
if (match(packageName, pkgMatchRule, packageDeclaration))
parsedUnit.traverse(new AllMethodDeclarationVisitor(), parsedUnit.scope);
}
}
}
}
}
void reportMatchingMethod(
final String path,
final char[] packageDeclaration,
final char[] declaringQualifier,
final TypeDeclaration typeDeclaration,
final MethodDeclaration methodDeclaration,
final IType type,
final IRestrictedAccessMethodRequestor nameRequestor) {
Argument[] arguments = methodDeclaration.arguments;
int argsLength = 0;
char[][] parameterTypes = CharOperation.NO_CHAR_CHAR;
char[][] parameterNames = CharOperation.NO_CHAR_CHAR;
if (arguments != null) {
argsLength = arguments.length;
parameterTypes = new char[argsLength][];
parameterNames = new char[argsLength][];
}
for (int i = 0; i < argsLength; ++i) {
Argument argument = arguments[i];
parameterNames[i] = argument.name;
parameterTypes[i] = CharOperation.concatWith(argument.type.getTypeName(), '.');
}
if (nameRequestor instanceof MethodNameMatchRequestorWrapper) {
IMethod method = type.getMethod(new String(methodDeclaration.selector), CharOperation.toStrings(parameterTypes));
((MethodNameMatchRequestorWrapper)nameRequestor).requestor.acceptMethodNameMatch(new JavaSearchMethodNameMatch(method, methodDeclaration.modifiers));
} else {
char[] returnType = CharOperation.toString(methodDeclaration.returnType.getTypeName()).toCharArray();
nameRequestor.acceptMethod(
methodDeclaration.selector,
argsLength,
declaringQualifier,
typeDeclaration.name,
typeDeclaration.modifiers,
packageDeclaration,
null,
parameterTypes,
parameterNames,
returnType,
methodDeclaration.modifiers,
path,
null,
-1 /* method index */);
}
}
void reportMatchingMethods(final char[] methodName, final int methodMatchRule,
final IRestrictedAccessMethodRequestor nameRequestor, final String path, char[] packageDeclaration,
IType type, char[] rDeclaringQualification, char[] rSimpleName)
throws JavaModelException {
IMethod[] methods = type.getMethods();
for (int k = 0; k < methods.length; k++) {
IMethod method = methods[k];
if (method.isConstructor()) continue;
char[] rMethodName = method.getElementName().toCharArray();
if (match(methodName, methodMatchRule, rMethodName)) {
if (nameRequestor instanceof MethodNameMatchRequestorWrapper) {
((MethodNameMatchRequestorWrapper) nameRequestor).requestor.acceptMethodNameMatch(new JavaSearchMethodNameMatch(method, method.getFlags()));
} else {
String[] stringParameterNames = method.getParameterNames();
String[] stringParameterTypes = method.getParameterTypes();
int length = stringParameterNames.length;
char[][] parameterNames = new char[length][];
char[][] parameterTypes = new char[length][];
for (int l = 0; l < length; l++) {
parameterNames[l] = stringParameterNames[l].toCharArray();
parameterTypes[l] = Signature.toCharArray(Signature.getTypeErasure(stringParameterTypes[l]).toCharArray());
}
String returnSignature = method.getReturnType();
char[] signature = returnSignature.toCharArray();
char[] returnErasure = Signature.toCharArray(Signature.getTypeErasure(signature));
CharOperation.replace(returnErasure, '$', '.');
char[] returnTypeName = returnErasure;
nameRequestor.acceptMethod(
rMethodName,
parameterNames.length,
rDeclaringQualification,
rSimpleName,
type.getFlags(),
packageDeclaration,
null, // signature not used for source
parameterTypes,
parameterNames,
returnTypeName,
method.getFlags(),
path,
null,
k);
}
}
}
}
/**
* 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 JavaModelException {
try {
if (VERBOSE) {
trace("BasicSearchEngine.searchAllSecondaryTypeNames(IPackageFragmentRoot[], IRestrictedAccessTypeRequestor, boolean, IProgressMonitor)"); //$NON-NLS-1$
StringBuilder buffer = new StringBuilder(" - source folders: "); //$NON-NLS-1$
int length = sourceFolders.length;
for (int i=0; i workingCopyPaths = new HashSet<>();
String workingCopyPath = null;
ICompilationUnit[] 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++) {
ICompilationUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
@Override
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 {
SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 100);
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
createJavaSearchScope(sourceFolders),
searchRequestor),
waitForIndexes
? IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH
: IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH,
subMonitor.split(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 SearchEngine#searchAllTypeNames(char[], int, char[], int, int, IJavaSearchScope, TypeNameRequestor, int, IProgressMonitor)
* for detailed comment
*/
public void searchAllTypeNames(
final char[] packageName,
final int packageMatchRule,
final char[] typeName,
final int typeMatchRule,
int searchFor,
IJavaSearchScope scope,
final IRestrictedAccessTypeRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
searchAllTypeNames(
packageName,
packageMatchRule,
typeName,
typeMatchRule,
searchFor,
scope,
true,
nameRequestor,
waitingPolicy,
progressMonitor);
}
/**
* 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 resolveDocumentName used to tell SearchEngine whether to resolve
* the document name for each result entry.
*
* @see SearchEngine#searchAllTypeNames(char[], int, char[], int, int, IJavaSearchScope, TypeNameRequestor, int, IProgressMonitor)
* for detailed comment
*/
public void searchAllTypeNames(
final char[] packageName,
final int packageMatchRule,
final char[] typeName,
final int typeMatchRule,
int searchFor,
IJavaSearchScope scope,
final boolean resolveDocumentName,
final IRestrictedAccessTypeRequestor nameRequestor,
int waitingPolicy,
IProgressMonitor progressMonitor) throws JavaModelException {
try {
// Validate match rule first
final int validatedTypeMatchRule = SearchPattern.validateMatchRule(typeName == null ? null : new String (typeName), typeMatchRule);
// Debug
if (VERBOSE) {
trace("BasicSearchEngine.searchAllTypeNames(char[], char[], int, int, IJavaSearchScope, IRestrictedAccessTypeRequestor, int, IProgressMonitor)"); //$NON-NLS-1$
trace(" - package name: "+(packageName==null?"null":new String(packageName))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - package match rule: "+getMatchRuleString(packageMatchRule)); //$NON-NLS-1$
trace(" - type name: "+(typeName==null?"null":new String(typeName))); //$NON-NLS-1$ //$NON-NLS-2$
trace(" - type match rule: "+getMatchRuleString(typeMatchRule)); //$NON-NLS-1$
if (validatedTypeMatchRule != typeMatchRule) {
trace(" - validated type match rule: "+getMatchRuleString(validatedTypeMatchRule)); //$NON-NLS-1$
}
trace(" - search for: "+searchFor); //$NON-NLS-1$
trace(" - scope: "+scope); //$NON-NLS-1$
}
if (validatedTypeMatchRule == -1) return; // invalid match rule => return no results
// Create pattern
IndexManager indexManager = JavaModelManager.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.INTERFACE_AND_ANNOTATION :
typeSuffix = IIndexConstants.INTERFACE_AND_ANNOTATION_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 = packageMatchRule == SearchPattern.R_EXACT_MATCH
? new TypeDeclarationPattern(
packageName,
null,
typeName,
typeSuffix,
validatedTypeMatchRule)
: new QualifiedTypeDeclarationPattern(
packageName,
packageMatchRule,
typeName,
typeSuffix,
validatedTypeMatchRule);
// Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
Set workingCopyPaths = new HashSet<>();
String workingCopyPath = null;
ICompilationUnit[] 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++) {
ICompilationUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
@Override
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; // filter 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;
}
};
SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
resolveDocumentName,
true,
searchRequestor),
waitingPolicy,
subMonitor.split(Math.max(1000-copiesLength, 0)));
// add type names from working copies
if (copies != null) {
for (int i = 0; i < copiesLength; i++) {
SubMonitor iterationMonitor = subMonitor.split(i);
final ICompilationUnit workingCopy = copies[i];
if (scope instanceof HierarchyScope) {
if (!((HierarchyScope)scope).encloses(workingCopy, iterationMonitor)) continue;
} else {
if (!scope.encloses(workingCopy)) continue;
}
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 = TypeDeclaration.ENUM_DECL;
} else if (type.isAnnotation()) {
kind = TypeDeclaration.ANNOTATION_TYPE_DECL;
} else if (type.isClass() || type.isRecord()) {
kind = TypeDeclaration.CLASS_DECL;
} else /*if (type.isInterface())*/ {
kind = TypeDeclaration.INTERFACE_DECL;
}
if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, 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.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
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 {
@Override
public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
return false; // no local/anonymous type
}
@Override
public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, 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;
}
@Override
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, TypeDeclaration.kind(memberTypeDeclaration.modifiers), packageDeclaration, memberTypeDeclaration.name)) {
// compute enclosing 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 workingCopyPaths = new HashSet<>();
String workingCopyPath = null;
ICompilationUnit[] 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++) {
ICompilationUnit workingCopy = copies[i];
workingCopyPaths.add(workingCopy.getPath().toString());
}
}
}
final String singleWkcpPath = workingCopyPath;
// Index requestor
IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
@Override
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; // filter 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, '.', '/');
// Access rules work on package level and should not discriminate on enclosing types.
boolean isNestedType = record.enclosingTypeNames != null && record.enclosingTypeNames.length > 0;
path[qualificationLength-1] = isNestedType ? '$' : '/';
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;
}
};
SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 100);
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
getDefaultSearchParticipant(), // Java search only
scope,
searchRequestor),
waitingPolicy,
subMonitor.split(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();
org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
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 {
@Override
public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
return false; // no local/anonymous type
}
@Override
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;
}
@Override
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
// compute enclosing 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;
}
}
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 {
try {
if (VERBOSE) {
trace(" - java element: "+enclosingElement); //$NON-NLS-1$
}
IJavaSearchScope scope = createJavaSearchScope(new IJavaElement[] {enclosingElement});
IResource resource = ((JavaElement) enclosingElement).resource();
if (enclosingElement instanceof IMember) {
IMember member = (IMember) enclosingElement;
ICompilationUnit cu = member.getCompilationUnit();
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) {
trace("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);
}
} finally {
if (monitor != null) {
monitor.done();
}
}
}
/**
* Searches for all declarations of the fields accessed in the given element.
* The element can be a compilation unit or a source type/method/field.
* Reports the field declarations using the given requestor.
*
* @see SearchEngine#searchDeclarationsOfAccessedFields(IJavaElement, SearchRequestor, IProgressMonitor)
* for detailed comment
*/
public void searchDeclarationsOfAccessedFields(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
if (VERBOSE) {
trace("BasicSearchEngine.searchDeclarationsOfAccessedFields(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
}
// Do not accept other kind of element type than those specified in the spec
switch (enclosingElement.getElementType()) {
case IJavaElement.FIELD:
case IJavaElement.METHOD:
case IJavaElement.TYPE:
case IJavaElement.COMPILATION_UNIT:
// valid element type
break;
default:
throw new IllegalArgumentException();
}
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 or a source type/method/field.
* Reports the type declarations using the given requestor.
*
* @see SearchEngine#searchDeclarationsOfReferencedTypes(IJavaElement, SearchRequestor, IProgressMonitor)
* for detailed comment
*/
public void searchDeclarationsOfReferencedTypes(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
if (VERBOSE) {
trace("BasicSearchEngine.searchDeclarationsOfReferencedTypes(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
}
// Do not accept other kind of element type than those specified in the spec
switch (enclosingElement.getElementType()) {
case IJavaElement.FIELD:
case IJavaElement.METHOD:
case IJavaElement.TYPE:
case IJavaElement.COMPILATION_UNIT:
// valid element type
break;
default:
throw new IllegalArgumentException();
}
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 or a source type/method/field.
* Reports the method declarations using the given requestor.
*
* @see SearchEngine#searchDeclarationsOfSentMessages(IJavaElement, SearchRequestor, IProgressMonitor)
* for detailed comment
*/
public void searchDeclarationsOfSentMessages(IJavaElement enclosingElement, SearchRequestor requestor, IProgressMonitor monitor) throws JavaModelException {
if (VERBOSE) {
trace("BasicSearchEngine.searchDeclarationsOfSentMessages(IJavaElement, SearchRequestor, SearchPattern, IProgressMonitor)"); //$NON-NLS-1$
}
// Do not accept other kind of element type than those specified in the spec
switch (enclosingElement.getElementType()) {
case IJavaElement.FIELD:
case IJavaElement.METHOD:
case IJavaElement.TYPE:
case IJavaElement.COMPILATION_UNIT:
// valid element type
break;
default:
throw new IllegalArgumentException();
}
SearchPattern pattern = new DeclarationOfReferencedMethodsPattern(enclosingElement);
searchDeclarations(enclosingElement, requestor, pattern, monitor);
}
}