blob: 6c3143e9e92468d7033ea4063dad3652c2919d80 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 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 java.io.IOException;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
import org.eclipse.jdt.internal.compiler.ast.AstNode;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.core.index.IEntryResult;
import org.eclipse.jdt.internal.core.index.impl.IndexInput;
import org.eclipse.jdt.internal.core.index.impl.IndexedFile;
import org.eclipse.jdt.internal.core.search.IIndexSearchRequestor;
import org.eclipse.jdt.internal.core.search.indexing.AbstractIndexer;
/**
* The selector is unused, the constructor name is specified by the type simple name.
*/
public class ConstructorReferencePattern extends MethodReferencePattern {
private char[] decodedTypeName;
public ConstructorReferencePattern(
char[] declaringSimpleName,
int matchMode,
boolean isCaseSensitive,
char[] declaringQualification,
char[][] parameterQualifications,
char[][] parameterSimpleNames,
IType declaringType) {
super(
null,
matchMode,
isCaseSensitive,
declaringQualification,
declaringSimpleName,
null,
null,
parameterQualifications,
parameterSimpleNames,
declaringType);
}
public void decodeIndexEntry(IEntryResult entryResult){
char[] word = entryResult.getWord();
int size = word.length;
int lastSeparatorIndex = CharOperation.lastIndexOf(SEPARATOR, word);
decodedParameterCount = Integer.parseInt(new String(word, lastSeparatorIndex + 1, size - lastSeparatorIndex - 1));
decodedTypeName = CharOperation.subarray(word, CONSTRUCTOR_REF.length, lastSeparatorIndex);
}
/**
* see SearchPattern.feedIndexRequestor
*/
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++) {
IndexedFile file = input.getIndexedFile(references[i]);
String path;
if (file != null && scope.encloses(path = IndexedFile.convertPath(file.getPath()))) {
requestor.acceptConstructorReference(path, decodedTypeName, decodedParameterCount);
}
}
}
/**
* @see SearchPattern#indexEntryPrefix
*/
public char[] indexEntryPrefix() {
return AbstractIndexer.bestConstructorReferencePrefix(
declaringSimpleName,
parameterSimpleNames == null ? -1 : parameterSimpleNames.length,
matchMode,
isCaseSensitive);
}
/**
* @see SearchPattern#matchContainer()
*/
protected int matchContainer() {
return
COMPILATION_UNIT // implicit constructor call: case of Y extends X and Y doesn't define any constructor
| CLASS // implicit constructor call: case of constructor declaration with no explicit super call
| METHOD // reference in another constructor
| FIELD; // anonymous in a field initializer
}
/**
* @see SearchPattern#matchIndexEntry
*/
protected boolean matchIndexEntry() {
/* check selector matches */
if (declaringSimpleName != null){
switch(matchMode){
case EXACT_MATCH :
if (!CharOperation.equals(declaringSimpleName, decodedTypeName, isCaseSensitive)){
return false;
}
break;
case PREFIX_MATCH :
if (!CharOperation.prefixEquals(declaringSimpleName, decodedTypeName, isCaseSensitive)){
return false;
}
break;
case PATTERN_MATCH :
if (!CharOperation.match(declaringSimpleName, decodedTypeName, isCaseSensitive)){
return false;
}
}
}
if (parameterSimpleNames != null){
if (parameterSimpleNames.length != decodedParameterCount) return false;
}
return true;
}
public String toString(){
StringBuffer buffer = new StringBuffer(20);
buffer.append("ConstructorReferencePattern: "); //$NON-NLS-1$
if (declaringQualification != null) buffer.append(declaringQualification).append('.');
if (declaringSimpleName != null)
buffer.append(declaringSimpleName);
else if (declaringQualification != null) buffer.append("*"); //$NON-NLS-1$
buffer.append('(');
if (parameterSimpleNames == null) {
buffer.append("..."); //$NON-NLS-1$
} else {
for (int i = 0, max = parameterSimpleNames.length; i < max; i++){
if (i > 0) buffer.append(", "); //$NON-NLS-1$
if (parameterQualifications[i] != null) buffer.append(parameterQualifications[i]).append('.');
if (parameterSimpleNames[i] == null) buffer.append('*'); else buffer.append(parameterSimpleNames[i]);
}
}
buffer.append(')');
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();
}
/**
* Returns whether this constructor pattern matches the given allocation expression.
* Look at resolved information only if specified.
*/
private int matchLevel(AllocationExpression allocation, boolean resolve) {
// constructor name is simple type name
char[][] typeName = allocation.type.getTypeName();
if (this.declaringSimpleName != null
&& !this.matchesName(this.declaringSimpleName, typeName[typeName.length-1]))
return IMPOSSIBLE_MATCH;
if (resolve) {
return this.matchLevel(allocation.binding);
} else {
// argument types
int argumentCount = this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
if (argumentCount > -1) {
int parameterCount = allocation.arguments == null ? 0 : allocation.arguments.length;
if (parameterCount != argumentCount)
return IMPOSSIBLE_MATCH;
}
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
}
}
/**
* @see SearchPattern#matchLevel(AstNode, boolean)
*/
public int matchLevel(AstNode node, boolean resolve) {
if (node instanceof AllocationExpression) {
return this.matchLevel((AllocationExpression)node, resolve);
} else if (node instanceof ExplicitConstructorCall) {
return this.matchLevel((ExplicitConstructorCall)node, resolve);
} else if (node instanceof ConstructorDeclaration) {
return this.matchLevel((ConstructorDeclaration)node, resolve);
} else if (node instanceof TypeDeclaration) {
return this.matchLevel((TypeDeclaration)node, resolve);
}
return IMPOSSIBLE_MATCH;
}
/**
* Returns whether the given constructor declaration has an implicit constructor reference that matches
* this constructor pattern.
* Look at resolved information only if specified.
*/
private int matchLevel(ConstructorDeclaration constructor, boolean resolve) {
ExplicitConstructorCall constructorCall = constructor.constructorCall;
if (constructorCall != null && constructorCall.accessMode == ExplicitConstructorCall.ImplicitSuper) {
return this.matchLevel(constructorCall, resolve);
} else {
// Eliminate explicit super call as it will be treated with matchLevel(ExplicitConstructorCall, boolean)
return IMPOSSIBLE_MATCH;
}
}
/**
* Returns whether this constructor pattern matches the given explicit constructor call.
* Look at resolved information only if specified.
*/
private int matchLevel(ExplicitConstructorCall call, boolean resolve) {
if (resolve) {
return this.matchLevel(call.binding);
} else {
// argument types
int argumentCount = this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
if (argumentCount > -1) {
int parameterCount = call.arguments == null ? 0 : call.arguments.length;
if (parameterCount != argumentCount)
return IMPOSSIBLE_MATCH;
}
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
}
}
/**
* Returns whether the given type declaration has an implicit constructor reference that matches
* this constructor pattern.
* Look at resolved information only if specified.
*/
private int matchLevel(TypeDeclaration type, boolean resolve) {
if (resolve) {
// find default constructor
AbstractMethodDeclaration[] methods = type.methods;
if (methods != null) {
for (int i = 0, length = methods.length; i < length; i++) {
AbstractMethodDeclaration method = methods[i];
if (method.isDefaultConstructor()
&& method.sourceStart < type.bodyStart) { // if synthetic
return this.matchLevel((ConstructorDeclaration)method, true);
}
}
}
return IMPOSSIBLE_MATCH;
} else {
// Need to wait for all the constructor bodies to have been parsed
return this.needsResolve ? POSSIBLE_MATCH : ACCURATE_MATCH;
}
}
/**
* @see SearchPattern#matchLevel(Binding binding).
*/
public int matchLevel(Binding binding) {
if (binding == null) return INACCURATE_MATCH;
if (!(binding instanceof MethodBinding)) return IMPOSSIBLE_MATCH;
int level;
// declaring type
MethodBinding method = (MethodBinding)binding;
ReferenceBinding declaringBinding = method.declaringClass;
level = this.matchLevelForType(this.declaringSimpleName, this.declaringQualification, declaringBinding);
if (level == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
// argument types
int argumentCount = this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
if (argumentCount > -1) {
if (method.parameters == null) {
level = INACCURATE_MATCH;
} else {
int parameterCount = method.parameters.length;
if (parameterCount != argumentCount)
return IMPOSSIBLE_MATCH;
for (int i = 0; i < parameterCount; i++) {
char[] qualification = this.parameterQualifications[i];
char[] type = this.parameterSimpleNames[i];
int newLevel = this.matchLevelForType(type, qualification, method.parameters[i]);
switch (newLevel) {
case IMPOSSIBLE_MATCH:
return IMPOSSIBLE_MATCH;
case ACCURATE_MATCH: // keep previous level
break;
default: // ie. INACCURATE_MATCH
level = newLevel;
break;
}
}
}
}
return level;
}
}