blob: 92b2a65e4a03c9d0e1fe2fe5ea3912a1e16ec726 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.codeassist.ISelectionRequestor;
import org.eclipse.jdt.internal.codeassist.SelectionEngine;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.CastExpression;
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.core.NameLookup.Answer;
import org.eclipse.jdt.internal.core.util.HandleFactory;
import org.eclipse.jdt.internal.core.util.Util;
import org.eclipse.objectteams.otdt.core.IMethodMapping;
import org.eclipse.objectteams.otdt.core.IMethodSpec;
import org.eclipse.objectteams.otdt.core.IOTJavaElement;
import org.eclipse.objectteams.otdt.core.IOTType;
import org.eclipse.objectteams.otdt.core.IRoleType;
import org.eclipse.objectteams.otdt.core.OTModelManager;
import org.eclipse.objectteams.otdt.internal.core.MethodMapping;
/**
* Implementation of <code>ISelectionRequestor</code> to assist with
* code resolve in a compilation unit. Translates names to elements.
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class SelectionRequestor implements ISelectionRequestor {
/*
* The name lookup facility used to resolve packages
*/
protected NameLookup nameLookup;
/*
* The compilation unit or class file we are resolving in
*/
protected Openable openable;
/*
* The collection of resolved elements.
*/
protected IJavaElement[] elements = JavaElement.NO_ELEMENTS;
protected int elementIndex = -1;
protected HandleFactory handleFactory = new HandleFactory();
/**
* Creates a selection requestor that uses that given
* name lookup facility to resolve names.
*
* Fix for 1FVXGDK
*/
public SelectionRequestor(NameLookup nameLookup, Openable openable) {
super();
this.nameLookup = nameLookup;
this.openable = openable;
}
private void acceptBinaryMethod(
IType type,
IMethod method,
char[] uniqueKey,
boolean isConstructor) {
try {
if(!isConstructor || ((JavaElement)method).getClassFile().getBuffer() == null) {
if (uniqueKey != null) {
ResolvedBinaryMethod resolvedMethod = new ResolvedBinaryMethod(
(JavaElement)method.getParent(),
method.getElementName(),
method.getParameterTypes(),
new String(uniqueKey));
resolvedMethod.occurrenceCount = method.getOccurrenceCount();
method = resolvedMethod;
}
addElement(method);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept method("); //$NON-NLS-1$
System.out.print(method.toString());
System.out.println(")"); //$NON-NLS-1$
}
} else {
ISourceRange range = method.getSourceRange();
if (range.getOffset() != -1 && range.getLength() != 0 ) {
if (uniqueKey != null) {
ResolvedBinaryMethod resolvedMethod = new ResolvedBinaryMethod(
(JavaElement)method.getParent(),
method.getElementName(),
method.getParameterTypes(),
new String(uniqueKey));
resolvedMethod.occurrenceCount = method.getOccurrenceCount();
method = resolvedMethod;
}
addElement(method);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept method("); //$NON-NLS-1$
System.out.print(method.toString());
System.out.println(")"); //$NON-NLS-1$
}
} else {
// no range was actually found, but a method was originally given -> default constructor
addElement(type);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(type.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
} catch (JavaModelException e) {
// an exception occurs, return nothing
}
}
/**
* Resolve the binary method
*
* fix for 1FWFT6Q
*/
protected void acceptBinaryMethod(
IType type,
char[] selector,
char[][] parameterPackageNames,
char[][] parameterTypeNames,
String[] parameterSignatures,
char[][] typeParameterNames,
char[][][] typeParameterBoundNames,
char[] uniqueKey,
boolean isConstructor) {
IMethod method= type.getMethod(new String(selector), parameterSignatures);
if (method.exists()) {
if (typeParameterNames != null && typeParameterNames.length != 0) {
IMethod[] methods = type.findMethods(method);
if (methods != null && methods.length > 1) {
for (int i = 0; i < methods.length; i++) {
if (areTypeParametersCompatible(methods[i], typeParameterNames, typeParameterBoundNames)) {
acceptBinaryMethod(type, method, uniqueKey, isConstructor);
}
}
return;
}
}
acceptBinaryMethod(type, method, uniqueKey, isConstructor);
}
}
@Override
public void acceptModule(char[] moduleName, char[] uniqueKey, int start, int end) {
IModuleDescription module = resolveModule(moduleName);
addElement(module);
}
/**
* Resolve the type.
*/
@Override
public void acceptType(char[] packageName, char[] typeName, int modifiers, boolean isDeclaration, char[] uniqueKey, int start, int end) {
int acceptFlags = 0;
int kind = modifiers & (ClassFileConstants.AccInterface|ClassFileConstants.AccEnum|ClassFileConstants.AccAnnotation);
switch (kind) {
case ClassFileConstants.AccAnnotation:
case ClassFileConstants.AccAnnotation|ClassFileConstants.AccInterface:
acceptFlags = NameLookup.ACCEPT_ANNOTATIONS;
break;
case ClassFileConstants.AccEnum:
acceptFlags = NameLookup.ACCEPT_ENUMS;
break;
case ClassFileConstants.AccInterface:
acceptFlags = NameLookup.ACCEPT_INTERFACES;
break;
default:
acceptFlags = NameLookup.ACCEPT_CLASSES;
break;
}
IType type = null;
if(isDeclaration) {
type = resolveTypeByLocation(packageName, typeName, acceptFlags, start, end);
} else {
type = resolveType(packageName, typeName, acceptFlags);
if(type != null ) {
String key = uniqueKey == null ? type.getKey() : new String(uniqueKey);
if(type.isBinary()) {
ResolvedBinaryType resolvedType = new ResolvedBinaryType((JavaElement)type.getParent(), type.getElementName(), key);
resolvedType.occurrenceCount = type.getOccurrenceCount();
type = resolvedType;
} else {
ResolvedSourceType resolvedType = new ResolvedSourceType((JavaElement)type.getParent(), type.getElementName(), key);
resolvedType.occurrenceCount = type.getOccurrenceCount();
type = resolvedType;
}
}
}
if (type != null) {
addElement(type);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(type.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
/**
* Resolve the type.
*/
public void acceptType(IType type) {
String key = type.getKey();
if(type.isBinary()) {
ResolvedBinaryType resolvedType = new ResolvedBinaryType((JavaElement)type.getParent(), type.getElementName(), key);
resolvedType.occurrenceCount = type.getOccurrenceCount();
type = resolvedType;
} else {
ResolvedSourceType resolvedType = new ResolvedSourceType((JavaElement)type.getParent(), type.getElementName(), key);
resolvedType.occurrenceCount = type.getOccurrenceCount();
type = resolvedType;
}
addElement(type);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(type.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
/**
* @see ISelectionRequestor#acceptError
*/
@Override
public void acceptError(CategorizedProblem error) {
// do nothing
}
/**
* Resolve the field.
*/
@Override
public void acceptField(char[] declaringTypePackageName, char[] declaringTypeName, char[] name, boolean isDeclaration, char[] uniqueKey, int start, int end) {
if(isDeclaration) {
IType type= resolveTypeByLocation(declaringTypePackageName, declaringTypeName,
NameLookup.ACCEPT_ALL,
start, end);
if(type != null) {
try {
IField[] fields = type.getFields();
for (int i = 0; i < fields.length; i++) {
IField field = fields[i];
ISourceRange range = field.getNameRange();
if(range.getOffset() <= start
&& range.getOffset() + range.getLength() >= end
&& field.getElementName().equals(new String(name))) {
addElement(fields[i]);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept field("); //$NON-NLS-1$
System.out.print(field.toString());
System.out.println(")"); //$NON-NLS-1$
}
return; // only one method is possible
}
}
} catch (JavaModelException e) {
return;
}
}
} else {
IType type= resolveType(declaringTypePackageName, declaringTypeName, NameLookup.ACCEPT_ALL);
if (type != null) {
IField field= type.getField(new String(name));
if (field.exists()) {
if (uniqueKey != null) {
if(field.isBinary()) {
ResolvedBinaryField resolvedField = new ResolvedBinaryField(
(JavaElement)field.getParent(),
field.getElementName(),
new String(uniqueKey));
resolvedField.occurrenceCount = field.getOccurrenceCount();
field = resolvedField;
} else {
ResolvedSourceField resolvedField = new ResolvedSourceField(
(JavaElement)field.getParent(),
field.getElementName(),
new String(uniqueKey));
resolvedField.occurrenceCount = field.getOccurrenceCount();
field = resolvedField;
}
}
addElement(field);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept field("); //$NON-NLS-1$
System.out.print(field.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
}
public void acceptLocalField(FieldBinding fieldBinding) {
IJavaElement res;
if(fieldBinding.declaringClass instanceof ParameterizedTypeBinding) {
LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)fieldBinding.declaringClass).genericType();
res = findLocalElement(localTypeBinding.sourceStart());
} else {
SourceTypeBinding typeBinding = (SourceTypeBinding)fieldBinding.declaringClass;
res = findLocalElement(typeBinding.sourceStart());
}
if (res != null && res.getElementType() == IJavaElement.TYPE) {
IType type = (IType) res;
IField field= type.getField(new String(fieldBinding.name));
if (field.exists()) {
char[] uniqueKey = fieldBinding.computeUniqueKey();
if(field.isBinary()) {
ResolvedBinaryField resolvedField = new ResolvedBinaryField(
(JavaElement)field.getParent(),
field.getElementName(),
new String(uniqueKey));
resolvedField.occurrenceCount = field.getOccurrenceCount();
field = resolvedField;
} else {
ResolvedSourceField resolvedField = new ResolvedSourceField(
(JavaElement)field.getParent(),
field.getElementName(),
new String(uniqueKey));
resolvedField.occurrenceCount = field.getOccurrenceCount();
field = resolvedField;
}
addElement(field);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept field("); //$NON-NLS-1$
System.out.print(field.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
public void acceptLocalMethod(MethodBinding methodBinding) {
IJavaElement res = findLocalElement(methodBinding.original().sourceStart());
if(res != null) {
if(res.getElementType() == IJavaElement.METHOD) {
IMethod method = (IMethod) res;
char[] uniqueKey = methodBinding.computeUniqueKey();
if(method.isBinary()) {
ResolvedBinaryMethod resolvedRes = new ResolvedBinaryMethod(
(JavaElement)res.getParent(),
method.getElementName(),
method.getParameterTypes(),
new String(uniqueKey));
resolvedRes.occurrenceCount = method.getOccurrenceCount();
res = resolvedRes;
} else {
ResolvedSourceMethod resolvedRes = new ResolvedSourceMethod(
(JavaElement)res.getParent(),
method.getElementName(),
method.getParameterTypes(),
new String(uniqueKey));
resolvedRes.occurrenceCount = method.getOccurrenceCount();
res = resolvedRes;
}
addElement(res);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept method("); //$NON-NLS-1$
System.out.print(res.toString());
System.out.println(")"); //$NON-NLS-1$
}
} else if(methodBinding.selector == TypeConstants.INIT && res.getElementType() == IJavaElement.TYPE) {
// it's a default constructor
res = ((JavaElement)res).resolved(methodBinding.declaringClass);
addElement(res);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(res.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
public void acceptLocalType(TypeBinding typeBinding) {
IJavaElement res = null;
if(typeBinding instanceof ParameterizedTypeBinding) {
LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)typeBinding).genericType();
res = findLocalElement(localTypeBinding.sourceStart());
} else if(typeBinding instanceof SourceTypeBinding) {
res = findLocalElement(((SourceTypeBinding)typeBinding).sourceStart());
}
if(res != null && res.getElementType() == IJavaElement.TYPE) {
res = ((JavaElement)res).resolved(typeBinding);
addElement(res);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(res.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
public void acceptLocalTypeParameter(TypeVariableBinding typeVariableBinding) {
IJavaElement res;
if(typeVariableBinding.declaringElement instanceof ParameterizedTypeBinding) {
LocalTypeBinding localTypeBinding = (LocalTypeBinding)((ParameterizedTypeBinding)typeVariableBinding.declaringElement).genericType();
res = findLocalElement(localTypeBinding.sourceStart());
} else {
SourceTypeBinding typeBinding = (SourceTypeBinding)typeVariableBinding.declaringElement;
res = findLocalElement(typeBinding.sourceStart());
}
if (res != null && res.getElementType() == IJavaElement.TYPE) {
IType type = (IType) res;
ITypeParameter typeParameter = type.getTypeParameter(new String(typeVariableBinding.sourceName));
if (typeParameter.exists()) {
addElement(typeParameter);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type parameter("); //$NON-NLS-1$
System.out.print(typeParameter.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
public void acceptLocalMethodTypeParameter(TypeVariableBinding typeVariableBinding) {
MethodBinding methodBinding = (MethodBinding)typeVariableBinding.declaringElement;
IJavaElement res = findLocalElement(methodBinding.sourceStart());
if(res != null && res.getElementType() == IJavaElement.METHOD) {
IMethod method = (IMethod) res;
ITypeParameter typeParameter = method.getTypeParameter(new String(typeVariableBinding.sourceName));
if (typeParameter.exists()) {
addElement(typeParameter);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type parameter("); //$NON-NLS-1$
System.out.print(typeParameter.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
public void acceptLocalVariable(LocalVariableBinding binding, org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit) {
LocalDeclaration local = binding.declaration;
IJavaElement parent = null;
if (binding.declaringScope.isLambdaSubscope() && unit instanceof ICompilationUnit) {
HashSet existingElements = new HashSet();
HashMap knownScopes = new HashMap();
parent = this.handleFactory.createElement(binding.declaringScope, local.sourceStart, (ICompilationUnit) unit, existingElements, knownScopes);
} else {
parent = findLocalElement(local.sourceStart, binding.declaringScope.methodScope()); // findLocalElement() cannot find local variable
}
LocalVariable localVar = null;
if(parent != null) {
//{ObjectTeams: play safe:
if (parent instanceof IOTJavaElement)
parent = ((IOTJavaElement)parent).getCorrespondingJavaElement();
// SH}
String typeSig = null;
if (local.type == null || local.type.isTypeNameVar(binding.declaringScope)) {
if (local.initialization instanceof CastExpression) {
typeSig = Util.typeSignature(((CastExpression) local.initialization).type);
} else {
typeSig = Signature.createTypeSignature(binding.type.signableName(), true);
}
} else {
typeSig = Util.typeSignature(local.type);
}
localVar = new LocalVariable(
(JavaElement)parent,
new String(local.name),
local.declarationSourceStart,
local.declarationSourceEnd,
local.sourceStart,
local.sourceEnd,
typeSig,
local.annotations,
local.modifiers,
local.getKind() == AbstractVariableDeclaration.PARAMETER);
}
if (localVar != null) {
addElement(localVar);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept local variable("); //$NON-NLS-1$
System.out.print(localVar.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
/**
* Resolve the method
*/
@Override
public void acceptMethod(
char[] declaringTypePackageName,
char[] declaringTypeName,
String enclosingDeclaringTypeSignature,
char[] selector,
char[][] parameterPackageNames,
char[][] parameterTypeNames,
String[] parameterSignatures,
char[][] typeParameterNames,
char[][][] typeParameterBoundNames,
boolean isConstructor,
boolean isDeclaration,
char[] uniqueKey,
int start,
int end) {
IJavaElement[] previousElement = this.elements;
int previousElementIndex = this.elementIndex;
this.elements = JavaElement.NO_ELEMENTS;
this.elementIndex = -1;
if(isDeclaration) {
IType type = resolveTypeByLocation(declaringTypePackageName, declaringTypeName,
NameLookup.ACCEPT_ALL,
start, end);
if(type != null) {
acceptMethodDeclaration(type, selector, start, end);
}
} else {
IType type = resolveType(declaringTypePackageName, declaringTypeName,
NameLookup.ACCEPT_ALL);
// fix for 1FWFT6Q
if (type != null) {
if (type.isBinary()) {
// need to add a paramater for constructor in binary type
IType declaringDeclaringType = type.getDeclaringType();
boolean isStatic = false;
try {
isStatic = Flags.isStatic(type.getFlags());
} catch (JavaModelException e) {
// isStatic == false
}
if(declaringDeclaringType != null && isConstructor && !isStatic) {
int length = parameterPackageNames.length;
System.arraycopy(parameterPackageNames, 0, parameterPackageNames = new char[length+1][], 1, length);
System.arraycopy(parameterTypeNames, 0, parameterTypeNames = new char[length+1][], 1, length);
System.arraycopy(parameterSignatures, 0, parameterSignatures = new String[length+1], 1, length);
parameterPackageNames[0] = declaringDeclaringType.getPackageFragment().getElementName().toCharArray();
parameterTypeNames[0] = declaringDeclaringType.getTypeQualifiedName().toCharArray();
parameterSignatures[0] = Signature.getTypeErasure(enclosingDeclaringTypeSignature);
}
acceptBinaryMethod(type, selector, parameterPackageNames, parameterTypeNames, parameterSignatures, typeParameterNames, typeParameterBoundNames, uniqueKey, isConstructor);
} else {
acceptSourceMethod(type, selector, parameterPackageNames, parameterTypeNames, parameterSignatures, typeParameterNames, typeParameterBoundNames, uniqueKey);
}
}
}
if(previousElementIndex > -1) {
int elementsLength = this.elementIndex + previousElementIndex + 2;
if(elementsLength > this.elements.length) {
System.arraycopy(this.elements, 0, this.elements = new IJavaElement[elementsLength * 2 + 1], 0, this.elementIndex + 1);
}
System.arraycopy(previousElement, 0, this.elements, this.elementIndex + 1, previousElementIndex + 1);
this.elementIndex += previousElementIndex + 1;
}
}
/**
* Resolve the package
*/
@Override
public void acceptPackage(char[] packageName) {
IPackageFragment[] pkgs = this.nameLookup.findPackageFragments(new String(packageName), false);
if (pkgs != null) {
for (int i = 0, length = pkgs.length; i < length; i++) {
addElement(pkgs[i]);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept package("); //$NON-NLS-1$
System.out.print(pkgs[i].toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
/**
* Resolve the source method
*
* fix for 1FWFT6Q
*/
protected void acceptSourceMethod(
IType type,
char[] selector,
char[][] parameterPackageNames,
char[][] parameterTypeNames,
String[] parameterSignatures,
char[][] typeParameterNames,
char[][][] typeParameterBoundNames,
char[] uniqueKey) {
String name = new String(selector);
IMethod[] methods = null;
try {
methods = type.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getElementName().equals(name)
&& methods[i].getParameterTypes().length == parameterTypeNames.length) {
IMethod method = methods[i];
if (uniqueKey != null) {
ResolvedSourceMethod resolvedMethod = new ResolvedSourceMethod(
(JavaElement)method.getParent(),
method.getElementName(),
method.getParameterTypes(),
new String(uniqueKey));
resolvedMethod.occurrenceCount = method.getOccurrenceCount();
method = resolvedMethod;
}
addElement(method);
}
}
//{ObjectTeams: possibly retrieve a short-hand callout as declaration
if ( this.elementIndex == -1 // nothing found so far
&& OTModelManager.hasOTElementFor(type)) // check for role with short-hand callout
{
IOTType otType = OTModelManager.getOTElement(type);
if (otType.isRole()) {
for (IMethodMapping mapping : ((IRoleType)otType).getMethodMappings(IRoleType.CALLOUTS))
{
IMethodSpec roleMethodHandle = mapping.getRoleMethodHandle();
if ( mapping.hasSignature() // could be short-hand callout?
&& roleMethodHandle.getSelector().equals(name)
&& roleMethodHandle.getArgumentTypes().length == parameterTypeNames.length)
{
IJavaElement element = mapping;
if (uniqueKey != null)
element = ((MethodMapping)mapping).resolved(uniqueKey);
addElement(element);
}
}
}
}
// SH}
} catch (JavaModelException e) {
return;
}
// if no matches, nothing to report
if (this.elementIndex == -1) {
// no match was actually found, but a method was originally given -> default constructor
addElement(type);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(type.toString());
System.out.println(")"); //$NON-NLS-1$
}
return;
}
// if there is only one match, we've got it
if (this.elementIndex == 0) {
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept method("); //$NON-NLS-1$
System.out.print(this.elements[0].toString());
System.out.println(")"); //$NON-NLS-1$
}
return;
}
// more than one match - must match simple parameter types
IJavaElement[] matches = this.elements;
int matchesIndex = this.elementIndex;
this.elements = JavaElement.NO_ELEMENTS;
this.elementIndex = -1;
for (int i = 0; i <= matchesIndex; i++) {
//{ObjectTeams: consider method mappings (callout declaring a role method):
/* orig:
IMethod method= (IMethod)matches[i];
:giro */
IMethod method= null;
try {
method = (IMethod)matches[i];
} catch (ClassCastException cce) {
method = (IMethod)((IOTJavaElement)matches[i]).getCorrespondingJavaElement();
}
// orig:
String[] signatures = method.getParameterTypes();
boolean match= true;
for (int p = 0; p < signatures.length; p++) {
String simpleName= Signature.getSimpleName(Signature.toString(Signature.getTypeErasure(signatures[p])));
char[] simpleParameterName = CharOperation.lastSegment(parameterTypeNames[p], '.');
if (!simpleName.equals(new String(simpleParameterName))) {
match = false;
break;
}
}
if (match && !areTypeParametersCompatible(method, typeParameterNames, typeParameterBoundNames)) {
match = false;
}
if (match) {
/* SH: don't add correspondingJavaElement but original:
addElement(method);
:giro */
addElement(matches[i]);
// SH}
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept method("); //$NON-NLS-1$
System.out.print(method.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
protected void acceptMethodDeclaration(IType type, char[] selector, int start, int end) {
String name = new String(selector);
IMethod[] methods = null;
try {
methods = type.getMethods();
for (int i = 0; i < methods.length; i++) {
ISourceRange range = methods[i].getNameRange();
if(range.getOffset() <= start
&& range.getOffset() + range.getLength() >= end
&& methods[i].getElementName().equals(name)) {
addElement(methods[i]);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept method("); //$NON-NLS-1$
System.out.print(this.elements[0].toString());
System.out.println(")"); //$NON-NLS-1$
}
return; // only one method is possible
}
}
} catch (JavaModelException e) {
return;
}
// {ObjectTeams: method could be declared as a short-hand callout:
IOTType otType = OTModelManager.getOTElement(type);
if (otType != null) {
if (otType.isRole()) {
IRoleType role = (IRoleType)otType;
IMethodMapping[] mappings = role.getMethodMappings(IOTJavaElement.CALLOUT_MAPPING);
for (IMethodMapping mapping : mappings) {
IMethodSpec mData = mapping.getRoleMethodHandle();
if ( mData != null
&& CharOperation.equals(mData.getSelector().toCharArray(), selector)
&& mData.hasSignature())
{
addElement(mapping);
return;
}
}
}
}
// SH}
// no match was actually found
addElement(type);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(type.toString());
System.out.println(")"); //$NON-NLS-1$
}
return;
}
@Override
public void acceptTypeParameter(char[] declaringTypePackageName, char[] declaringTypeName, char[] typeParameterName, boolean isDeclaration, int start, int end) {
IType type;
if(isDeclaration) {
type = resolveTypeByLocation(declaringTypePackageName, declaringTypeName,
NameLookup.ACCEPT_ALL,
start, end);
} else {
type = resolveType(declaringTypePackageName, declaringTypeName,
NameLookup.ACCEPT_ALL);
}
if(type != null) {
ITypeParameter typeParameter = type.getTypeParameter(new String(typeParameterName));
if(typeParameter == null) {
addElement(type);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(type.toString());
System.out.println(")"); //$NON-NLS-1$
}
} else {
addElement(typeParameter);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type parameter("); //$NON-NLS-1$
System.out.print(typeParameter.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
@Override
public void acceptMethodTypeParameter(char[] declaringTypePackageName, char[] declaringTypeName, char[] selector,int selectorStart, int selectorEnd, char[] typeParameterName, boolean isDeclaration, int start, int end) {
IType type = resolveTypeByLocation(declaringTypePackageName, declaringTypeName,
NameLookup.ACCEPT_ALL,
selectorStart, selectorEnd);
if(type != null) {
IMethod method = null;
String name = new String(selector);
IMethod[] methods = null;
try {
methods = type.getMethods();
done : for (int i = 0; i < methods.length; i++) {
ISourceRange range = methods[i].getNameRange();
if(range.getOffset() >= selectorStart
&& range.getOffset() + range.getLength() <= selectorEnd
&& methods[i].getElementName().equals(name)) {
method = methods[i];
break done;
}
}
} catch (JavaModelException e) {
//nothing to do
}
if(method == null) {
addElement(type);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept type("); //$NON-NLS-1$
System.out.print(type.toString());
System.out.println(")"); //$NON-NLS-1$
}
} else {
ITypeParameter typeParameter = method.getTypeParameter(new String(typeParameterName));
if(typeParameter == null) {
addElement(method);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept method("); //$NON-NLS-1$
System.out.print(method.toString());
System.out.println(")"); //$NON-NLS-1$
}
} else {
addElement(typeParameter);
if(SelectionEngine.DEBUG){
System.out.print("SELECTION - accept method type parameter("); //$NON-NLS-1$
System.out.print(typeParameter.toString());
System.out.println(")"); //$NON-NLS-1$
}
}
}
}
}
/*
* Adds the given element to the list of resolved elements.
*/
protected void addElement(IJavaElement element) {
int elementLength = this.elementIndex + 1;
for (int i = 0; i < elementLength; i++) {
if (this.elements[i].equals(element)) {
return;
}
}
if (elementLength == this.elements.length) {
System.arraycopy(this.elements, 0, this.elements = new IJavaElement[(elementLength*2) + 1], 0, elementLength);
}
this.elements[++this.elementIndex] = element;
}
private boolean areTypeParametersCompatible(IMethod method, char[][] typeParameterNames, char[][][] typeParameterBoundNames) {
try {
ITypeParameter[] typeParameters = method.getTypeParameters();
int length1 = typeParameters == null ? 0 : typeParameters.length;
int length2 = typeParameterNames == null ? 0 : typeParameterNames.length;
if (length1 != length2) {
return false;
} else {
for (int j = 0; j < length1; j++) {
ITypeParameter typeParameter = typeParameters[j];
String typeParameterName = typeParameter.getElementName();
if (!typeParameterName.equals(new String(typeParameterNames[j]))) {
return false;
}
String[] bounds = typeParameter.getBounds();
int boundCount = typeParameterBoundNames[j] == null ? 0 : typeParameterBoundNames[j].length;
if (bounds.length != boundCount) {
return false;
} else {
for (int k = 0; k < boundCount; k++) {
String simpleName = Signature.getSimpleName(bounds[k]);
int index = simpleName.indexOf('<');
if (index != -1) {
simpleName = simpleName.substring(0, index);
}
if (!simpleName.equals(new String(typeParameterBoundNames[j][k]))) {
return false;
}
}
}
}
}
} catch (JavaModelException e) {
return false;
}
return true;
}
/*
* findLocalElement() cannot find local variable
*/
protected IJavaElement findLocalElement(int pos) {
IJavaElement res = null;
if(this.openable instanceof ICompilationUnit) {
ICompilationUnit cu = (ICompilationUnit) this.openable;
try {
res = cu.getElementAt(pos);
} catch (JavaModelException e) {
// do nothing
}
} else if (this.openable instanceof ClassFile) {
ClassFile cf = (ClassFile) this.openable;
try {
res = cf.getElementAtConsideringSibling(pos);
} catch (JavaModelException e) {
// do nothing
}
}
return res;
}
/*
* findLocalElement() cannot find lambdas.
*/
protected IJavaElement findLocalElement(int pos, MethodScope scope) {
if (scope != null && scope.isLambdaScope()) {
IJavaElement parent = findLocalElement(pos, scope.enclosingMethodScope());
LambdaExpression expression = (LambdaExpression) scope.originalReferenceContext();
if (expression != null && expression.resolvedType != null && expression.resolvedType.isValidBinding()) {
org.eclipse.jdt.internal.core.LambdaExpression lambdaElement = LambdaFactory.createLambdaExpression((JavaElement) parent, expression);
return lambdaElement.getMethod();
}
return parent;
}
return findLocalElement(pos);
}
/**
* This method returns an IMethod element from the given method and declaring type bindings. However,
* unlike {@link Util#findMethod(IType, char[], String[], boolean)} , this does not require an IType to get
* the IMethod element.
* @param method the given method binding
* @param signatures the type signatures of the method arguments
* @param declaringClass the binding of the method's declaring class
* @return an IMethod corresponding to the method binding given, or null if none is found.
*/
public IJavaElement findMethodFromBinding(MethodBinding method, String[] signatures, ReferenceBinding declaringClass) {
IType foundType = this.resolveType(declaringClass.qualifiedPackageName(), declaringClass.qualifiedSourceName(), NameLookup.ACCEPT_CLASSES & NameLookup.ACCEPT_INTERFACES);
if (foundType != null) {
if (foundType instanceof BinaryType) {
try {
return Util.findMethod(foundType, method.selector, signatures, method.isConstructor());
} catch (JavaModelException e) {
return null;
}
} else {
return foundType.getMethod(new String(method.selector), signatures);
}
}
return null;
}
/**
* Returns the resolved elements.
*/
public IJavaElement[] getElements() {
int elementLength = this.elementIndex + 1;
if (this.elements.length != elementLength) {
System.arraycopy(this.elements, 0, this.elements = new IJavaElement[elementLength], 0, elementLength);
}
return this.elements;
}
protected IModuleDescription resolveModule(char[] moduleName) {
Answer answer = this.nameLookup.findModule(moduleName);
if (answer != null) {
return answer.module;
}
return null;
}
/**
* Resolve the type
*/
protected IType resolveType(char[] packageName, char[] typeName, int acceptFlags) {
IType type= null;
if (this.openable instanceof CompilationUnit && ((CompilationUnit)this.openable).isWorkingCopy()) {
CompilationUnit wc = (CompilationUnit) this.openable;
try {
if(((packageName == null || packageName.length == 0) && wc.getPackageDeclarations().length == 0) ||
(!(packageName == null || packageName.length == 0) && wc.getPackageDeclaration(new String(packageName)).exists())) {
char[][] compoundName = CharOperation.splitOn('.', typeName);
if(compoundName.length > 0) {
type = wc.getType(new String(compoundName[0]));
for (int i = 1, length = compoundName.length; i < length; i++) {
type = type.getType(new String(compoundName[i]));
}
}
if(type != null && !type.exists()) {
type = null;
}
}
}catch (JavaModelException e) {
// type is null
}
}
if(type == null) {
IPackageFragment[] pkgs = this.nameLookup.findPackageFragments(
(packageName == null || packageName.length == 0) ? IPackageFragment.DEFAULT_PACKAGE_NAME : new String(packageName),
false);
// iterate type lookup in each package fragment
for (int i = 0, length = pkgs == null ? 0 : pkgs.length; i < length; i++) {
type= this.nameLookup.findType(new String(typeName), pkgs[i], false, acceptFlags, false, true/*consider secondary types*/);
if (type != null) break;
}
if (type == null) {
String pName= IPackageFragment.DEFAULT_PACKAGE_NAME;
if (packageName != null) {
pName = new String(packageName);
}
if (this.openable != null && this.openable.getParent().getElementName().equals(pName)) {
// look inside the type in which we are resolving in
String tName= new String(typeName);
tName = tName.replace('.','$');
IType[] allTypes= null;
try {
ArrayList list = this.openable.getChildrenOfType(IJavaElement.TYPE);
allTypes = new IType[list.size()];
list.toArray(allTypes);
} catch (JavaModelException e) {
return null;
}
for (int i= 0; i < allTypes.length; i++) {
if (allTypes[i].getTypeQualifiedName().equals(tName)) {
return allTypes[i];
}
}
}
}
}
//{ObjectTeams: Plan B for Role Files: re-interpretation of packageName.typeName
if ( (type == null || !type.exists()) // nothing found
&& this.openable instanceof CompilationUnit && ((CompilationUnit)this.openable).isWorkingCopy())
{
CompilationUnit wc = (CompilationUnit) this.openable;
char[] wcPack = CharOperation.concatWith(wc.getPackageName(), '.');
if ( packageName.length < wcPack.length
&& CharOperation.prefixEquals(packageName, wcPack))
{
// packageName is only a prefix of wcPack -> wcPack includes a team name!
char[] packSuffix = CharOperation.subarray(wcPack, packageName.length+1, -1);
if ( packSuffix.length < typeName.length
&& CharOperation.prefixEquals(packSuffix, typeName))
{
// typeName starts with the team name!
// change from "p1.p2" , "T1.T2.R" --to-> "p1.p2.T1.T2" , "R"
typeName = CharOperation.subarray(typeName, packSuffix.length+1, -1);
packageName = wcPack;
return resolveType(packageName, typeName, acceptFlags);
}
}
}
//SH}
return type;
}
protected IType resolveTypeByLocation(char[] packageName, char[] typeName, int acceptFlags, int start, int end) {
IType type= null;
// TODO (david) post 3.0 should remove isOpen check, and investigate reusing ICompilationUnit#getElementAt. may need to optimize #getElementAt to remove recursions
if (this.openable instanceof CompilationUnit && ((CompilationUnit)this.openable).isOpen()) {
CompilationUnit wc = (CompilationUnit) this.openable;
try {
if(((packageName == null || packageName.length == 0) && wc.getPackageDeclarations().length == 0) ||
(!(packageName == null || packageName.length == 0) && wc.getPackageDeclaration(new String(packageName)).exists())) {
char[][] compoundName = CharOperation.splitOn('.', typeName);
if(compoundName.length > 0) {
IType[] tTypes = wc.getTypes();
int i = 0;
int depth = 0;
done : while(i < tTypes.length) {
ISourceRange range = tTypes[i].getSourceRange();
if(range.getOffset() <= start
&& range.getOffset() + range.getLength() >= end
&& tTypes[i].getElementName().equals(new String(compoundName[depth]))) {
if(depth == compoundName.length - 1) {
type = tTypes[i];
break done;
}
tTypes = tTypes[i].getTypes();
i = 0;
depth++;
continue done;
}
i++;
}
}
if(type != null && !type.exists()) {
type = null;
}
}
}catch (JavaModelException e) {
// type is null
}
}
if(type == null) {
IPackageFragment[] pkgs = this.nameLookup.findPackageFragments(
(packageName == null || packageName.length == 0) ? IPackageFragment.DEFAULT_PACKAGE_NAME : new String(packageName),
false);
// iterate type lookup in each package fragment
for (int i = 0, length = pkgs == null ? 0 : pkgs.length; i < length; i++) {
type= this.nameLookup.findType(new String(typeName), pkgs[i], false, acceptFlags, false, true/*consider secondary types*/);
if (type != null) break;
}
if (type == null) {
String pName= IPackageFragment.DEFAULT_PACKAGE_NAME;
if (packageName != null) {
pName = new String(packageName);
}
if (this.openable != null && this.openable.getParent().getElementName().equals(pName)) {
// look inside the type in which we are resolving in
String tName= new String(typeName);
tName = tName.replace('.','$');
IType[] allTypes= null;
try {
ArrayList list = this.openable.getChildrenOfType(IJavaElement.TYPE);
allTypes = new IType[list.size()];
list.toArray(allTypes);
} catch (JavaModelException e) {
return null;
}
for (int i= 0; i < allTypes.length; i++) {
if (allTypes[i].getTypeQualifiedName().equals(tName)) {
return allTypes[i];
}
}
}
}
}
return type;
}
}