blob: 8c59ba6e4efb5e2229d1eefc17a20c70386ba8b4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.*;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.core.search.indexing.IIndexConstants;
public abstract class PatternLocator implements IIndexConstants {
protected int matchMode;
protected boolean isCaseSensitive;
/* match levels */
public static final int IMPOSSIBLE_MATCH = 0;
public static final int INACCURATE_MATCH = 1;
public static final int POSSIBLE_MATCH = 2;
public static final int ACCURATE_MATCH = 3;
/* match container */
public static final int COMPILATION_UNIT_CONTAINER = 1;
public static final int CLASS_CONTAINER = 2;
public static final int METHOD_CONTAINER = 4;
public static final int FIELD_CONTAINER = 8;
public static final int ALL_CONTAINER =
COMPILATION_UNIT_CONTAINER | CLASS_CONTAINER | METHOD_CONTAINER | FIELD_CONTAINER;
public static PatternLocator patternLocator(SearchPattern pattern) {
switch (((InternalSearchPattern)pattern).kind) {
case IIndexConstants.PKG_REF_PATTERN :
return new PackageReferenceLocator((PackageReferencePattern) pattern);
case IIndexConstants.PKG_DECL_PATTERN :
return new PackageDeclarationLocator((PackageDeclarationPattern) pattern);
case IIndexConstants.TYPE_REF_PATTERN :
return new TypeReferenceLocator((TypeReferencePattern) pattern);
case IIndexConstants.TYPE_DECL_PATTERN :
return new TypeDeclarationLocator((TypeDeclarationPattern) pattern);
case IIndexConstants.SUPER_REF_PATTERN :
return new SuperTypeReferenceLocator((SuperTypeReferencePattern) pattern);
case IIndexConstants.CONSTRUCTOR_PATTERN :
return new ConstructorLocator((ConstructorPattern) pattern);
case IIndexConstants.FIELD_PATTERN :
return new FieldLocator((FieldPattern) pattern);
case IIndexConstants.METHOD_PATTERN :
return new MethodLocator((MethodPattern) pattern);
case IIndexConstants.OR_PATTERN :
return new OrLocator((OrPattern) pattern);
case IIndexConstants.LOCAL_VAR_PATTERN :
return new LocalVariableLocator((LocalVariablePattern) pattern);
}
return null;
}
public static char[] qualifiedPattern(char[] simpleNamePattern, char[] qualificationPattern) {
// NOTE: if case insensitive search then simpleNamePattern & qualificationPattern are assumed to be lowercase
if (simpleNamePattern == null) {
if (qualificationPattern == null) return null;
return CharOperation.concat(qualificationPattern, ONE_STAR, '.');
} else {
return qualificationPattern == null
? CharOperation.concat(ONE_STAR, simpleNamePattern)
: CharOperation.concat(qualificationPattern, simpleNamePattern, '.');
}
}
public static char[] qualifiedSourceName(TypeBinding binding) {
if (binding instanceof ReferenceBinding) {
ReferenceBinding type = (ReferenceBinding) binding;
if (type.isLocalType())
return type.isMemberType()
? CharOperation.concat(qualifiedSourceName(type.enclosingType()), type.sourceName(), '.')
: CharOperation.concat(qualifiedSourceName(type.enclosingType()), new char[] {'.', '1', '.'}, type.sourceName());
}
return binding != null ? binding.qualifiedSourceName() : null;
}
public PatternLocator(SearchPattern pattern) {
this.matchMode = pattern.getMatchMode();
this.isCaseSensitive = pattern.isCaseSensitive();
}
/**
* Initializes this search pattern so that polymorphic search can be performed.
*/
public void initializePolymorphicSearch(MatchLocator locator) {
// default is to do nothing
}
/**
* Check if the given ast node syntactically matches this pattern.
* If it does, add it to the match set.
* Returns the match level.
*/
public int match(ASTNode node, MatchingNodeSet nodeSet) { // needed for some generic nodes
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(ConstructorDeclaration node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(Expression node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(FieldDeclaration node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(LocalDeclaration node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(MethodDeclaration node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(MessageSend node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(Reference node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(TypeDeclaration node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
public int match(TypeReference node, MatchingNodeSet nodeSet) {
// each subtype should override if needed
return IMPOSSIBLE_MATCH;
}
/**
* Returns the type(s) of container for this pattern.
* It is a bit combination of types, denoting compilation unit, class declarations, field declarations or method declarations.
*/
protected int matchContainer() {
// override if the pattern can be more specific
return ALL_CONTAINER;
}
/**
* Returns whether the given name matches the given pattern.
*/
protected boolean matchesName(char[] pattern, char[] name) {
if (pattern == null) return true; // null is as if it was "*"
if (name != null) {
switch (this.matchMode) {
case SearchPattern.R_EXACT_MATCH :
return CharOperation.equals(pattern, name, this.isCaseSensitive);
case SearchPattern.R_PREFIX_MATCH :
return CharOperation.prefixEquals(pattern, name, this.isCaseSensitive);
case SearchPattern.R_PATTERN_MATCH :
if (!this.isCaseSensitive)
pattern = CharOperation.toLowerCase(pattern);
return CharOperation.match(pattern, name, this.isCaseSensitive);
}
}
return false;
}
/**
* Returns whether the given type reference matches the given pattern.
*/
protected boolean matchesTypeReference(char[] pattern, TypeReference type) {
if (pattern == null) return true; // null is as if it was "*"
if (type == null) return true; // treat as an inexact match
char[][] compoundName = type.getTypeName();
char[] simpleName = compoundName[compoundName.length - 1];
int dimensions = type.dimensions() * 2;
if (dimensions > 0) {
int length = simpleName.length;
char[] result = new char[length + dimensions];
System.arraycopy(simpleName, 0, result, 0, length);
for (int i = length, l = result.length; i < l;) {
result[i++] = '[';
result[i++] = ']';
}
simpleName = result;
}
return matchesName(pattern, simpleName);
}
/**
* Returns the match level for the given importRef.
*/
protected int matchLevel(ImportReference importRef) {
// override if interested in import references which are caught by the generic version of match(ASTNode, MatchingNodeSet)
return IMPOSSIBLE_MATCH;
}
/**
* Reports the match of the given import reference if the resolveLevel is high enough.
*/
protected void matchLevelAndReportImportRef(ImportReference importRef, Binding binding, MatchLocator locator) throws CoreException {
int level = resolveLevel(binding);
if (level >= INACCURATE_MATCH) {
matchReportImportRef(
importRef,
binding,
locator.createImportHandle(importRef),
level == ACCURATE_MATCH
? SearchMatch.A_ACCURATE
: SearchMatch.A_INACCURATE,
locator);
}
}
/**
* Reports the match of the given import reference.
*/
protected void matchReportImportRef(ImportReference importRef, Binding binding, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
if (locator.encloses(element)) {
// default is to report a match as a regular ref.
this.matchReportReference(importRef, element, accuracy, locator);
}
}
/**
* Reports the match of the given reference.
*/
protected void matchReportReference(ASTNode reference, IJavaElement element, int accuracy, MatchLocator locator) throws CoreException {
SearchMatch match = null;
int referenceType = referenceType();
int offset = reference.sourceStart;
switch (referenceType) {
case IJavaElement.PACKAGE_FRAGMENT:
match = locator.newPackageReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
break;
case IJavaElement.TYPE:
match = locator.newTypeReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
break;
case IJavaElement.FIELD:
match = locator.newFieldReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
break;
case IJavaElement.METHOD:
match = locator.newMethodReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
break;
case IJavaElement.LOCAL_VARIABLE:
match = locator.newLocalVariableReferenceMatch(element, accuracy, offset, reference.sourceEnd-offset+1, reference);
break;
}
if (match != null) {
locator.report(match);
}
}
protected int referenceType() {
return 0; // defaults to unknown (a generic JavaSearchMatch will be created)
}
/**
* Finds out whether the given ast node matches this search pattern.
* Returns IMPOSSIBLE_MATCH if it doesn't.
* Returns INACCURATE_MATCH if it potentially matches this search pattern (ie.
* it has already been resolved but resolving failed.)
* Returns ACCURATE_MATCH if it matches exactly this search pattern (ie.
* it doesn't need to be resolved or it has already been resolved.)
*/
public int resolveLevel(ASTNode possibleMatchingNode) {
// only called with nodes which were possible matches to the call to matchLevel
// need to do instance of checks to find out exact type of ASTNode
return IMPOSSIBLE_MATCH;
}
/**
* 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.
* Returns IMPOSSIBLE_MATCH otherwise.
* Default is to return INACCURATE_MATCH.
*/
public int resolveLevel(Binding binding) {
// override if the pattern can match the binding
return INACCURATE_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 resolveLevelForType(char[] simpleNamePattern, char[] qualificationPattern, TypeBinding type) {
return resolveLevelForType(qualifiedPattern(simpleNamePattern, qualificationPattern), type);
}
/**
* Returns whether the given type binding matches the given qualified pattern.
* Returns ACCURATE_MATCH if it does.
* Returns INACCURATE_MATCH if resolve failed.
* Returns IMPOSSIBLE_MATCH if it doesn't.
*/
protected int resolveLevelForType(char[] qualifiedPattern, TypeBinding type) {
if (qualifiedPattern == null) return ACCURATE_MATCH;
if (type == null) return INACCURATE_MATCH;
// NOTE: if case insensitive search then qualifiedPattern is assumed to be lowercase
char[] qualifiedPackageName = type.qualifiedPackageName();
char[] qualifiedSourceName = qualifiedSourceName(type);
char[] fullyQualifiedTypeName = qualifiedPackageName.length == 0
? qualifiedSourceName
: CharOperation.concat(qualifiedPackageName, qualifiedSourceName, '.');
return CharOperation.match(qualifiedPattern, fullyQualifiedTypeName, this.isCaseSensitive)
? ACCURATE_MATCH
: IMPOSSIBLE_MATCH;
}
public String toString(){
return "SearchPattern"; //$NON-NLS-1$
}
}