blob: 0b95a2c19ed4b5e2ec2f001747e0cba8197ca9db [file] [log] [blame]
package org.eclipse.jdt.internal.core.search.matching;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.util.*;
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 MethodReferencePattern extends MethodPattern {
public char[][][] allSuperDeclaringTypeNames;
public MethodReferencePattern(
char[] selector,
int matchMode,
boolean isCaseSensitive,
char[] declaringQualification,
char[] declaringSimpleName,
char[] returnQualification,
char[] returnSimpleName,
char[][] parameterQualifications,
char[][] parameterSimpleNames) {
super(matchMode, isCaseSensitive);
this.selector = isCaseSensitive ? selector : CharOperation.toLowerCase(selector);
this.declaringQualification = isCaseSensitive ? declaringQualification : CharOperation.toLowerCase(declaringQualification);
this.declaringSimpleName = isCaseSensitive ? declaringSimpleName : CharOperation.toLowerCase(declaringSimpleName);
this.returnQualification = isCaseSensitive ? returnQualification : CharOperation.toLowerCase(returnQualification);
this.returnSimpleName = isCaseSensitive ? returnSimpleName : CharOperation.toLowerCase(returnSimpleName);
if (parameterSimpleNames != null){
this.parameterQualifications = new char[parameterSimpleNames.length][];
this.parameterSimpleNames = new char[parameterSimpleNames.length][];
for (int i = 0, max = parameterSimpleNames.length; i < max; i++){
this.parameterQualifications[i] = isCaseSensitive ? parameterQualifications[i] : CharOperation.toLowerCase(parameterQualifications[i]);
this.parameterSimpleNames[i] = isCaseSensitive ? parameterSimpleNames[i] : CharOperation.toLowerCase(parameterSimpleNames[i]);
}
}
this.needsResolve = this.needsResolve();
}
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));
decodedSelector = CharOperation.subarray(word, METHOD_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.acceptMethodReference(path, decodedSelector, decodedParameterCount);
}
}
}
public String getPatternName(){
return "MethodReferencePattern: "; //$NON-NLS-1$
}
/**
* @see SearchPattern#indexEntryPrefix
*/
public char[] indexEntryPrefix() {
return AbstractIndexer.bestMethodReferencePrefix(
selector,
parameterSimpleNames == null ? -1 : parameterSimpleNames.length,
matchMode,
isCaseSensitive);
}
/**
* @see SearchPattern#matchContainer()
*/
protected int matchContainer() {
return METHOD | FIELD;
}
public boolean initializeFromLookupEnvironment(LookupEnvironment env) {
this.allSuperDeclaringTypeNames = this.collectSuperTypeNames(this.declaringQualification, this.declaringSimpleName, this.matchMode, env);
return this.allSuperDeclaringTypeNames == null || this.allSuperDeclaringTypeNames != NOT_FOUND_DECLARING_TYPE;
}
/**
* Returns whether the code gen will use an invoke virtual for
* this message send or not.
*/
private boolean isVirtualInvoke(MethodBinding method, MessageSend messageSend) {
return !method.isStatic() && !messageSend.isSuperAccess() && !method.isPrivate();
}
/**
* @see SearchPattern#matchLevel(AstNode, boolean)
*/
public int matchLevel(AstNode node, boolean resolve) {
if (!(node instanceof MessageSend)) return IMPOSSIBLE_MATCH;
MessageSend messageSend = (MessageSend)node;
if (resolve) {
return this.matchLevel(messageSend.binding, messageSend);
} else {
// selector
if (this.selector != null && !this.matchesName(this.selector, messageSend.selector))
return IMPOSSIBLE_MATCH;
// argument types
int argumentCount = this.parameterSimpleNames == null ? -1 : this.parameterSimpleNames.length;
if (argumentCount > -1) {
int parameterCount = messageSend.arguments == null ? 0 : messageSend.arguments.length;
if (parameterCount != argumentCount)
return IMPOSSIBLE_MATCH;
}
return POSSIBLE_MATCH;
}
}
/**
* @see SearchPattern#matchLevel(Binding)
*/
public int matchLevel(Binding binding, MessageSend messageSend) {
if (binding == null) return INACCURATE_MATCH;
if (!(binding instanceof MethodBinding)) return IMPOSSIBLE_MATCH;
int level;
MethodBinding method = (MethodBinding)binding;
// selector
if (this.selector != null && !this.matchesName(this.selector, method.selector))
return IMPOSSIBLE_MATCH;
// receiver type
ReferenceBinding receiverType =
binding == null ?
null :
(!isVirtualInvoke(method, messageSend) ? method.declaringClass : (ReferenceBinding)messageSend.receiverType);
if (this.isVirtualInvoke(method, messageSend)) {
level = this.matchLevelAsSubtype(receiverType, this.declaringSimpleName, this.declaringQualification);
if (level == IMPOSSIBLE_MATCH) {
level = this.matchLevelForType(this.allSuperDeclaringTypeNames, receiverType);
if (level == IMPOSSIBLE_MATCH) {
return IMPOSSIBLE_MATCH;
}
}
} else {
level = this.matchLevelForType(this.declaringSimpleName, this.declaringQualification, receiverType);
if (level == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
}
// return type
int newLevel = this.matchLevelForType(this.returnSimpleName, this.returnQualification, method.returnType);
switch (newLevel) {
case IMPOSSIBLE_MATCH:
return IMPOSSIBLE_MATCH;
case ACCURATE_MATCH: // keep previous level
break;
default: // ie. INACCURATE_MATCH
level = newLevel;
break;
}
// 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];
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;
}
}