package org.eclipse.jdt.internal.core.search.matching; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved. | |
*/ | |
import org.eclipse.core.resources.*; | |
import org.eclipse.core.runtime.*; | |
import org.eclipse.jdt.core.*; | |
import org.eclipse.jdt.internal.core.BinaryType; | |
import org.eclipse.jdt.internal.core.CompilationUnit; | |
import org.eclipse.jdt.internal.core.JavaModelManager; | |
import org.eclipse.jdt.internal.core.Openable; | |
import org.eclipse.jdt.internal.core.SourceType; | |
import org.eclipse.jdt.internal.core.index.*; | |
import org.eclipse.jdt.core.compiler.*; | |
import org.eclipse.jdt.core.compiler.ITerminalSymbols; | |
import org.eclipse.jdt.core.compiler.InvalidInputException; | |
import org.eclipse.jdt.core.search.*; | |
import org.eclipse.jdt.internal.compiler.ast.*; | |
import org.eclipse.jdt.internal.compiler.env.IBinaryType; | |
import org.eclipse.jdt.internal.compiler.env.ISourceType; | |
import org.eclipse.jdt.internal.compiler.lookup.*; | |
import org.eclipse.jdt.internal.compiler.parser.Scanner; | |
import org.eclipse.jdt.internal.compiler.util.*; | |
import org.eclipse.jdt.internal.core.index.impl.IndexInput; | |
import org.eclipse.jdt.internal.core.index.impl.IndexedFile; | |
import org.eclipse.jdt.internal.core.index.impl.BlocksIndexInput; | |
import org.eclipse.jdt.internal.core.search.*; | |
import org.eclipse.jdt.internal.core.search.indexing.*; | |
import java.io.*; | |
import java.util.*; | |
public abstract class SearchPattern implements ISearchPattern, IIndexConstants, IJavaSearchConstants { | |
protected int matchMode; | |
protected boolean isCaseSensitive; | |
protected boolean needsResolve = true; | |
/* match level */ | |
public static final int IMPOSSIBLE_MATCH = 0; | |
public static final int POSSIBLE_MATCH = 1; | |
public static final int ACCURATE_MATCH = 2; | |
public static final int INACCURATE_MATCH = 3; | |
/* match container */ | |
public static final int COMPILATION_UNIT = 1; | |
public static final int CLASS = 2; | |
public static final int FIELD = 4; | |
public static final int METHOD = 8; | |
public SearchPattern(int matchMode, boolean isCaseSensitive) { | |
this.matchMode = matchMode; | |
this.isCaseSensitive = isCaseSensitive; | |
} | |
/** | |
* Constructor pattern are formed by [declaringQualification.]type[(parameterTypes)] | |
* e.g. java.lang.Object() | |
* Main(*) | |
*/ | |
private static SearchPattern createConstructorPattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) { | |
Scanner scanner = new Scanner(false, true); // tokenize white spaces | |
scanner.setSource(patternString.toCharArray()); | |
final int InsideName = 1; | |
final int InsideParameter = 2; | |
String declaringQualification = null, typeName = null, parameterType = null; | |
String[] parameterTypes = null; | |
int parameterCount = -1; | |
boolean foundClosingParenthesis = false; | |
int mode = InsideName; | |
int token; | |
try { | |
token = scanner.getNextToken(); | |
} catch (InvalidInputException e) { | |
return null; | |
} | |
while (token != ITerminalSymbols.TokenNameEOF){ | |
switch(mode){ | |
// read declaring type and selector | |
case InsideName : | |
switch (token) { | |
case ITerminalSymbols.TokenNameDOT: | |
if (declaringQualification == null){ | |
if (typeName == null) return null; | |
declaringQualification = typeName; | |
} else { | |
String tokenSource = new String(scanner.getCurrentTokenSource()); | |
declaringQualification += tokenSource + typeName; | |
} | |
typeName = null; | |
break; | |
case ITerminalSymbols.TokenNameLPAREN: | |
parameterTypes = new String[5]; | |
parameterCount = 0; | |
mode = InsideParameter; | |
break; | |
case Scanner.TokenNameWHITESPACE: | |
break; | |
case ITerminalSymbols.TokenNameIdentifier: | |
case ITerminalSymbols.TokenNameMULTIPLY: | |
if (typeName == null) { | |
typeName = new String(scanner.getCurrentTokenSource()); | |
} else { | |
typeName += new String(scanner.getCurrentTokenSource()); | |
} | |
break; | |
default: | |
return null; | |
} | |
break; | |
// read parameter types | |
case InsideParameter : | |
switch (token) { | |
case Scanner.TokenNameWHITESPACE: | |
break; | |
case ITerminalSymbols.TokenNameCOMMA: | |
if (parameterType == null) return null; | |
if (parameterTypes.length == parameterCount){ | |
System.arraycopy(parameterTypes, 0, parameterTypes = new String[parameterCount*2], 0, parameterCount); | |
} | |
parameterTypes[parameterCount++] = parameterType; | |
parameterType = null; | |
break; | |
case ITerminalSymbols.TokenNameRPAREN: | |
foundClosingParenthesis = true; | |
if (parameterType != null){ | |
if (parameterTypes.length == parameterCount){ | |
System.arraycopy(parameterTypes, 0, parameterTypes = new String[parameterCount*2], 0, parameterCount); | |
} | |
parameterTypes[parameterCount++] = parameterType; | |
} | |
break; | |
case ITerminalSymbols.TokenNameDOT: | |
case ITerminalSymbols.TokenNameIdentifier: | |
case ITerminalSymbols.TokenNameMULTIPLY: | |
case ITerminalSymbols.TokenNameLBRACKET: | |
case ITerminalSymbols.TokenNameRBRACKET: | |
case ITerminalSymbols.TokenNameboolean: | |
case ITerminalSymbols.TokenNamebyte: | |
case ITerminalSymbols.TokenNamechar: | |
case ITerminalSymbols.TokenNamedouble: | |
case ITerminalSymbols.TokenNamefloat: | |
case ITerminalSymbols.TokenNameint: | |
case ITerminalSymbols.TokenNamelong: | |
case ITerminalSymbols.TokenNameshort: | |
case ITerminalSymbols.TokenNamevoid: | |
if (parameterType == null){ | |
parameterType = new String(scanner.getCurrentTokenSource()); | |
} else { | |
parameterType += new String(scanner.getCurrentTokenSource()); | |
} | |
break; | |
default: | |
return null; | |
} | |
break; | |
} | |
try { | |
token = scanner.getNextToken(); | |
} catch (InvalidInputException e) { | |
return null; | |
} | |
} | |
// parenthesis mismatch | |
if (parameterCount>0 && !foundClosingParenthesis) return null; | |
if (typeName == null) return null; | |
char[] typeNameChars = typeName.toCharArray(); | |
if (typeNameChars.length == 1 && typeNameChars[0] == '*') typeNameChars = null; | |
char[] declaringQualificationChars = null; | |
if (declaringQualification != null) declaringQualificationChars = declaringQualification.toCharArray(); | |
char[][] parameterTypeQualifications = null, parameterTypeSimpleNames = null; | |
// extract parameter types infos | |
if (parameterCount >= 0){ | |
parameterTypeQualifications = new char[parameterCount][]; | |
parameterTypeSimpleNames = new char[parameterCount][]; | |
for (int i = 0; i < parameterCount; i++){ | |
char[] parameterTypePart = parameterTypes[i].toCharArray(); | |
int lastDotPosition = CharOperation.lastIndexOf('.', parameterTypePart); | |
if (lastDotPosition >= 0){ | |
parameterTypeQualifications[i] = CharOperation.subarray(parameterTypePart, 0, lastDotPosition); | |
if (parameterTypeQualifications[i].length == 1 && parameterTypeQualifications[i][0] == '*') { | |
parameterTypeQualifications[i] = null; | |
} else { | |
// prefix with a '*' as the full qualification could be bigger | |
// (i.e. because of an import) | |
parameterTypeQualifications[i] = CharOperation.concat(ONE_STAR, parameterTypeQualifications[i]); | |
} | |
parameterTypeSimpleNames[i] = CharOperation.subarray(parameterTypePart, lastDotPosition+1, parameterTypePart.length); | |
} else { | |
parameterTypeQualifications[i] = null; | |
parameterTypeSimpleNames[i] = parameterTypePart; | |
} | |
if (parameterTypeSimpleNames[i].length == 1 && parameterTypeSimpleNames[i][0] == '*') parameterTypeSimpleNames[i] = null; | |
} | |
} | |
SearchPattern searchPattern = null; | |
switch (limitTo){ | |
case IJavaSearchConstants.DECLARATIONS : | |
searchPattern = | |
new ConstructorDeclarationPattern( | |
typeNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringQualificationChars, | |
parameterTypeQualifications, | |
parameterTypeSimpleNames); | |
break; | |
case IJavaSearchConstants.REFERENCES : | |
searchPattern = | |
new ConstructorReferencePattern( | |
typeNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringQualificationChars, | |
parameterTypeQualifications, | |
parameterTypeSimpleNames, | |
null); | |
break; | |
case IJavaSearchConstants.ALL_OCCURRENCES : | |
searchPattern = new OrPattern( | |
new ConstructorDeclarationPattern( | |
typeNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringQualificationChars, | |
parameterTypeQualifications, | |
parameterTypeSimpleNames), | |
new ConstructorReferencePattern( | |
typeNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringQualificationChars, | |
parameterTypeQualifications, | |
parameterTypeSimpleNames, | |
null)); | |
break; | |
} | |
return searchPattern; | |
} | |
/** | |
* Field pattern are formed by [declaringType.]name[type] | |
* e.g. java.lang.String.serialVersionUID long | |
* field* | |
*/ | |
private static SearchPattern createFieldPattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) { | |
Scanner scanner = new Scanner(false, true); // tokenize white spaces | |
scanner.setSource(patternString.toCharArray()); | |
final int InsideDeclaringPart = 1; | |
final int InsideType = 2; | |
int lastToken = -1; | |
String declaringType = null, fieldName = null; | |
String type = null; | |
int mode = InsideDeclaringPart; | |
int token; | |
try { | |
token = scanner.getNextToken(); | |
} catch (InvalidInputException e) { | |
return null; | |
} | |
while (token != ITerminalSymbols.TokenNameEOF){ | |
switch(mode){ | |
// read declaring type and fieldName | |
case InsideDeclaringPart : | |
switch (token) { | |
case ITerminalSymbols.TokenNameDOT: | |
if (declaringType == null){ | |
if (fieldName == null) return null; | |
declaringType = fieldName; | |
} else { | |
String tokenSource = new String(scanner.getCurrentTokenSource()); | |
declaringType += tokenSource + fieldName; | |
} | |
fieldName = null; | |
break; | |
case Scanner.TokenNameWHITESPACE: | |
if (!(Scanner.TokenNameWHITESPACE == lastToken | |
|| ITerminalSymbols.TokenNameDOT == lastToken)){ | |
mode = InsideType; | |
} | |
break; | |
case ITerminalSymbols.TokenNameIdentifier: | |
case ITerminalSymbols.TokenNameMULTIPLY: | |
if (fieldName == null) { | |
fieldName = new String(scanner.getCurrentTokenSource()); | |
} else { | |
fieldName += new String(scanner.getCurrentTokenSource()); | |
} | |
break; | |
default: | |
return null; | |
} | |
break; | |
// read type | |
case InsideType: | |
switch (token) { | |
case Scanner.TokenNameWHITESPACE: | |
break; | |
case ITerminalSymbols.TokenNameDOT: | |
case ITerminalSymbols.TokenNameIdentifier: | |
case ITerminalSymbols.TokenNameMULTIPLY: | |
case ITerminalSymbols.TokenNameLBRACKET: | |
case ITerminalSymbols.TokenNameRBRACKET: | |
case ITerminalSymbols.TokenNameboolean: | |
case ITerminalSymbols.TokenNamebyte: | |
case ITerminalSymbols.TokenNamechar: | |
case ITerminalSymbols.TokenNamedouble: | |
case ITerminalSymbols.TokenNamefloat: | |
case ITerminalSymbols.TokenNameint: | |
case ITerminalSymbols.TokenNamelong: | |
case ITerminalSymbols.TokenNameshort: | |
case ITerminalSymbols.TokenNamevoid: | |
if (type == null){ | |
type = new String(scanner.getCurrentTokenSource()); | |
} else { | |
type += new String(scanner.getCurrentTokenSource()); | |
} | |
break; | |
default: | |
return null; | |
} | |
break; | |
} | |
lastToken = token; | |
try { | |
token = scanner.getNextToken(); | |
} catch (InvalidInputException e) { | |
return null; | |
} | |
} | |
if (fieldName == null) return null; | |
char[] fieldNameChars = fieldName.toCharArray(); | |
if (fieldNameChars.length == 1 && fieldNameChars[0] == '*') fieldNameChars = null; | |
char[] declaringTypeQualification = null, declaringTypeSimpleName = null; | |
char[] typeQualification = null, typeSimpleName = null; | |
// extract declaring type infos | |
if (declaringType != null){ | |
char[] declaringTypePart = declaringType.toCharArray(); | |
int lastDotPosition = CharOperation.lastIndexOf('.', declaringTypePart); | |
if (lastDotPosition >= 0){ | |
declaringTypeQualification = CharOperation.subarray(declaringTypePart, 0, lastDotPosition); | |
if (declaringTypeQualification.length == 1 && declaringTypeQualification[0] == '*') declaringTypeQualification = null; | |
declaringTypeSimpleName = CharOperation.subarray(declaringTypePart, lastDotPosition+1, declaringTypePart.length); | |
} else { | |
declaringTypeQualification = null; | |
declaringTypeSimpleName = declaringTypePart; | |
} | |
if (declaringTypeSimpleName.length == 1 && declaringTypeSimpleName[0] == '*') declaringTypeSimpleName = null; | |
} | |
// extract type infos | |
if (type != null){ | |
char[] typePart = type.toCharArray(); | |
int lastDotPosition = CharOperation.lastIndexOf('.', typePart); | |
if (lastDotPosition >= 0){ | |
typeQualification = CharOperation.subarray(typePart, 0, lastDotPosition); | |
if (typeQualification.length == 1 && typeQualification[0] == '*') { | |
typeQualification = null; | |
} else { | |
// prefix with a '*' as the full qualification could be bigger | |
// (i.e. because of an import) | |
typeQualification = CharOperation.concat(ONE_STAR, typeQualification); | |
} | |
typeSimpleName = CharOperation.subarray(typePart, lastDotPosition+1, typePart.length); | |
} else { | |
typeQualification = null; | |
typeSimpleName = typePart; | |
} | |
if (typeSimpleName.length == 1 && typeSimpleName[0] == '*') typeSimpleName = null; | |
} | |
SearchPattern searchPattern = null; | |
switch (limitTo){ | |
case IJavaSearchConstants.DECLARATIONS : | |
searchPattern = | |
new FieldDeclarationPattern( | |
fieldNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
typeQualification, | |
typeSimpleName); | |
break; | |
case IJavaSearchConstants.REFERENCES : | |
searchPattern = | |
new FieldReferencePattern( | |
fieldNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
typeQualification, | |
typeSimpleName, | |
true, // read access | |
true); // write access | |
break; | |
case IJavaSearchConstants.READ_ACCESSES : | |
searchPattern = | |
new FieldReferencePattern( | |
fieldNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
typeQualification, | |
typeSimpleName, | |
true, // read access only | |
false); | |
break; | |
case IJavaSearchConstants.WRITE_ACCESSES : | |
searchPattern = | |
new FieldReferencePattern( | |
fieldNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
typeQualification, | |
typeSimpleName, | |
false, | |
true); // write access only | |
break; | |
case IJavaSearchConstants.ALL_OCCURRENCES : | |
searchPattern = new OrPattern( | |
new FieldDeclarationPattern( | |
fieldNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
typeQualification, | |
typeSimpleName), | |
new FieldReferencePattern( | |
fieldNameChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
typeQualification, | |
typeSimpleName, | |
true, // read access | |
true)); // write access | |
break; | |
} | |
return searchPattern; | |
} | |
/** | |
* Method pattern are formed by [declaringType.]selector[(parameterTypes)][returnType] | |
* e.g. java.lang.Runnable.run() void | |
* main(*) | |
*/ | |
private static SearchPattern createMethodPattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) { | |
Scanner scanner = new Scanner(false, true); // tokenize white spaces | |
scanner.setSource(patternString.toCharArray()); | |
final int InsideSelector = 1; | |
final int InsideParameter = 2; | |
final int InsideReturnType = 3; | |
int lastToken = -1; | |
String declaringType = null, selector = null, parameterType = null; | |
String[] parameterTypes = null; | |
int parameterCount = -1; | |
String returnType = null; | |
boolean foundClosingParenthesis = false; | |
int mode = InsideSelector; | |
int token; | |
try { | |
token = scanner.getNextToken(); | |
} catch (InvalidInputException e) { | |
return null; | |
} | |
while (token != ITerminalSymbols.TokenNameEOF){ | |
switch(mode){ | |
// read declaring type and selector | |
case InsideSelector : | |
switch (token) { | |
case ITerminalSymbols.TokenNameDOT: | |
if (declaringType == null){ | |
if (selector == null) return null; | |
declaringType = selector; | |
} else { | |
String tokenSource = new String(scanner.getCurrentTokenSource()); | |
declaringType += tokenSource + selector; | |
} | |
selector = null; | |
break; | |
case ITerminalSymbols.TokenNameLPAREN: | |
parameterTypes = new String[5]; | |
parameterCount = 0; | |
mode = InsideParameter; | |
break; | |
case Scanner.TokenNameWHITESPACE: | |
if (!(Scanner.TokenNameWHITESPACE == lastToken | |
|| ITerminalSymbols.TokenNameDOT == lastToken)){ | |
mode = InsideReturnType; | |
} | |
break; | |
case ITerminalSymbols.TokenNameIdentifier: | |
case ITerminalSymbols.TokenNameMULTIPLY: | |
if (selector == null) { | |
selector = new String(scanner.getCurrentTokenSource()); | |
} else { | |
selector += new String(scanner.getCurrentTokenSource()); | |
} | |
break; | |
default: | |
return null; | |
} | |
break; | |
// read parameter types | |
case InsideParameter : | |
switch (token) { | |
case Scanner.TokenNameWHITESPACE: | |
break; | |
case ITerminalSymbols.TokenNameCOMMA: | |
if (parameterType == null) return null; | |
if (parameterTypes.length == parameterCount){ | |
System.arraycopy(parameterTypes, 0, parameterTypes = new String[parameterCount*2], 0, parameterCount); | |
} | |
parameterTypes[parameterCount++] = parameterType; | |
parameterType = null; | |
break; | |
case ITerminalSymbols.TokenNameRPAREN: | |
foundClosingParenthesis = true; | |
if (parameterType != null){ | |
if (parameterTypes.length == parameterCount){ | |
System.arraycopy(parameterTypes, 0, parameterTypes = new String[parameterCount*2], 0, parameterCount); | |
} | |
parameterTypes[parameterCount++] = parameterType; | |
} | |
mode = InsideReturnType; | |
break; | |
case ITerminalSymbols.TokenNameDOT: | |
case ITerminalSymbols.TokenNameIdentifier: | |
case ITerminalSymbols.TokenNameMULTIPLY: | |
case ITerminalSymbols.TokenNameLBRACKET: | |
case ITerminalSymbols.TokenNameRBRACKET: | |
case ITerminalSymbols.TokenNameboolean: | |
case ITerminalSymbols.TokenNamebyte: | |
case ITerminalSymbols.TokenNamechar: | |
case ITerminalSymbols.TokenNamedouble: | |
case ITerminalSymbols.TokenNamefloat: | |
case ITerminalSymbols.TokenNameint: | |
case ITerminalSymbols.TokenNamelong: | |
case ITerminalSymbols.TokenNameshort: | |
case ITerminalSymbols.TokenNamevoid: | |
if (parameterType == null){ | |
parameterType = new String(scanner.getCurrentTokenSource()); | |
} else { | |
parameterType += new String(scanner.getCurrentTokenSource()); | |
} | |
break; | |
default: | |
return null; | |
} | |
break; | |
// read return type | |
case InsideReturnType: | |
switch (token) { | |
case Scanner.TokenNameWHITESPACE: | |
break; | |
case ITerminalSymbols.TokenNameDOT: | |
case ITerminalSymbols.TokenNameIdentifier: | |
case ITerminalSymbols.TokenNameMULTIPLY: | |
case ITerminalSymbols.TokenNameLBRACKET: | |
case ITerminalSymbols.TokenNameRBRACKET: | |
case ITerminalSymbols.TokenNameboolean: | |
case ITerminalSymbols.TokenNamebyte: | |
case ITerminalSymbols.TokenNamechar: | |
case ITerminalSymbols.TokenNamedouble: | |
case ITerminalSymbols.TokenNamefloat: | |
case ITerminalSymbols.TokenNameint: | |
case ITerminalSymbols.TokenNamelong: | |
case ITerminalSymbols.TokenNameshort: | |
case ITerminalSymbols.TokenNamevoid: | |
if (returnType == null){ | |
returnType = new String(scanner.getCurrentTokenSource()); | |
} else { | |
returnType += new String(scanner.getCurrentTokenSource()); | |
} | |
break; | |
default: | |
return null; | |
} | |
break; | |
} | |
lastToken = token; | |
try { | |
token = scanner.getNextToken(); | |
} catch (InvalidInputException e) { | |
return null; | |
} | |
} | |
// parenthesis mismatch | |
if (parameterCount>0 && !foundClosingParenthesis) return null; | |
if (selector == null) return null; | |
char[] selectorChars = selector.toCharArray(); | |
if (selectorChars.length == 1 && selectorChars[0] == '*') selectorChars = null; | |
char[] declaringTypeQualification = null, declaringTypeSimpleName = null; | |
char[] returnTypeQualification = null, returnTypeSimpleName = null; | |
char[][] parameterTypeQualifications = null, parameterTypeSimpleNames = null; | |
// extract declaring type infos | |
if (declaringType != null){ | |
char[] declaringTypePart = declaringType.toCharArray(); | |
int lastDotPosition = CharOperation.lastIndexOf('.', declaringTypePart); | |
if (lastDotPosition >= 0){ | |
declaringTypeQualification = CharOperation.subarray(declaringTypePart, 0, lastDotPosition); | |
if (declaringTypeQualification.length == 1 && declaringTypeQualification[0] == '*') declaringTypeQualification = null; | |
declaringTypeSimpleName = CharOperation.subarray(declaringTypePart, lastDotPosition+1, declaringTypePart.length); | |
} else { | |
declaringTypeQualification = null; | |
declaringTypeSimpleName = declaringTypePart; | |
} | |
if (declaringTypeSimpleName.length == 1 && declaringTypeSimpleName[0] == '*') declaringTypeSimpleName = null; | |
} | |
// extract parameter types infos | |
if (parameterCount >= 0){ | |
parameterTypeQualifications = new char[parameterCount][]; | |
parameterTypeSimpleNames = new char[parameterCount][]; | |
for (int i = 0; i < parameterCount; i++){ | |
char[] parameterTypePart = parameterTypes[i].toCharArray(); | |
int lastDotPosition = CharOperation.lastIndexOf('.', parameterTypePart); | |
if (lastDotPosition >= 0){ | |
parameterTypeQualifications[i] = CharOperation.subarray(parameterTypePart, 0, lastDotPosition); | |
if (parameterTypeQualifications[i].length == 1 && parameterTypeQualifications[i][0] == '*') { | |
parameterTypeQualifications[i] = null; | |
} else { | |
// prefix with a '*' as the full qualification could be bigger | |
// (i.e. because of an import) | |
parameterTypeQualifications[i] = CharOperation.concat(ONE_STAR, parameterTypeQualifications[i]); | |
} | |
parameterTypeSimpleNames[i] = CharOperation.subarray(parameterTypePart, lastDotPosition+1, parameterTypePart.length); | |
} else { | |
parameterTypeQualifications[i] = null; | |
parameterTypeSimpleNames[i] = parameterTypePart; | |
} | |
if (parameterTypeSimpleNames[i].length == 1 && parameterTypeSimpleNames[i][0] == '*') parameterTypeSimpleNames[i] = null; | |
} | |
} | |
// extract return type infos | |
if (returnType != null){ | |
char[] returnTypePart = returnType.toCharArray(); | |
int lastDotPosition = CharOperation.lastIndexOf('.', returnTypePart); | |
if (lastDotPosition >= 0){ | |
returnTypeQualification = CharOperation.subarray(returnTypePart, 0, lastDotPosition); | |
if (returnTypeQualification.length == 1 && returnTypeQualification[0] == '*') { | |
returnTypeQualification = null; | |
} else { | |
// (i.e. because of an import) | |
returnTypeQualification = CharOperation.concat(ONE_STAR, returnTypeQualification); | |
} | |
returnTypeSimpleName = CharOperation.subarray(returnTypePart, lastDotPosition+1, returnTypePart.length); | |
} else { | |
returnTypeQualification = null; | |
returnTypeSimpleName = returnTypePart; | |
} | |
if (returnTypeSimpleName.length == 1 && returnTypeSimpleName[0] == '*') returnTypeSimpleName = null; | |
} | |
SearchPattern searchPattern = null; | |
switch (limitTo){ | |
case IJavaSearchConstants.DECLARATIONS : | |
searchPattern = | |
new MethodDeclarationPattern( | |
selectorChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
returnTypeQualification, | |
returnTypeSimpleName, | |
parameterTypeQualifications, | |
parameterTypeSimpleNames); | |
break; | |
case IJavaSearchConstants.REFERENCES : | |
searchPattern = | |
new MethodReferencePattern( | |
selectorChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
returnTypeQualification, | |
returnTypeSimpleName, | |
parameterTypeQualifications, | |
parameterTypeSimpleNames, | |
null); | |
break; | |
case IJavaSearchConstants.ALL_OCCURRENCES : | |
searchPattern = new OrPattern( | |
new MethodDeclarationPattern( | |
selectorChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
returnTypeQualification, | |
returnTypeSimpleName, | |
parameterTypeQualifications, | |
parameterTypeSimpleNames), | |
new MethodReferencePattern( | |
selectorChars, | |
matchMode, | |
isCaseSensitive, | |
declaringTypeQualification, | |
declaringTypeSimpleName, | |
returnTypeQualification, | |
returnTypeSimpleName, | |
parameterTypeQualifications, | |
parameterTypeSimpleNames, | |
null)); | |
break; | |
} | |
return searchPattern; | |
} | |
private static SearchPattern createPackagePattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) { | |
SearchPattern searchPattern = null; | |
switch (limitTo){ | |
case IJavaSearchConstants.DECLARATIONS : | |
searchPattern = new PackageDeclarationPattern(patternString.toCharArray(), matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.REFERENCES : | |
searchPattern = new PackageReferencePattern(patternString.toCharArray(), matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.ALL_OCCURRENCES : | |
searchPattern = new OrPattern( | |
new PackageDeclarationPattern(patternString.toCharArray(), matchMode, isCaseSensitive), | |
new PackageReferencePattern(patternString.toCharArray(), matchMode, isCaseSensitive) | |
); | |
break; | |
} | |
return searchPattern; | |
} | |
public static SearchPattern createPattern(String patternString, int searchFor, int limitTo, int matchMode, boolean isCaseSensitive) { | |
if (patternString == null || patternString.length() == 0) | |
return null; | |
SearchPattern searchPattern = null; | |
switch (searchFor) { | |
case IJavaSearchConstants.TYPE: | |
searchPattern = createTypePattern(patternString, limitTo, matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.METHOD: | |
searchPattern = createMethodPattern(patternString, limitTo, matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.CONSTRUCTOR: | |
searchPattern = createConstructorPattern(patternString, limitTo, matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.FIELD: | |
searchPattern = createFieldPattern(patternString, limitTo, matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.PACKAGE: | |
searchPattern = createPackagePattern(patternString, limitTo, matchMode, isCaseSensitive); | |
} | |
return searchPattern; | |
} | |
public static SearchPattern createPattern(IJavaElement element, int limitTo) { | |
SearchPattern searchPattern = null; | |
int lastDot; | |
switch (element.getElementType()) { | |
case IJavaElement.FIELD : | |
IField field = (IField) element; | |
String fullDeclaringName = field.getDeclaringType().getFullyQualifiedName().replace('$', '.'); | |
lastDot = fullDeclaringName.lastIndexOf('.'); | |
char[] declaringSimpleName = (lastDot != -1 ? fullDeclaringName.substring(lastDot + 1) : fullDeclaringName).toCharArray(); | |
char[] declaringQualification = lastDot != -1 ? fullDeclaringName.substring(0, lastDot).toCharArray() : NO_CHAR; | |
char[] name = field.getElementName().toCharArray(); | |
char[] typeSimpleName; | |
char[] typeQualification; | |
try { | |
String typeSignature = Signature.toString(field.getTypeSignature()).replace('$', '.'); | |
lastDot = typeSignature.lastIndexOf('.'); | |
typeSimpleName = (lastDot != -1 ? typeSignature.substring(lastDot + 1) : typeSignature).toCharArray(); | |
typeQualification = | |
lastDot != -1 ? | |
// prefix with a '*' as the full qualification could be bigger | |
// (i.e. because of an import) | |
CharOperation.concat(ONE_STAR, typeSignature.substring(0, lastDot).toCharArray()) : | |
null; | |
} catch (JavaModelException e) { | |
return null; | |
} | |
switch (limitTo) { | |
case IJavaSearchConstants.DECLARATIONS : | |
searchPattern = | |
new FieldDeclarationPattern( | |
name, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
typeQualification, | |
typeSimpleName); | |
break; | |
case IJavaSearchConstants.REFERENCES : | |
searchPattern = | |
new FieldReferencePattern( | |
name, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
typeQualification, | |
typeSimpleName, | |
true, // read access | |
true); // write access | |
break; | |
case IJavaSearchConstants.READ_ACCESSES : | |
searchPattern = | |
new FieldReferencePattern( | |
name, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
typeQualification, | |
typeSimpleName, | |
true, // read access only | |
false); | |
break; | |
case IJavaSearchConstants.WRITE_ACCESSES : | |
searchPattern = | |
new FieldReferencePattern( | |
name, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
typeQualification, | |
typeSimpleName, | |
false, | |
true); // write access only | |
break; | |
case IJavaSearchConstants.ALL_OCCURRENCES : | |
searchPattern = new OrPattern( | |
new FieldDeclarationPattern( | |
name, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
typeQualification, | |
typeSimpleName), | |
new FieldReferencePattern( | |
name, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
typeQualification, | |
typeSimpleName, | |
true, // read access | |
true)); // write access | |
break; | |
} | |
break; | |
case IJavaElement.IMPORT_DECLARATION : | |
String elementName = element.getElementName(); | |
lastDot = elementName.lastIndexOf('.'); | |
if (lastDot == -1) return null; // invalid import declaration | |
IImportDeclaration importDecl = (IImportDeclaration)element; | |
if (importDecl.isOnDemand()) { | |
searchPattern = createPackagePattern(elementName.substring(0, lastDot), limitTo, EXACT_MATCH, CASE_SENSITIVE); | |
} else { | |
searchPattern = | |
createTypePattern( | |
elementName.substring(lastDot+1).toCharArray(), | |
elementName.substring(0, lastDot).toCharArray(), | |
null, | |
limitTo); | |
} | |
break; | |
case IJavaElement.METHOD : | |
IMethod method = (IMethod) element; | |
boolean isConstructor; | |
try { | |
isConstructor = method.isConstructor(); | |
} catch (JavaModelException e) { | |
return null; | |
} | |
fullDeclaringName = method.getDeclaringType().getFullyQualifiedName().replace('$', '.'); | |
lastDot = fullDeclaringName.lastIndexOf('.'); | |
declaringSimpleName = (lastDot != -1 ? fullDeclaringName.substring(lastDot + 1) : fullDeclaringName).toCharArray(); | |
declaringQualification = lastDot != -1 ? fullDeclaringName.substring(0, lastDot).toCharArray() : NO_CHAR; | |
char[] selector = method.getElementName().toCharArray(); | |
char[] returnSimpleName; | |
char[] returnQualification; | |
try { | |
String returnType = Signature.toString(method.getReturnType()).replace('$', '.'); | |
lastDot = returnType.lastIndexOf('.'); | |
returnSimpleName = (lastDot != -1 ? returnType.substring(lastDot + 1) : returnType).toCharArray(); | |
returnQualification = | |
lastDot != -1 ? | |
// prefix with a '*' as the full qualification could be bigger | |
// (i.e. because of an import) | |
CharOperation.concat(ONE_STAR, returnType.substring(0, lastDot).toCharArray()) : | |
null; | |
} catch (JavaModelException e) { | |
return null; | |
} | |
String[] parameterTypes = method.getParameterTypes(); | |
int paramCount = parameterTypes.length; | |
char[][] parameterSimpleNames = new char[paramCount][]; | |
char[][] parameterQualifications = new char[paramCount][]; | |
for (int i = 0; i < paramCount; i++) { | |
String signature = Signature.toString(parameterTypes[i]).replace('$', '.'); | |
lastDot = signature.lastIndexOf('.'); | |
parameterSimpleNames[i] = (lastDot != -1 ? signature.substring(lastDot + 1) : signature).toCharArray(); | |
parameterQualifications[i] = | |
lastDot != -1 ? | |
// prefix with a '*' as the full qualification could be bigger | |
// (i.e. because of an import) | |
CharOperation.concat(ONE_STAR, signature.substring(0, lastDot).toCharArray()) : | |
null; | |
} | |
switch (limitTo) { | |
case IJavaSearchConstants.DECLARATIONS : | |
if (isConstructor) { | |
searchPattern = | |
new ConstructorDeclarationPattern( | |
declaringSimpleName, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
parameterQualifications, | |
parameterSimpleNames); | |
} else { | |
searchPattern = | |
new MethodDeclarationPattern( | |
selector, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
returnQualification, | |
returnSimpleName, | |
parameterQualifications, | |
parameterSimpleNames); | |
} | |
break; | |
case IJavaSearchConstants.REFERENCES : | |
if (isConstructor) { | |
searchPattern = | |
new ConstructorReferencePattern( | |
declaringSimpleName, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
parameterQualifications, | |
parameterSimpleNames, | |
method.getDeclaringType()); | |
} else { | |
searchPattern = | |
new MethodReferencePattern( | |
selector, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
returnQualification, | |
returnSimpleName, | |
parameterQualifications, | |
parameterSimpleNames, | |
method.getDeclaringType()); | |
} | |
break; | |
case IJavaSearchConstants.ALL_OCCURRENCES : | |
if (isConstructor) { | |
searchPattern = new OrPattern( | |
new ConstructorDeclarationPattern( | |
declaringSimpleName, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
parameterQualifications, | |
parameterSimpleNames), | |
new ConstructorReferencePattern( | |
declaringSimpleName, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
parameterQualifications, | |
parameterSimpleNames, | |
method.getDeclaringType())); | |
} else { | |
searchPattern = new OrPattern( | |
new MethodDeclarationPattern( | |
selector, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
returnQualification, | |
returnSimpleName, | |
parameterQualifications, | |
parameterSimpleNames), | |
new MethodReferencePattern( | |
selector, | |
EXACT_MATCH, | |
CASE_SENSITIVE, | |
declaringQualification, | |
declaringSimpleName, | |
returnQualification, | |
returnSimpleName, | |
parameterQualifications, | |
parameterSimpleNames, | |
method.getDeclaringType())); | |
} | |
break; | |
} | |
break; | |
case IJavaElement.TYPE : | |
IType type = (IType)element; | |
searchPattern = | |
createTypePattern( | |
type.getElementName().toCharArray(), | |
type.getPackageFragment().getElementName().toCharArray(), | |
enclosingTypeNames(type), | |
limitTo); | |
break; | |
case IJavaElement.PACKAGE_DECLARATION : | |
case IJavaElement.PACKAGE_FRAGMENT : | |
searchPattern = createPackagePattern(element.getElementName(), limitTo, EXACT_MATCH, CASE_SENSITIVE); | |
break; | |
} | |
return searchPattern; | |
} | |
private static SearchPattern createTypePattern(char[] simpleName, char[] packageName, char[][] enclosingTypeNames, int limitTo) { | |
SearchPattern searchPattern = null; | |
switch (limitTo) { | |
case IJavaSearchConstants.DECLARATIONS : | |
searchPattern = | |
new TypeDeclarationPattern( | |
packageName, | |
enclosingTypeNames, | |
simpleName, | |
TYPE_SUFFIX, | |
EXACT_MATCH, | |
CASE_SENSITIVE); | |
break; | |
case IJavaSearchConstants.REFERENCES : | |
searchPattern = | |
new TypeReferencePattern( | |
CharOperation.concatWith(packageName, enclosingTypeNames, '.'), | |
simpleName, | |
EXACT_MATCH, | |
CASE_SENSITIVE); | |
break; | |
case IJavaSearchConstants.IMPLEMENTORS : | |
searchPattern = | |
new SuperInterfaceReferencePattern( | |
CharOperation.concatWith(packageName, enclosingTypeNames, '.'), | |
simpleName, | |
EXACT_MATCH, | |
CASE_SENSITIVE); | |
break; | |
case IJavaSearchConstants.ALL_OCCURRENCES : | |
searchPattern = new OrPattern( | |
new TypeDeclarationPattern( | |
packageName, | |
enclosingTypeNames, | |
simpleName, | |
TYPE_SUFFIX, | |
EXACT_MATCH, | |
CASE_SENSITIVE), | |
new TypeReferencePattern( | |
CharOperation.concatWith(packageName, enclosingTypeNames, '.'), | |
simpleName, | |
EXACT_MATCH, | |
CASE_SENSITIVE)); | |
break; | |
} | |
return searchPattern; | |
} | |
/** | |
* Type pattern are formed by [qualification.]type | |
* e.g. java.lang.Object | |
* Runnable | |
* | |
*/ | |
private static SearchPattern createTypePattern(String patternString, int limitTo, int matchMode, boolean isCaseSensitive) { | |
Scanner scanner = new Scanner(false, true); // tokenize white spaces | |
scanner.setSource(patternString.toCharArray()); | |
String type = null; | |
int token; | |
try { | |
token = scanner.getNextToken(); | |
} catch (InvalidInputException e) { | |
return null; | |
} | |
while (token != ITerminalSymbols.TokenNameEOF){ | |
switch (token) { | |
case Scanner.TokenNameWHITESPACE: | |
break; | |
case ITerminalSymbols.TokenNameDOT: | |
case ITerminalSymbols.TokenNameIdentifier: | |
case ITerminalSymbols.TokenNameMULTIPLY: | |
case ITerminalSymbols.TokenNameLBRACKET: | |
case ITerminalSymbols.TokenNameRBRACKET: | |
case ITerminalSymbols.TokenNameboolean: | |
case ITerminalSymbols.TokenNamebyte: | |
case ITerminalSymbols.TokenNamechar: | |
case ITerminalSymbols.TokenNamedouble: | |
case ITerminalSymbols.TokenNamefloat: | |
case ITerminalSymbols.TokenNameint: | |
case ITerminalSymbols.TokenNamelong: | |
case ITerminalSymbols.TokenNameshort: | |
case ITerminalSymbols.TokenNamevoid: | |
if (type == null){ | |
type = new String(scanner.getCurrentTokenSource()); | |
} else { | |
type += new String(scanner.getCurrentTokenSource()); | |
} | |
break; | |
default: | |
return null; | |
} | |
try { | |
token = scanner.getNextToken(); | |
} catch (InvalidInputException e) { | |
return null; | |
} | |
} | |
if (type == null) return null; | |
char[] qualificationChars = null, typeChars = null; | |
// extract declaring type infos | |
if (type != null){ | |
char[] typePart = type.toCharArray(); | |
int lastDotPosition = CharOperation.lastIndexOf('.', typePart); | |
if (lastDotPosition >= 0){ | |
qualificationChars = CharOperation.subarray(typePart, 0, lastDotPosition); | |
if (qualificationChars.length == 1 && qualificationChars[0] == '*') qualificationChars = null; | |
typeChars = CharOperation.subarray(typePart, lastDotPosition+1, typePart.length); | |
} else { | |
qualificationChars = null; | |
typeChars = typePart; | |
} | |
if (typeChars.length == 1 && typeChars[0] == '*') typeChars = null; | |
} | |
SearchPattern searchPattern = null; | |
switch (limitTo){ | |
case IJavaSearchConstants.DECLARATIONS : // cannot search for explicit member types | |
searchPattern = new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, TYPE_SUFFIX, matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.REFERENCES : | |
searchPattern = new TypeReferencePattern(qualificationChars, typeChars, matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.IMPLEMENTORS : | |
searchPattern = new SuperInterfaceReferencePattern(qualificationChars, typeChars, matchMode, isCaseSensitive); | |
break; | |
case IJavaSearchConstants.ALL_OCCURRENCES : | |
searchPattern = new OrPattern( | |
new QualifiedTypeDeclarationPattern(qualificationChars, typeChars, TYPE_SUFFIX, matchMode, isCaseSensitive),// cannot search for explicit member types | |
new TypeReferencePattern(qualificationChars, typeChars, matchMode, isCaseSensitive)); | |
break; | |
} | |
return searchPattern; | |
} | |
protected abstract void decodeIndexEntry(IEntryResult entryResult); | |
/** | |
* Returns the enclosing type names of the given type. | |
*/ | |
private static char[][] enclosingTypeNames(IType type) { | |
IJavaElement parent = type.getParent(); | |
switch (parent.getElementType()) { | |
case IJavaElement.CLASS_FILE: | |
case IJavaElement.COMPILATION_UNIT: | |
return NO_CHAR_CHAR; | |
case IJavaElement.TYPE: | |
return CharOperation.arrayConcat( | |
enclosingTypeNames((IType)parent), | |
parent.getElementName().toCharArray()); | |
default: | |
return null; | |
} | |
} | |
/** | |
* Feed the requestor according to the current search pattern | |
*/ | |
public abstract void feedIndexRequestor(IIndexSearchRequestor requestor, int detailLevel, int[] references, IndexInput input, IJavaSearchScope scope) throws IOException ; | |
/** | |
* Query a given index for matching entries. | |
*/ | |
public void findIndexMatches(IIndex index, IIndexSearchRequestor requestor, int detailLevel, IProgressMonitor progressMonitor, IJavaSearchScope scope) throws IOException { | |
if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException(); | |
IndexInput input = new BlocksIndexInput(index.getIndexFile()); | |
try { | |
input.open(); | |
findIndexMatches(input, requestor, detailLevel, progressMonitor,scope); | |
} finally { | |
input.close(); | |
} | |
} | |
/** | |
* Query a given index for matching entries. | |
*/ | |
public void findIndexMatches(IndexInput input, IIndexSearchRequestor requestor, int detailLevel, IProgressMonitor progressMonitor, IJavaSearchScope scope) throws IOException { | |
if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException(); | |
/* narrow down a set of entries using prefix criteria */ | |
IEntryResult[] entries = input.queryEntriesPrefixedBy(indexEntryPrefix()); | |
if (entries == null) return; | |
/* only select entries which actually match the entire search pattern */ | |
for (int i = 0, max = entries.length; i < max; i++){ | |
if (progressMonitor != null && progressMonitor.isCanceled()) throw new OperationCanceledException(); | |
/* retrieve and decode entry */ | |
IEntryResult entry = entries[i]; | |
decodeIndexEntry(entry); | |
if (matchIndexEntry()){ | |
feedIndexRequestor(requestor, detailLevel, entry.getFileReferences(), input, scope); | |
} | |
} | |
} | |
/** | |
* Answers the suitable prefix that should be used in order | |
* to query indexes for the corresponding item. | |
* The more accurate the prefix and the less false hits will have | |
* to be eliminated later on. | |
*/ | |
public abstract char[] indexEntryPrefix(); | |
/** | |
* Check if the given ast node syntactically matches this pattern. | |
* If it does, add it to the match set. | |
*/ | |
protected void matchCheck(AstNode node, MatchSet set) { | |
int matchLevel = this.matchLevel(node, false); | |
switch (matchLevel) { | |
case SearchPattern.POSSIBLE_MATCH: | |
set.addPossibleMatch(node); | |
break; | |
case SearchPattern.ACCURATE_MATCH: | |
set.addTrustedMatch(node); | |
} | |
} | |
/** | |
* Returns the type of container of this pattern, i.e. is it in compilation unit, | |
* in class declarations, field declarations, or in method declarations. | |
*/ | |
protected abstract int matchContainer(); | |
/** | |
* Finds out whether the given binary info matches this search pattern. | |
* Default is to return false. | |
*/ | |
public boolean matchesBinary(Object binaryInfo, Object enclosingBinaryInfo) { | |
return false; | |
} | |
/** | |
* Returns whether the given name matches the given pattern. | |
*/ | |
protected boolean matchesName(char[] pattern, char[] name) { | |
if (name != null){ | |
switch (this.matchMode) { | |
case EXACT_MATCH : | |
return CharOperation.equals(pattern, name, this.isCaseSensitive); | |
case PREFIX_MATCH : | |
return CharOperation.prefixEquals(pattern, name, this.isCaseSensitive); | |
case PATTERN_MATCH : | |
return CharOperation.match(pattern, name, this.isCaseSensitive); | |
} | |
} | |
return false; | |
} | |
/** | |
* Returns whether the given type binding matches the given simple name pattern | |
* and qualification pattern. | |
*/ | |
protected boolean matchesType(char[] simpleNamePattern, char[] qualificationPattern, char[] fullyQualifiedTypeName) { | |
char[] pattern; | |
if (simpleNamePattern == null) { | |
if (qualificationPattern == null) { | |
pattern = ONE_STAR; | |
} else { | |
pattern = CharOperation.concat(qualificationPattern, ONE_STAR, '.'); | |
} | |
} else { | |
if (qualificationPattern == null) { | |
pattern = CharOperation.concat(ONE_STAR, simpleNamePattern); | |
} else { | |
pattern = CharOperation.concat(qualificationPattern, simpleNamePattern, '.'); | |
} | |
} | |
return | |
CharOperation.match( | |
pattern, | |
fullyQualifiedTypeName, | |
this.isCaseSensitive | |
); | |
} | |
/** | |
* Checks whether an entry matches the current search pattern | |
*/ | |
protected abstract boolean matchIndexEntry(); | |
/** | |
* Reports the match of the given reference. | |
*/ | |
protected void matchReportReference(AstNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException { | |
// default is to report a match on the whole node. | |
locator.report(reference.sourceStart, reference.sourceEnd, element, accuracy); | |
} | |
/** | |
* Add square brackets to the given simple name | |
*/ | |
protected char[] toArrayName(char[] simpleName, int dimensions) { | |
if (dimensions == 0) return simpleName; | |
int length = simpleName.length; | |
char[] result = new char[length + dimensions * 2]; | |
System.arraycopy(simpleName, 0, result, 0, length); | |
for (int i = 0; i < dimensions; i++) { | |
result[simpleName.length + i*2] = '['; | |
result[simpleName.length + i*2 + 1] = ']'; | |
} | |
return result; | |
} | |
public String toString(){ | |
return "SearchPattern"; //$NON-NLS-1$ | |
} | |
/** | |
* Initializes this search pattern so that polymorphic search can be performed. | |
*/ | |
public void initializePolymorphicSearch(MatchLocator locator, IProgressMonitor progressMonitor) { | |
// default is to do nothing | |
} | |
/** | |
* Finds out whether the given ast node matches this search pattern. | |
* Returns IMPOSSIBLE_MATCH if it doesn't. | |
* Returns POSSIBLE_MATCH if it potentially matches this search pattern | |
* and it has not been reolved, and it needs to be resolved to get more information. | |
* Returns ACCURATE_MATCH if it matches exactly this search pattern (ie. | |
* it doesn't need to be resolved or it has already been resolved.) | |
* Returns INACCURATE_MATCH if it potentially exactly this search pattern (ie. | |
* it has already been resolved but resolving failed.) | |
*/ | |
public abstract int matchLevel(AstNode node, boolean resolve); | |
/** | |
* Finds out whether the given binding matches this search pattern. | |
* Returns ACCURATE_MATCH if it does. | |
* Returns INACCURATE_MATCH if resolve failed but match is still possible. | |
* Retunrs IMPOSSIBLE_MATCH otherwise. | |
* Default is to return INACCURATE_MATCH. | |
*/ | |
public int matchLevel(Binding binding) { | |
return INACCURATE_MATCH; | |
} | |
/** | |
* Returns whether the given reference type binding matches or is a subtype of a type | |
* that matches the given simple name pattern and qualification pattern. | |
* Returns ACCURATE_MATCH if it does. | |
* Returns INACCURATE_MATCH if resolve fails | |
* Returns IMPOSSIBLE_MATCH if it doesn't. | |
*/ | |
protected int matchLevelAsSubtype(ReferenceBinding type, char[] simpleNamePattern, char[] qualificationPattern) { | |
if (type == null) return INACCURATE_MATCH; | |
int level; | |
// matches type | |
if ((level = this.matchLevelForType(simpleNamePattern, qualificationPattern, type)) != IMPOSSIBLE_MATCH) | |
return level; | |
// matches superclass | |
if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) { | |
if ((level = this.matchLevelAsSubtype(type.superclass(), simpleNamePattern, qualificationPattern)) != IMPOSSIBLE_MATCH) { | |
return level; | |
} | |
} | |
// matches interfaces | |
ReferenceBinding[] interfaces = type.superInterfaces(); | |
if (interfaces == null) { | |
return INACCURATE_MATCH; | |
} else { | |
for (int i = 0; i < interfaces.length; i++) { | |
if ((level = this.matchLevelAsSubtype(interfaces[i], simpleNamePattern, qualificationPattern)) != IMPOSSIBLE_MATCH) { | |
return level; | |
}; | |
} | |
} | |
return IMPOSSIBLE_MATCH; | |
} | |
/** | |
* Returns whether one of the given declaring types is the given receiver type. | |
* Returns ACCURATE_MATCH if it does. | |
* Returns INACCURATE_MATCH if resolve failed. | |
* Returns IMPOSSIBLE_MATCH if it doesn't. | |
*/ | |
protected int matchLevelForType(char[][][] declaringTypes, ReferenceBinding receiverType) { | |
if (receiverType == null) return INACCURATE_MATCH; | |
if (declaringTypes == null) { | |
return INACCURATE_MATCH; // we were not able to compute the declaring types, default to inaccurate | |
} else { | |
for (int i = 0, max = declaringTypes.length; i < max; i++) { | |
if (CharOperation.equals(declaringTypes[i], receiverType.compoundName)) { | |
return ACCURATE_MATCH; | |
} | |
} | |
return IMPOSSIBLE_MATCH; | |
} | |
} | |
/** | |
* Returns whether the given type binding matches the given simple name pattern | |
* and qualification pattern. | |
* Returns ACCURATE_MATCH if it does. | |
* Returns INACCURATE_MATCH if resolve failed. | |
* Returns IMPOSSIBLE_MATCH if it doesn't. | |
*/ | |
protected int matchLevelForType(char[] simpleNamePattern, char[] qualificationPattern, TypeBinding type) { | |
if (type == null) return INACCURATE_MATCH; | |
char[] qualifiedPackageName = type.qualifiedPackageName(); | |
char[] qualifiedSourceName = | |
type instanceof LocalTypeBinding ? | |
CharOperation.concat("1".toCharArray(), type.qualifiedSourceName(), '.') : //$NON-NLS-1$ | |
type.qualifiedSourceName(); | |
if (this.matchesType( | |
simpleNamePattern, | |
qualificationPattern, | |
qualifiedPackageName.length == 0 ? | |
qualifiedSourceName : | |
CharOperation.concat(qualifiedPackageName, qualifiedSourceName, '.'))) { | |
return ACCURATE_MATCH; | |
} else { | |
return IMPOSSIBLE_MATCH; | |
} | |
} | |
} |