blob: 0edef61ddda12a7cf71d07b7c1045f4516f19626 [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.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.internal.core.index.*;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jdt.internal.core.index.impl.*;
import org.eclipse.jdt.internal.core.search.indexing.AbstractIndexer;
import org.eclipse.jdt.internal.core.search.IIndexSearchRequestor;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.util.CharOperation;
import org.eclipse.jdt.internal.compiler.lookup.*;
import java.io.IOException;
public class PackageReferencePattern extends AndPattern {
private static char[][] TAGS = { REF };
private char[] pkgName;
private char[][] segments;
private int currentSegment;
private char[] decodedSegment;
public PackageReferencePattern(char[] pkgName, int matchMode, boolean isCaseSensitive) {
super(matchMode, isCaseSensitive);
this.pkgName = pkgName;
char[][] splittedName = CharOperation.splitOn('.', pkgName);
this.segments = splittedName == TypeConstants.NoCharChar ? new char[][]{ pkgName } : splittedName;
this.needsResolve = pkgName != null;
}
/**
* ref/name (where name is the last segment of the package name)
*/
public void decodeIndexEntry(IEntryResult entryResult){
char[] word = entryResult.getWord();
int size = word.length;
int tagLength = REF.length;
int nameLength = CharOperation.indexOf(SEPARATOR, word, tagLength);
if (nameLength < 0) nameLength = size;
this.decodedSegment = CharOperation.subarray(word, tagLength, nameLength);
}
/**
* @see SearchPattern#feedIndexRequestor(IIndexSearchRequestor requestor, int detailLevel, int[] references, IndexInput input, IJavaSearchScope scope)
*/
public void feedIndexRequestor(IIndexSearchRequestor requestor, int detailLevel, int[] references, IndexInput input, IJavaSearchScope scope) throws IOException {
for (int i = 0, max = references.length; i < max; i++) {
int reference = references[i];
if (reference != -1) { // if the reference has not been eliminated
IndexedFile file = input.getIndexedFile(reference);
String path;
if (file != null && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
requestor.acceptPackageReference(path, this.pkgName);
}
}
}
}
protected char[][] getPossibleTags() {
return TAGS;
}
/**
* @see AndPattern#hasNextQuery()
*/
protected boolean hasNextQuery() {
if (this.segments.length > 2) {
// if package has more than 2 segments, don't look at the first 2 since they are mostly
// redundant (eg. in 'org.eclipse.jdt.core.*' 'org.eclipse' is used all the time)
return --this.currentSegment >= 2;
} else {
return --this.currentSegment >= 0;
}
}
/**
* @see SearchPattern#indexEntryPrefix()
*/
public char[] indexEntryPrefix() {
return AbstractIndexer.bestReferencePrefix(
REF,
this.segments[this.currentSegment],
matchMode,
isCaseSensitive);
}
/**
* @see SearchPattern#matchContainer()
*/
protected int matchContainer() {
return COMPILATION_UNIT | CLASS | METHOD | FIELD;
}
/**
* Returns whether this package reference pattern matches the given tokens.
*/
private boolean matches(char[][] tokens) {
char[] name = CharOperation.concatWith(tokens, '.');
return this.matchesName(this.pkgName, name);
}
/**
* @see SearchPattern#matchIndexEntry()
*/
protected boolean matchIndexEntry() {
switch(matchMode){
case EXACT_MATCH :
if (!CharOperation.equals(this.segments[this.currentSegment], this.decodedSegment, isCaseSensitive)){
return false;
}
break;
case PREFIX_MATCH :
if (!CharOperation.prefixEquals(this.segments[this.currentSegment], this.decodedSegment, isCaseSensitive)){
return false;
}
break;
case PATTERN_MATCH :
if (!CharOperation.match(this.segments[this.currentSegment], this.decodedSegment, isCaseSensitive)){
return false;
}
}
return true;
}
/**
* @see SearchPattern#matchReportReference(AstNode reference, IJavaElement element, int accuracy, MatchLocator locator)
*/
protected void matchReportReference(AstNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
char[][] tokens = null;
if (reference instanceof ImportReference) {
ImportReference importRef = (ImportReference)reference;
if (importRef.onDemand) {
tokens = importRef.tokens;
} else {
int length = importRef.tokens.length - 1;
tokens = new char[length][];
System.arraycopy(importRef.tokens, 0, tokens, 0, length);
}
} else if (reference instanceof QualifiedNameReference) {
QualifiedNameReference qNameRef = (QualifiedNameReference)reference;
Binding binding = qNameRef.binding;
TypeBinding typeBinding = null;
switch (qNameRef.bits & AstNode.RestrictiveFlagMASK) {
case BindingIds.FIELD : // reading a field
typeBinding = ((FieldBinding)binding).declaringClass;
break;
case BindingIds.TYPE : //=============only type ==============
typeBinding = (TypeBinding)binding;
}
if (typeBinding instanceof ReferenceBinding) {
PackageBinding pkgBinding = ((ReferenceBinding)typeBinding).fPackage;
if (pkgBinding != null) {
tokens = pkgBinding.compoundName;
}
}
if (tokens == null) {
tokens = qNameRef.tokens;
}
} else if (reference instanceof QualifiedTypeReference) {
QualifiedTypeReference qTypeRef = (QualifiedTypeReference)reference;
TypeBinding typeBinding = qTypeRef.binding;
if (typeBinding instanceof ArrayBinding) {
typeBinding = ((ArrayBinding)typeBinding).leafComponentType;
}
if (typeBinding instanceof ReferenceBinding) {
PackageBinding pkgBinding = ((ReferenceBinding)typeBinding).fPackage;
if (pkgBinding != null) {
tokens = pkgBinding.compoundName;
}
}
if (tokens == null) {
tokens = qTypeRef.tokens;
}
}
if (tokens == null) tokens = NO_CHAR_CHAR;
locator.reportAccurateReference(reference.sourceStart, reference.sourceEnd, tokens, element, accuracy);
}
/**
* @see AndPattern#resetQuery()
*/
protected void resetQuery() {
/* walk the segments from end to start as it will find less potential references using 'lang' than 'java' */
this.currentSegment = this.segments.length - 1;
}
public String toString(){
StringBuffer buffer = new StringBuffer(20);
buffer.append("PackageReferencePattern: <"); //$NON-NLS-1$
if (this.pkgName != null) buffer.append(this.pkgName);
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 QualifiedTypeReference) {
return this.matchLevel((QualifiedTypeReference)node, resolve);
} else if (node instanceof ImportReference) {
return this.matchLevel((ImportReference)node, resolve);
} else if (node instanceof QualifiedNameReference) {
return this.matchLevel((QualifiedNameReference)node, resolve);
}
return IMPOSSIBLE_MATCH;
}
/**
* Returns whether this package reference pattern matches the given import reference.
* Look at resolved information only if specified.
*/
private int matchLevel(ImportReference importRef, boolean resolve) {
if (importRef.onDemand) {
if (this.matches(importRef.tokens)) {
return ACCURATE_MATCH;
} else {
return IMPOSSIBLE_MATCH;
}
} else {
int length = importRef.tokens.length - 1;
char[][] tokens = new char[length][];
System.arraycopy(importRef.tokens, 0, tokens, 0, length);
if (this.matches(tokens)) {
return ACCURATE_MATCH;
} else {
return IMPOSSIBLE_MATCH;
}
}
}
/**
* Returns whether this package reference pattern matches the given qualified name reference.
* Look at resolved information only if specified.
*/
private int matchLevel(QualifiedNameReference qNameRef, boolean resolve) {
if (!resolve) {
if (this.pkgName == null) {
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
} else {
switch (this.matchMode) {
case EXACT_MATCH:
case PREFIX_MATCH:
if (CharOperation.prefixEquals(this.pkgName, CharOperation.concatWith(qNameRef.tokens, '.'), this.isCaseSensitive)) {
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
} else {
return IMPOSSIBLE_MATCH;
}
case PATTERN_MATCH:
char[] pattern = this.pkgName[this.pkgName.length-1] == '*' ? this.pkgName : CharOperation.concat(this.pkgName, ".*".toCharArray()); //$NON-NLS-1$
if (CharOperation.match(pattern, CharOperation.concatWith(qNameRef.tokens, '.'), this.isCaseSensitive)) {
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
} else {
return IMPOSSIBLE_MATCH;
}
default:
return IMPOSSIBLE_MATCH;
}
}
} else {
Binding binding = qNameRef.binding;
if (binding == null) {
return INACCURATE_MATCH;
} else {
TypeBinding typeBinding = null;
char[][] tokens = qNameRef.tokens;
int lastIndex = tokens.length-1;
switch (qNameRef.bits & AstNode.RestrictiveFlagMASK) {
case BindingIds.FIELD : // reading a field
typeBinding = ((FieldBinding)binding).declaringClass;
// no valid match amongst fields
int otherBindingsCount = qNameRef.otherBindings == null ? 0 : qNameRef.otherBindings.length;
lastIndex -= otherBindingsCount + 1;
if (lastIndex < 0) return IMPOSSIBLE_MATCH;
break;
case BindingIds.LOCAL : // reading a local variable
return IMPOSSIBLE_MATCH; // no package match in it
case BindingIds.TYPE : //=============only type ==============
typeBinding = (TypeBinding)binding;
}
if (typeBinding instanceof ArrayBinding) {
typeBinding = ((ArrayBinding)typeBinding).leafComponentType;
}
if (typeBinding == null) {
return INACCURATE_MATCH;
} else {
if (typeBinding instanceof ReferenceBinding) {
PackageBinding pkgBinding = ((ReferenceBinding)typeBinding).fPackage;
if (pkgBinding == null) {
return INACCURATE_MATCH;
} else if (this.matches(pkgBinding.compoundName)) {
return ACCURATE_MATCH;
} else {
return IMPOSSIBLE_MATCH;
}
} else {
return IMPOSSIBLE_MATCH;
}
}
}
}
}
/**
* Returns whether this package reference pattern matches the given type reference.
* Look at resolved information only if specified.
*/
private int matchLevel(QualifiedTypeReference typeRef, boolean resolve) {
if (!resolve) {
if (this.pkgName == null) {
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
} else {
switch (this.matchMode) {
case EXACT_MATCH:
case PREFIX_MATCH:
if (CharOperation.prefixEquals(this.pkgName, CharOperation.concatWith(typeRef.tokens, '.'), this.isCaseSensitive)) {
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
} else {
return IMPOSSIBLE_MATCH;
}
case PATTERN_MATCH:
char[] pattern = this.pkgName[this.pkgName.length-1] == '*' ? this.pkgName : CharOperation.concat(this.pkgName, ".*".toCharArray()); //$NON-NLS-1$
if (CharOperation.match(pattern, CharOperation.concatWith(typeRef.tokens, '.'), this.isCaseSensitive)) {
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
} else {
return IMPOSSIBLE_MATCH;
}
default:
return IMPOSSIBLE_MATCH;
}
}
} else {
TypeBinding typeBinding = typeRef.binding;
if (typeBinding == null || typeBinding instanceof ProblemReferenceBinding) {
return INACCURATE_MATCH;
} else {
if (typeBinding instanceof ArrayBinding) {
typeBinding = ((ArrayBinding)typeBinding).leafComponentType;
}
if (typeBinding == null) {
return INACCURATE_MATCH;
} else if (typeBinding instanceof ReferenceBinding) {
PackageBinding pkgBinding = ((ReferenceBinding)typeBinding).fPackage;
if (this.matches(pkgBinding.compoundName)) {
return ACCURATE_MATCH;
} else {
return IMPOSSIBLE_MATCH;
}
} else {
return IMPOSSIBLE_MATCH;
}
}
}
}
}