Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Samrat Dhillon [email protected] - Search for method references is
* returning methods as overriden even if the superclass's method is
* only package-visible - https://bugs.eclipse.org/357547
*******************************************************************************/
package org.eclipse.jdt.internal.core.search.matching;
import java.util.Arrays;
import java.util.HashMap;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.eclipse.jdt.internal.core.BinaryMethod;
import org.eclipse.jdt.internal.core.search.BasicSearchEngine;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class MethodLocator extends PatternLocator {
protected MethodPattern pattern;
protected boolean isDeclarationOfReferencedMethodsPattern;
//extra reference info
public char[][][] allSuperDeclaringTypeNames;
// This is set only if focus is null. In these cases
// it will be hard to determine if the super class is of the same package
// at a latter point. Hence, this array is created with all the super class
// names of the same package name as of the matching class name.
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=357547
private char[][][] samePkgSuperDeclaringTypeNames;
private MatchLocator matchLocator;
//method declarations which parameters verification fail
private HashMap methodDeclarationsWithInvalidParam = new HashMap();
public MethodLocator(MethodPattern pattern) {
super(pattern);
this.pattern = pattern;
this.isDeclarationOfReferencedMethodsPattern = this.pattern instanceof DeclarationOfReferencedMethodsPattern;
}
/*
* Clear caches
*/
protected void clear() {
this.methodDeclarationsWithInvalidParam = new HashMap();
}
protected int fineGrain() {
return this.pattern.fineGrain;
}
private ReferenceBinding getMatchingSuper(ReferenceBinding binding) {
if (binding == null) return null;
ReferenceBinding superBinding = binding.superclass();
int level = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, superBinding);
if (level != IMPOSSIBLE_MATCH) return superBinding;
// matches superclass
if (!binding.isInterface() && !CharOperation.equals(binding.compoundName, TypeConstants.JAVA_LANG_OBJECT)) {
superBinding = getMatchingSuper(superBinding);
if (superBinding != null) return superBinding;
}
// matches interfaces
ReferenceBinding[] interfaces = binding.superInterfaces();
if (interfaces == null) return null;
for (int i = 0; i < interfaces.length; i++) {
level = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, interfaces[i]);
if (level != IMPOSSIBLE_MATCH) return interfaces[i];
superBinding = getMatchingSuper(interfaces[i]);
if (superBinding != null) return superBinding;
}
return null;
}
private MethodBinding getMethodBinding(ReferenceBinding type, char[] methodName, TypeBinding[] argumentTypes) {
MethodBinding[] methods = type.getMethods(methodName);
MethodBinding method = null;
methodsLoop: for (int i=0, length=methods.length; i newLevel) {
if (newLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
level = newLevel; // can only be downgraded
}
}
// parameter types
int parameterCount = this.pattern.parameterSimpleNames == null ? -1 : this.pattern.parameterSimpleNames.length;
if (parameterCount > -1) {
// global verification
if (method.parameters == null) return INACCURATE_MATCH;
if (parameterCount != method.parameters.length) return IMPOSSIBLE_MATCH;
if (!method.isValidBinding() && ((ProblemMethodBinding)method).problemId() == ProblemReasons.Ambiguous) {
// return inaccurate match for ambiguous call (bug 80890)
return INACCURATE_MATCH;
}
boolean foundTypeVariable = false;
MethodBinding focusMethodBinding = null;
boolean checkedFocus = false;
boolean isBinary = this.pattern!= null && this.pattern.focus instanceof BinaryMethod;
// verify each parameter
for (int i = 0; i < parameterCount; i++) {
TypeBinding argType = method.parameters[i];
int newLevel = IMPOSSIBLE_MATCH;
boolean foundLevel = false;
if (argType.isMemberType() || this.pattern.parameterQualifications[i] != null) {
if (!checkedFocus) {
focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
checkedFocus = true;
}
if (focusMethodBinding != null) {// textual comparison insufficient
TypeBinding[] parameters = focusMethodBinding.parameters;
if (parameters.length >= parameterCount) {
newLevel = (isBinary ? argType.erasure().isEquivalentTo((parameters[i].erasure())) :argType.isEquivalentTo((parameters[i]))) ?
ACCURATE_MATCH : IMPOSSIBLE_MATCH;
foundLevel = true;
}
}
} else {
// TODO (frederic) use this call to refine accuracy on parameter types
// newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], this.pattern.parametersTypeArguments[i], 0, argType);
newLevel = resolveLevelForType(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i], argType);
}
if (level > newLevel) {
if (newLevel == IMPOSSIBLE_MATCH) {
if (skipImpossibleArg) {
// Do not consider match as impossible while finding declarations and source level >= 1.5
// (see bugs https://bugs.eclipse.org/bugs/show_bug.cgi?id=79990, 96761, 96763)
if (!foundLevel) {
newLevel = level;
}
} else if (argType.isTypeVariable()) {
newLevel = level;
foundTypeVariable = true;
} else {
return IMPOSSIBLE_MATCH;
}
}
level = newLevel; // can only be downgraded
}
}
if (foundTypeVariable) {
if (!method.isStatic() && !method.isPrivate()) {
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=123836, No point in textually comparing type variables, captures etc with concrete types.
if (!checkedFocus)
focusMethodBinding = this.matchLocator.getMethodBinding(this.pattern);
if (focusMethodBinding != null) {
if (matchOverriddenMethod(focusMethodBinding.declaringClass, focusMethodBinding, method)) {
return ACCURATE_MATCH;
}
}
}
return IMPOSSIBLE_MATCH;
}
}
return level;
}
// This works for only methods of parameterized types.
private boolean matchOverriddenMethod(ReferenceBinding type, MethodBinding method, MethodBinding matchMethod) {
if (type == null || this.pattern.selector == null) return false;
// matches superclass
if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) {
ReferenceBinding superClass = type.superclass();
if (superClass.isParameterizedType()) {
MethodBinding[] methods = superClass.getMethods(this.pattern.selector);
int length = methods.length;
for (int i = 0; i>> 32);
this.match.setOffset(offset);
this.match.setLength(messageSend.sourceEnd - offset + 1);
if (isParameterized && this.pattern.hasMethodArguments()) {
locator.reportAccurateParameterizedMethodReference(this.match, messageSend, messageSend.typeArguments);
} else {
locator.report(this.match);
}
}
/*
* Return whether method parameters are equals to pattern ones.
*/
private boolean methodParametersEqualsPattern(MethodBinding method) {
TypeBinding[] methodParameters = method.parameters;
int length = methodParameters.length;
if (length != this.pattern.parameterSimpleNames.length) return false;
for (int i = 0; i < length; i++) {
char[] paramQualifiedName = qualifiedPattern(this.pattern.parameterSimpleNames[i], this.pattern.parameterQualifications[i]);
if (!CharOperation.match(paramQualifiedName, methodParameters[i].readableName(), this.isCaseSensitive)) {
return false;
}
}
return true;
}
public SearchMatch newDeclarationMatch(ASTNode reference, IJavaElement element, Binding elementBinding, int accuracy, int length, MatchLocator locator) {
if (elementBinding != null) {
MethodBinding methodBinding = (MethodBinding) elementBinding;
// If method parameters verification was not valid, then try to see if method arguments can match a method in hierarchy
if (this.methodDeclarationsWithInvalidParam.containsKey(reference)) {
// First see if this reference has already been resolved => report match if validated
Boolean report = (Boolean) this.methodDeclarationsWithInvalidParam.get(reference);
if (report != null) {
if (report.booleanValue()) {
return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
}
return null;
}
if (matchOverriddenMethod(methodBinding.declaringClass, methodBinding, null)) {
this.methodDeclarationsWithInvalidParam.put(reference, Boolean.TRUE);
return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
}
if (isTypeInSuperDeclaringTypeNames(methodBinding.declaringClass.compoundName)) {
MethodBinding patternBinding = locator.getMethodBinding(this.pattern);
if (patternBinding != null) {
if (!matchOverriddenMethod(patternBinding.declaringClass, patternBinding, methodBinding)) {
this.methodDeclarationsWithInvalidParam.put(reference, Boolean.FALSE);
return null;
}
}
this.methodDeclarationsWithInvalidParam.put(reference, Boolean.TRUE);
return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
}
this.methodDeclarationsWithInvalidParam.put(reference, Boolean.FALSE);
return null;
}
}
return super.newDeclarationMatch(reference, element, elementBinding, accuracy, length, locator);
}
protected int referenceType() {
return IJavaElement.METHOD;
}
protected void reportDeclaration(MethodBinding methodBinding, MatchLocator locator, SimpleSet knownMethods) throws CoreException {
ReferenceBinding declaringClass = methodBinding.declaringClass;
IType type = locator.lookupType(declaringClass);
if (type == null) return; // case of a secondary type
// Report match for binary
if (type.isBinary()) {
IMethod method = null;
TypeBinding[] parameters = methodBinding.original().parameters;
int parameterLength = parameters.length;
char[][] parameterTypes = new char[parameterLength][];
for (int i = 0; i (declaringLevel & MATCH_LEVEL_MASK) ? declaringLevel : methodLevel; // return the weaker match
}
protected int resolveLevel(MessageSend messageSend) {
MethodBinding method = messageSend.binding;
if (method == null) {
return INACCURATE_MATCH;
}
if (messageSend.resolvedType == null) {
// Closest match may have different argument numbers when ProblemReason is NotFound
// see MessageSend#resolveType(BlockScope)
// see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=97322
int argLength = messageSend.arguments == null ? 0 : messageSend.arguments.length;
if (this.pattern.parameterSimpleNames == null || argLength == this.pattern.parameterSimpleNames.length) {
return INACCURATE_MATCH;
}
return IMPOSSIBLE_MATCH;
}
int methodLevel = matchMethod(method, false);
if (methodLevel == IMPOSSIBLE_MATCH) {
if (method != method.original()) methodLevel = matchMethod(method.original(), false);
if (methodLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
method = method.original();
}
// receiver type
if (this.pattern.declaringSimpleName == null && this.pattern.declaringQualification == null) return methodLevel; // since any declaring class will do
int declaringLevel;
if (isVirtualInvoke(method, messageSend) && (messageSend.actualReceiverType instanceof ReferenceBinding)) {
ReferenceBinding methodReceiverType = (ReferenceBinding) messageSend.actualReceiverType;
declaringLevel = resolveLevelAsSubtype(this.pattern.declaringSimpleName, this.pattern.declaringQualification, methodReceiverType, method.selector, method.parameters, methodReceiverType.qualifiedPackageName(), method.isDefault());
if (declaringLevel == IMPOSSIBLE_MATCH) {
if (method.declaringClass == null || this.allSuperDeclaringTypeNames == null) {
declaringLevel = INACCURATE_MATCH;
} else {
char[][][] superTypeNames = (method.isDefault() && this.pattern.focus == null) ? this.samePkgSuperDeclaringTypeNames: this.allSuperDeclaringTypeNames;
if (superTypeNames != null && resolveLevelAsSuperInvocation(methodReceiverType, method.parameters, superTypeNames, true)) {
declaringLevel = methodLevel // since this is an ACCURATE_MATCH so return the possibly weaker match
| SUPER_INVOCATION_FLAVOR; // this is an overridden method => add flavor to returned level
}
}
}
if ((declaringLevel & FLAVORS_MASK) != 0) {
// level got some flavors => return it
return declaringLevel;
}
} else {
declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, method.declaringClass);
}
return (methodLevel & MATCH_LEVEL_MASK) > (declaringLevel & MATCH_LEVEL_MASK) ? declaringLevel : methodLevel; // return the weaker match
}
protected int resolveLevel(ReferenceExpression referenceExpression) {
MethodBinding method = referenceExpression.getMethodBinding();
if (method == null || !method.isValidBinding())
return INACCURATE_MATCH;
int methodLevel = matchMethod(method, false);
if (methodLevel == IMPOSSIBLE_MATCH) {
if (method != method.original()) methodLevel = matchMethod(method.original(), false);
if (methodLevel == IMPOSSIBLE_MATCH) return IMPOSSIBLE_MATCH;
method = method.original();
}
// receiver type
if (this.pattern.declaringSimpleName == null && this.pattern.declaringQualification == null) return methodLevel; // since any declaring class will do
int declaringLevel;
ReferenceBinding ref = checkMethodRef(method, referenceExpression);
if (ref != null) {
declaringLevel = resolveLevelAsSubtype(this.pattern.declaringSimpleName, this.pattern.declaringQualification, ref, method.selector, method.parameters, ref.qualifiedPackageName(), method.isDefault());
if (declaringLevel == IMPOSSIBLE_MATCH) {
if (method.declaringClass == null || this.allSuperDeclaringTypeNames == null) {
declaringLevel = INACCURATE_MATCH;
} else {
char[][][] superTypeNames = (method.isDefault() && this.pattern.focus == null) ? this.samePkgSuperDeclaringTypeNames: this.allSuperDeclaringTypeNames;
if (superTypeNames != null && resolveLevelAsSuperInvocation(ref, method.parameters, superTypeNames, true)) {
declaringLevel = methodLevel // since this is an ACCURATE_MATCH so return the possibly weaker match
| SUPER_INVOCATION_FLAVOR; // TODO: not an invocation really but ref -> add flavor to returned level
}
}
}
if ((declaringLevel & FLAVORS_MASK) != 0) {
// level got some flavors => return it
return declaringLevel;
}
} else {
declaringLevel = resolveLevelForType(this.pattern.declaringSimpleName, this.pattern.declaringQualification, method.declaringClass);
}
return (methodLevel & MATCH_LEVEL_MASK) > (declaringLevel & MATCH_LEVEL_MASK) ? declaringLevel : methodLevel; // return the weaker match
}
/**
* Returns whether the given reference type binding matches or is a subtype of a type
* that matches the given qualified pattern.
* Returns ACCURATE_MATCH if it does.
* Returns INACCURATE_MATCH if resolve fails
* Returns IMPOSSIBLE_MATCH if it doesn't.
*/
protected int resolveLevelAsSubtype(char[] simplePattern, char[] qualifiedPattern, ReferenceBinding type, char[] methodName, TypeBinding[] argumentTypes, char[] packageName, boolean isDefault) {
if (type == null) return INACCURATE_MATCH;
int level = resolveLevelForType(simplePattern, qualifiedPattern, type);
if (level != IMPOSSIBLE_MATCH) {
if (isDefault && !CharOperation.equals(packageName, type.qualifiedPackageName())) {
return IMPOSSIBLE_MATCH;
}
MethodBinding method = argumentTypes == null ? null : getMethodBinding(type, methodName, argumentTypes);
if (((method != null && !method.isAbstract()) || !type.isAbstract()) && !type.isInterface()) { // if concrete, then method is overridden
level |= OVERRIDDEN_METHOD_FLAVOR;
}
return level;
}
// matches superclass
if (!type.isInterface() && !CharOperation.equals(type.compoundName, TypeConstants.JAVA_LANG_OBJECT)) {
level = resolveLevelAsSubtype(simplePattern, qualifiedPattern, type.superclass(), methodName, argumentTypes, packageName, isDefault);
if (level != IMPOSSIBLE_MATCH) {
if (argumentTypes != null) {
// need to verify if method may be overridden
MethodBinding method = getMethodBinding(type, methodName, argumentTypes);
if (method != null) { // one method match in hierarchy
if ((level & OVERRIDDEN_METHOD_FLAVOR) != 0) {
// this method is already overridden on a super class, current match is impossible
return IMPOSSIBLE_MATCH;
}
if (!method.isAbstract() && !type.isInterface()) {
// store the fact that the method is overridden
level |= OVERRIDDEN_METHOD_FLAVOR;
}
}
}
return level | SUB_INVOCATION_FLAVOR; // add flavor to returned level
}
}
// matches interfaces
ReferenceBinding[] interfaces = type.superInterfaces();
if (interfaces == null) return INACCURATE_MATCH;
for (int i = 0; i < interfaces.length; i++) {
level = resolveLevelAsSubtype(simplePattern, qualifiedPattern, interfaces[i], methodName, null, packageName, isDefault);
if (level != IMPOSSIBLE_MATCH) {
if (!type.isAbstract() && !type.isInterface()) { // if concrete class, then method is overridden
level |= OVERRIDDEN_METHOD_FLAVOR;
}
return level | SUB_INVOCATION_FLAVOR; // add flavor to returned level
}
}
return IMPOSSIBLE_MATCH;
}
/*
* Return whether the given type binding or one of its possible super interfaces
* matches a type in the declaring type names hierarchy.
*/
private boolean resolveLevelAsSuperInvocation(ReferenceBinding type, TypeBinding[] argumentTypes, char[][][] superTypeNames, boolean methodAlreadyVerified) {
char[][] compoundName = type.compoundName;
for (int i = 0, max = superTypeNames.length; i < max; i++) {
if (CharOperation.equals(superTypeNames[i], compoundName)) {
// need to verify if the type implements the pattern method
if (methodAlreadyVerified) return true; // already verified before enter into this method (see resolveLevel(MessageSend))
MethodBinding[] methods = type.getMethods(this.pattern.selector);
for (int j=0, length=methods.length; j