blob: d8e7984bcf0d4392e7a0d0be7569a450a7fe5f35 [file] [log] [blame]
package org.eclipse.jdt.internal.core.search.matching;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.internal.compiler.env.*;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.util.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.core.index.*;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jdt.internal.core.search.indexing.*;
import org.eclipse.jdt.internal.core.index.impl.*;
import org.eclipse.jdt.internal.core.search.*;
import java.io.*;
public class TypeDeclarationPattern extends SearchPattern {
private char[] qualification;
private char[][] enclosingTypeNames;
private char[] simpleName;
// set to CLASS_SUFFIX for only matching classes
// set to INTERFACE_SUFFIX for only matching interfaces
// set to TYPE_SUFFIX for matching both classes and interfaces
private char classOrInterface;
private char[] decodedQualification;
private char[] decodedSimpleName;
private char[][] decodedEnclosingTypeNames;
private char decodedClassOrInterface;
public TypeDeclarationPattern(
char[] qualification,
char[][] enclosingTypeNames,
char[] simpleName,
char classOrInterface,
int matchMode,
boolean isCaseSensitive) {
super(matchMode, isCaseSensitive);
this.qualification = isCaseSensitive ? qualification : CharOperation.toLowerCase(qualification);
if (isCaseSensitive || enclosingTypeNames == null) {
this.enclosingTypeNames = enclosingTypeNames;
} else {
int length = enclosingTypeNames.length;
this.enclosingTypeNames = new char[length][];
for (int i = 0; i < length; i++){
this.enclosingTypeNames[i] = CharOperation.toLowerCase(enclosingTypeNames[i]);
}
}
this.simpleName = isCaseSensitive ? simpleName : CharOperation.toLowerCase(simpleName);
this.classOrInterface = classOrInterface;
this.needsResolve = qualification != null;
}
public void decodeIndexEntry(IEntryResult entryResult){
char[] word = entryResult.getWord();
int size = word.length;
decodedClassOrInterface = word[TYPE_DECL_LENGTH];
int oldSlash = TYPE_DECL_LENGTH+1;
int slash = CharOperation.indexOf(SEPARATOR, word, oldSlash+1);
if (slash == oldSlash+1){
decodedQualification = NO_CHAR;
} else {
decodedQualification = CharOperation.subarray(word, oldSlash+1, slash);
}
decodedSimpleName = CharOperation.subarray(word, slash+1, slash = CharOperation.indexOf(SEPARATOR, word, slash+1));
if (slash+1 < size){
decodedEnclosingTypeNames = CharOperation.splitOn('/', CharOperation.subarray(word, slash+1, size-1));
} else {
decodedEnclosingTypeNames = NO_CHAR_CHAR;
}
}
/**
* see SearchPattern.feedIndexRequestor
*/
public void feedIndexRequestor(IIndexSearchRequestor requestor, int detailLevel, int[] references, IndexInput input, IJavaSearchScope scope) throws IOException {
boolean isClass = decodedClassOrInterface == CLASS_SUFFIX;
for (int i = 0, max = references.length; i < max; i++) {
IndexedFile file = input.getIndexedFile(references[i]);
String path;
if (file != null && scope.encloses(path =IndexedFile.convertPath(file.getPath()))) {
if (isClass) {
requestor.acceptClassDeclaration(path, decodedSimpleName, decodedEnclosingTypeNames, decodedQualification);
} else {
requestor.acceptInterfaceDeclaration(path, decodedSimpleName, decodedEnclosingTypeNames, decodedQualification);
}
}
}
}
/**
* see SearchPattern.indexEntryPrefix()
*/
public char[] indexEntryPrefix(){
return AbstractIndexer.bestTypeDeclarationPrefix(
qualification,
simpleName,
classOrInterface,
matchMode,
isCaseSensitive);
}
/**
* @see SearchPattern#matchContainer()
*/
protected int matchContainer() {
return COMPILATION_UNIT | CLASS;
}
/**
* @see SearchPattern#matchesBinary(Object, Object)
*/
public boolean matchesBinary(Object binaryInfo, Object enclosingBinaryInfo) {
if (!(binaryInfo instanceof IBinaryType)) return false;
IBinaryType type = (IBinaryType)binaryInfo;
// fully qualified name
char[] typeName = (char[])type.getName().clone();
CharOperation.replace(typeName, '/', '.');
char[] enclosingTypeName = this.enclosingTypeNames == null ? null : CharOperation.concatWith(this.enclosingTypeNames, '.');
if (!this.matchesType(this.simpleName, this.qualification, enclosingTypeName, typeName)) {
return false;
}
// class or interface
switch (this.classOrInterface) {
case CLASS_SUFFIX:
if (type.isInterface())
return false;
break;
case INTERFACE_SUFFIX:
if (!type.isInterface())
return false;
break;
}
return true;
}
/**
* Returns whether the given type binding matches the given simple name pattern
* qualification pattern and enclosing name pattern.
*/
protected boolean matchesType(char[] simpleNamePattern, char[] qualificationPattern, char[] enclosingNamePattern, char[] fullyQualifiedTypeName) {
if (enclosingNamePattern == null) {
return this.matchesType(simpleNamePattern, qualificationPattern, fullyQualifiedTypeName);
} else {
char[] pattern;
if (qualificationPattern == null) {
pattern = enclosingNamePattern;
} else {
pattern = CharOperation.concat(qualificationPattern, enclosingNamePattern, '.');
}
return this.matchesType(simpleNamePattern, pattern, fullyQualifiedTypeName);
}
}
/**
* see SearchPattern.matchIndexEntry
*/
protected boolean matchIndexEntry(){
/* check class/interface nature */
switch(classOrInterface){
case CLASS_SUFFIX :
case INTERFACE_SUFFIX :
if (classOrInterface != decodedClassOrInterface) return false;
default :
}
/* check qualification - exact match only */
if (qualification != null && !CharOperation.equals(qualification, decodedQualification, isCaseSensitive))
return false;
/* check enclosingTypeName - exact match only */
if (enclosingTypeNames != null){
// empty char[][] means no enclosing type, i.e. the decoded one is the empty char array
if (enclosingTypeNames.length == 0){
if (decodedEnclosingTypeNames != NO_CHAR_CHAR) return false;
} else {
if (!CharOperation.equals(enclosingTypeNames, decodedEnclosingTypeNames, isCaseSensitive)) return false;
}
}
/* check simple name matches */
if (simpleName != null){
switch(matchMode){
case EXACT_MATCH :
if (!CharOperation.equals(simpleName, decodedSimpleName, isCaseSensitive)){
return false;
}
break;
case PREFIX_MATCH :
if (!CharOperation.prefixEquals(simpleName, decodedSimpleName, isCaseSensitive)){
return false;
}
break;
case PATTERN_MATCH :
if (!CharOperation.match(simpleName, decodedSimpleName, isCaseSensitive)){
return false;
}
}
}
return true;
}
public String toString(){
StringBuffer buffer = new StringBuffer(20);
switch (classOrInterface){
case CLASS_SUFFIX :
buffer.append("ClassDeclarationPattern: pkg<"); //$NON-NLS-1$
break;
case INTERFACE_SUFFIX :
buffer.append("InterfaceDeclarationPattern: pkg<"); //$NON-NLS-1$
break;
default :
buffer.append("TypeDeclarationPattern: pkg<"); //$NON-NLS-1$
break;
}
if (qualification != null) buffer.append(qualification);
buffer.append(">, enclosing<"); //$NON-NLS-1$
if (enclosingTypeNames != null) {
for (int i = 0; i < enclosingTypeNames.length; i++){
buffer.append(enclosingTypeNames[i]);
if (i < enclosingTypeNames.length - 1)
buffer.append('.');
}
}
buffer.append(">, type<"); //$NON-NLS-1$
if (simpleName != null) buffer.append(simpleName);
buffer.append(">, "); //$NON-NLS-1$
switch(matchMode){
case EXACT_MATCH :
buffer.append("exact match, "); //$NON-NLS-1$
break;
case PREFIX_MATCH :
buffer.append("prefix match, "); //$NON-NLS-1$
break;
case PATTERN_MATCH :
buffer.append("pattern match, "); //$NON-NLS-1$
break;
}
if (isCaseSensitive)
buffer.append("case sensitive"); //$NON-NLS-1$
else
buffer.append("case insensitive"); //$NON-NLS-1$
return buffer.toString();
}
/**
* @see SearchPattern#matchLevel(AstNode, boolean)
*/
public int matchLevel(AstNode node, boolean resolve) {
if (!(node instanceof TypeDeclaration)) return IMPOSSIBLE_MATCH;
TypeDeclaration type = (TypeDeclaration)node;
if (resolve) {
return this.matchLevel(type.binding);
} else {
// type name
if (this.simpleName != null && !this.matchesName(this.simpleName, type.name))
return IMPOSSIBLE_MATCH;
else
return POSSIBLE_MATCH;
}
}
/**
* @see SearchPattern#matchLevel(Binding)
*/
public int matchLevel(Binding binding) {
if (binding == null) return INACCURATE_MATCH;
if (!(binding instanceof TypeBinding)) return IMPOSSIBLE_MATCH;
TypeBinding type = (TypeBinding)binding;
// class or interface
switch (this.classOrInterface) {
case CLASS_SUFFIX:
if (type.isInterface())
return IMPOSSIBLE_MATCH;
break;
case INTERFACE_SUFFIX:
if (!type.isInterface())
return IMPOSSIBLE_MATCH;
break;
}
// fully qualified name
char[] enclosingTypeName = this.enclosingTypeNames == null ? null : CharOperation.concatWith(this.enclosingTypeNames, '.');
return this.matchLevelForType(this.simpleName, this.qualification, enclosingTypeName, type);
}
/**
* Returns whether the given type binding matches the given simple name pattern
* qualification pattern and enclosing type name pattern.
*/
protected int matchLevelForType(char[] simpleNamePattern, char[] qualificationPattern, char[] enclosingNamePattern, TypeBinding type) {
if (enclosingNamePattern == null) {
return this.matchLevelForType(simpleNamePattern, qualificationPattern, type);
} else {
char[] pattern;
if (qualificationPattern == null) {
return matchLevelForType(simpleNamePattern, enclosingNamePattern, type);
} else {
// pattern was created from a Java element: qualification is the package name.
char[] fullQualificationPattern = CharOperation.concat(qualificationPattern, enclosingNamePattern, '.');
if ( CharOperation.equals(qualification, CharOperation.concatWith(type.getPackage().compoundName, '.'))) {
return this.matchLevelForType(simpleNamePattern, fullQualificationPattern, type);
} else {
return IMPOSSIBLE_MATCH;
}
}
}
}
}