org.aspectj.org.eclipse.jdt.internal.codeassist.MissingTypesGuesser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/*******************************************************************************
* Copyright (c) 2006, 2013 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
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.codeassist;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.search.IJavaSearchConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.*;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.AccessRestriction;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
import org.aspectj.org.eclipse.jdt.internal.core.SearchableEnvironment;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class MissingTypesGuesser extends ASTVisitor {
public static interface GuessedTypeRequestor {
public void accept(
TypeBinding guessedType,
Binding[] missingElements,
int[] missingElementsStarts,
int[] missingElementsEnds,
boolean hasProblems);
}
private static class ResolutionCleaner extends ASTVisitor {
private HashtableOfObjectToInt bitsMap = new HashtableOfObjectToInt();
private boolean firstCall = true;
public ResolutionCleaner(){
super();
}
private void cleanUp(TypeReference typeReference) {
if (this.firstCall) {
this.bitsMap.put(typeReference, typeReference.bits);
} else {
typeReference.bits = this.bitsMap.get(typeReference);
}
typeReference.resolvedType = null;
}
private void cleanUp(ParameterizedSingleTypeReference typeReference) {
this.cleanUp((TypeReference)typeReference);
typeReference.bits &= ~ASTNode.DidResolve;
}
private void cleanUp(ParameterizedQualifiedTypeReference typeReference) {
this.cleanUp((TypeReference)typeReference);
typeReference.bits &= ~ASTNode.DidResolve;
}
public void cleanUp(TypeReference convertedType, BlockScope scope) {
convertedType.traverse(this, scope);
this.firstCall = false;
}
public void cleanUp(TypeReference convertedType, ClassScope scope) {
convertedType.traverse(this, scope);
this.firstCall = false;
}
public boolean visit(SingleTypeReference singleTypeReference, BlockScope scope) {
this.cleanUp(singleTypeReference);
return true;
}
public boolean visit(SingleTypeReference singleTypeReference, ClassScope scope) {
this.cleanUp(singleTypeReference);
return true;
}
public boolean visit(Wildcard wildcard, BlockScope scope) {
this.cleanUp(wildcard);
return true;
}
public boolean visit(Wildcard wildcard, ClassScope scope) {
this.cleanUp(wildcard);
return true;
}
public boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope) {
this.cleanUp(arrayTypeReference);
return true;
}
public boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope) {
this.cleanUp(arrayTypeReference);
return true;
}
public boolean visit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, BlockScope scope) {
this.cleanUp(parameterizedSingleTypeReference);
return true;
}
public boolean visit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, ClassScope scope) {
this.cleanUp(parameterizedSingleTypeReference);
return true;
}
public boolean visit(QualifiedTypeReference qualifiedTypeReference, BlockScope scope) {
this.cleanUp(qualifiedTypeReference);
return true;
}
public boolean visit(QualifiedTypeReference qualifiedTypeReference, ClassScope scope) {
this.cleanUp(qualifiedTypeReference);
return true;
}
public boolean visit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, BlockScope scope) {
this.cleanUp(arrayQualifiedTypeReference);
return true;
}
public boolean visit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, ClassScope scope) {
this.cleanUp(arrayQualifiedTypeReference);
return true;
}
public boolean visit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, BlockScope scope) {
this.cleanUp(parameterizedQualifiedTypeReference);
return true;
}
public boolean visit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, ClassScope scope) {
this.cleanUp(parameterizedQualifiedTypeReference);
return true;
}
}
private CompletionEngine.CompletionProblemFactory problemFactory ;
private SearchableEnvironment nameEnvironment;
private HashMap substituedTypes;
private HashMap originalTypes;
private int combinationsCount;
public MissingTypesGuesser(CompletionEngine completionEngine) {
this.problemFactory = completionEngine.problemFactory;
this.nameEnvironment = completionEngine.nameEnvironment;
}
private boolean computeMissingElements(
QualifiedTypeReference[] substituedTypeNodes,
char[][][] originalTypeNames,
Binding[] missingElements,
int[] missingElementsStarts,
int[] missingElementsEnds) {
int length = substituedTypeNodes.length;
for (int i = 0; i < length; i++) {
TypeReference substituedType = substituedTypeNodes[i];
if (substituedType.resolvedType == null) return false;
ReferenceBinding erasure = (ReferenceBinding)substituedType.resolvedType.leafComponentType().erasure();
Binding missingElement;
int depthToRemove = originalTypeNames[i].length - 1 ;
if (depthToRemove == 0) {
missingElement = erasure;
} else {
int depth = erasure.depth() + 1;
if (depth > depthToRemove) {
missingElement = erasure.enclosingTypeAt(depthToRemove);
} else {
return false;
///////////////////////////////////////////////////////////
//// Uncomment the following code to return missing package
///////////////////////////////////////////////////////////
//depthToRemove -= depth;
//PackageBinding packageBinding = erasure.getPackage();
//while(depthToRemove > 0) {
// packageBinding = packageBinding.parent;
// depthToRemove--;
//}
//missingElement = packageBinding;
}
}
missingElements[i] = missingElement;
missingElementsStarts[i] = substituedType.sourceStart;
missingElementsEnds[i] = substituedType.sourceEnd + 1;
}
return true;
}
private TypeReference convert(ArrayQualifiedTypeReference typeRef) {
if (typeRef.resolvedType != null) {
if (typeRef.resolvedType.isValidBinding()) {
ArrayQualifiedTypeReference convertedType =
new ArrayQualifiedTypeReference(
typeRef.tokens,
typeRef.dimensions(),
typeRef.sourcePositions);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.sourceEnd;
return convertedType;
} else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
// only the first token must be resolved
if(((ReferenceBinding)typeRef.resolvedType.leafComponentType()).compoundName.length != 1) return null;
char[][] typeName = typeRef.getTypeName();
char[][][] typeNames = findTypeNames(typeName);
if(typeNames == null || typeNames.length == 0) return null;
ArrayQualifiedTypeReference convertedType =
new ArrayQualifiedTypeReference(
typeNames[0],
typeRef.dimensions(),
new long[typeNames[0].length]);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL);
this.substituedTypes.put(convertedType, typeNames);
this.originalTypes.put(convertedType, typeName);
this.combinationsCount *= typeNames.length;
return convertedType;
}
}
return null;
}
private TypeReference convert(ArrayTypeReference typeRef) {
if (typeRef.resolvedType != null) {
if (typeRef.resolvedType.isValidBinding()) {
ArrayTypeReference convertedType =
new ArrayTypeReference(
typeRef.token,
typeRef.dimensions,
0);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.originalSourceEnd;
return convertedType;
} else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
char[][] typeName = typeRef.getTypeName();
char[][][] typeNames = findTypeNames(typeName);
if(typeNames == null || typeNames.length == 0) return null;
ArrayQualifiedTypeReference convertedType =
new ArrayQualifiedTypeReference(
typeNames[0],
typeRef.dimensions,
new long[typeNames[0].length]);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.originalSourceEnd;
this.substituedTypes.put(convertedType, typeNames);
this.originalTypes.put(convertedType, typeName);
this.combinationsCount *= typeNames.length;
return convertedType;
}
}
return null;
}
private TypeReference convert(ParameterizedQualifiedTypeReference typeRef) {
if (typeRef.resolvedType != null) {
TypeReference[][] typeArguments = typeRef.typeArguments;
int length = typeArguments.length;
TypeReference[][] convertedTypeArguments = new TypeReference[length][];
next : for (int i = 0; i < length; i++) {
if (typeArguments[i] == null) continue next;
int length2 = typeArguments[i].length;
convertedTypeArguments[i] = new TypeReference[length2];
for (int j = 0; j < length2; j++) {
convertedTypeArguments[i][j] = convert(typeArguments[i][j]);
if (convertedTypeArguments[i][j] == null) return null;
}
}
if (typeRef.resolvedType.isValidBinding()) {
ParameterizedQualifiedTypeReference convertedType =
new ParameterizedQualifiedTypeReference(
typeRef.tokens,
convertedTypeArguments,
typeRef.dimensions(),
new long[typeRef.tokens.length]);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.sourceEnd;
return convertedType;
} else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
// only the first token must be resolved
if(((ReferenceBinding)typeRef.resolvedType.leafComponentType()).compoundName.length != 1) return null;
char[][] typeName = typeRef.getTypeName();
char[][][] typeNames = findTypeNames(typeName);
if(typeNames == null || typeNames.length == 0) return null;
TypeReference[][] newConvertedTypeArguments = new TypeReference[typeNames[0].length][];
for (int k = newConvertedTypeArguments.length - 1, l = convertedTypeArguments.length -1; k > -1 && l > -1;) {
newConvertedTypeArguments[k] = convertedTypeArguments[l];
k--;
l--;
}
ParameterizedQualifiedTypeReference convertedType =
new ParameterizedQualifiedTypeReference(
typeNames[0],
newConvertedTypeArguments,
typeRef.dimensions(),
new long[typeNames[0].length]);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL);
this.substituedTypes.put(convertedType, typeNames);
this.originalTypes.put(convertedType, typeName);
this.combinationsCount *= typeNames.length;
return convertedType;
}
}
return null;
}
private TypeReference convert(ParameterizedSingleTypeReference typeRef) {
if (typeRef.resolvedType != null) {
TypeReference[] typeArguments = typeRef.typeArguments;
int length = typeArguments.length;
TypeReference[] convertedTypeArguments = new TypeReference[length];
for (int i = 0; i < length; i++) {
convertedTypeArguments[i] = convert(typeArguments[i]);
if(convertedTypeArguments[i] == null) return null;
}
if (typeRef.resolvedType.isValidBinding()) {
ParameterizedSingleTypeReference convertedType =
new ParameterizedSingleTypeReference(
typeRef.token,
convertedTypeArguments,
typeRef.dimensions,
0);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.sourceEnd;
return convertedType;
} else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
char[][] typeName = typeRef.getTypeName();
char[][][] typeNames = findTypeNames(typeName);
if(typeNames == null || typeNames.length == 0) return null;
TypeReference[][] allConvertedTypeArguments = new TypeReference[typeNames[0].length][];
allConvertedTypeArguments[allConvertedTypeArguments.length - 1] = convertedTypeArguments;
ParameterizedQualifiedTypeReference convertedType =
new ParameterizedQualifiedTypeReference(
typeNames[0],
allConvertedTypeArguments,
typeRef.dimensions,
new long[typeNames[0].length]);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.sourceEnd;
this.substituedTypes.put(convertedType, typeNames);
this.originalTypes.put(convertedType, typeName);
this.combinationsCount *= typeNames.length;
return convertedType;
}
}
return null;
}
private TypeReference convert(QualifiedTypeReference typeRef) {
if (typeRef.resolvedType != null) {
if (typeRef.resolvedType.isValidBinding()) {
QualifiedTypeReference convertedType = new QualifiedTypeReference(typeRef.tokens, typeRef.sourcePositions);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.sourceEnd;
return convertedType;
} else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
// only the first token must be resolved
if(((ReferenceBinding)typeRef.resolvedType).compoundName.length != 1) return null;
char[][] typeName = typeRef.getTypeName();
char[][][] typeNames = findTypeNames(typeName);
if(typeNames == null || typeNames.length == 0) return null;
QualifiedTypeReference convertedType = new QualifiedTypeReference(typeNames[0], new long[typeNames[0].length]);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL);
this.substituedTypes.put(convertedType, typeNames);
this.originalTypes.put(convertedType, typeName);
this.combinationsCount *= typeNames.length;
return convertedType;
}
}
return null;
}
private TypeReference convert(SingleTypeReference typeRef) {
if (typeRef.resolvedType != null) {
if (typeRef.resolvedType.isValidBinding()) {
SingleTypeReference convertedType = new SingleTypeReference(typeRef.token, 0);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.sourceEnd;
return convertedType;
} else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) {
char[][] typeName = typeRef.getTypeName();
char[][][] typeNames = findTypeNames(typeName);
if(typeNames == null || typeNames.length == 0) return null;
QualifiedTypeReference convertedType = new QualifiedTypeReference(typeNames[0], new long[typeNames[0].length]);
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.sourceEnd;
this.substituedTypes.put(convertedType, typeNames);
this.originalTypes.put(convertedType, typeName);
this.combinationsCount *= typeNames.length;
return convertedType;
}
}
return null;
}
private TypeReference convert(TypeReference typeRef) {
if (typeRef instanceof ParameterizedSingleTypeReference) {
return convert((ParameterizedSingleTypeReference)typeRef);
} else if(typeRef instanceof ParameterizedQualifiedTypeReference) {
return convert((ParameterizedQualifiedTypeReference)typeRef);
} else if (typeRef instanceof ArrayTypeReference) {
return convert((ArrayTypeReference)typeRef);
} else if(typeRef instanceof ArrayQualifiedTypeReference) {
return convert((ArrayQualifiedTypeReference)typeRef);
} else if(typeRef instanceof Wildcard) {
return convert((Wildcard)typeRef);
} else if (typeRef instanceof SingleTypeReference) {
return convert((SingleTypeReference)typeRef);
} else if (typeRef instanceof QualifiedTypeReference) {
return convert((QualifiedTypeReference)typeRef);
}
return null;
}
private TypeReference convert(Wildcard typeRef) {
TypeReference bound = typeRef.bound;
TypeReference convertedBound = null;
if (bound != null) {
convertedBound = convert(bound);
if (convertedBound == null) return null;
}
Wildcard convertedType = new Wildcard(typeRef.kind);
convertedType.bound = convertedBound;
convertedType.sourceStart = typeRef.sourceStart;
convertedType.sourceEnd = typeRef.sourceEnd;
return convertedType;
}
private char[][][] findTypeNames(char[][] missingTypeName) {
char[] missingSimpleName = missingTypeName[missingTypeName.length - 1];
final boolean isQualified = missingTypeName.length > 1;
final char[] missingFullyQualifiedName =
isQualified ? CharOperation.concatWith(missingTypeName, '.') : null;
final ArrayList results = new ArrayList();
ISearchRequestor storage = new ISearchRequestor() {
public void acceptConstructor(
int modifiers,
char[] simpleTypeName,
int parameterCount,
char[] signature,
char[][] parameterTypes,
char[][] parameterNames,
int typeModifiers,
char[] packageName,
int extraFlags,
String path,
AccessRestriction access) {
// constructors aren't searched
}
public void acceptPackage(char[] packageName) {
// package aren't searched
}
public void acceptType(
char[] packageName,
char[] typeName,
char[][] enclosingTypeNames,
int modifiers,
AccessRestriction accessRestriction) {
char[] fullyQualifiedName = CharOperation.concat(packageName, CharOperation.concat(CharOperation.concatWith(enclosingTypeNames, '.'), typeName, '.'), '.');
if (isQualified && !CharOperation.endsWith(fullyQualifiedName, missingFullyQualifiedName)) return;
char[][] compoundName = CharOperation.splitOn('.', fullyQualifiedName);
results.add(compoundName);
}
};
this.nameEnvironment.findExactTypes(missingSimpleName, true, IJavaSearchConstants.TYPE, storage);
if(results.size() == 0) return null;
return (char[][][])results.toArray(new char[results.size()][0][0]);
}
private char[][] getOriginal(TypeReference typeRef) {
return (char[][])this.originalTypes.get(typeRef);
}
private QualifiedTypeReference[] getSubstituedTypes() {
Set types = this.substituedTypes.keySet();
return (QualifiedTypeReference[]) types.toArray(new QualifiedTypeReference[types.size()]);
}
private char[][][] getSubstitution(TypeReference typeRef) {
return (char[][][])this.substituedTypes.get(typeRef);
}
public void guess(TypeReference typeRef, Scope scope, GuessedTypeRequestor requestor) {
this.substituedTypes = new HashMap();
this.originalTypes = new HashMap();
this.combinationsCount = 1;
TypeReference convertedType = convert(typeRef);
if(convertedType == null) return;
QualifiedTypeReference[] substituedTypeNodes = getSubstituedTypes();
int length = substituedTypeNodes.length;
int[] substitutionsIndexes = new int[substituedTypeNodes.length];
char[][][][] subtitutions = new char[substituedTypeNodes.length][][][];
char[][][] originalTypeNames = new char[substituedTypeNodes.length][][];
for (int i = 0; i < substituedTypeNodes.length; i++) {
subtitutions[i] = getSubstitution(substituedTypeNodes[i]);
originalTypeNames[i] = getOriginal(substituedTypeNodes[i]);
}
ResolutionCleaner resolutionCleaner = new ResolutionCleaner();
for (int i = 0; i < this.combinationsCount; i++) {
nextSubstitution(substituedTypeNodes, subtitutions, substitutionsIndexes);
this.problemFactory.startCheckingProblems();
TypeBinding guessedType = null;
switch (scope.kind) {
case Scope.METHOD_SCOPE :
case Scope.BLOCK_SCOPE :
resolutionCleaner.cleanUp(convertedType, (BlockScope)scope);
guessedType = convertedType.resolveType((BlockScope)scope);
break;
case Scope.CLASS_SCOPE :
resolutionCleaner.cleanUp(convertedType, (ClassScope)scope);
guessedType = convertedType.resolveType((ClassScope)scope);
break;
}
this.problemFactory.stopCheckingProblems();
if (!this.problemFactory.hasForbiddenProblems) {
if (guessedType != null) {
Binding[] missingElements = new Binding[length];
int[] missingElementsStarts = new int[length];
int[] missingElementsEnds = new int[length];
if(computeMissingElements(
substituedTypeNodes,
originalTypeNames,
missingElements,
missingElementsStarts,
missingElementsEnds)) {
requestor.accept(
guessedType.capture(scope, typeRef.sourceEnd),
missingElements,
missingElementsStarts,
missingElementsEnds,
this.problemFactory.hasAllowedProblems);
}
}
}
}
}
private void nextSubstitution(
QualifiedTypeReference[] substituedTypeNodes,
char[][][][] subtitutions,
int[] substitutionsIndexes) {
int length = substituedTypeNodes.length;
done : for (int i = 0; i < length; i++) {
if(substitutionsIndexes[i] < subtitutions[i].length - 1) {
substitutionsIndexes[i]++;
break done;
} else {
substitutionsIndexes[i] = 0;
}
}
for (int i = 0; i < length; i++) {
QualifiedTypeReference qualifiedTypeReference = substituedTypeNodes[i];
qualifiedTypeReference.tokens = subtitutions[i][substitutionsIndexes[i]];
qualifiedTypeReference.sourcePositions = new long[qualifiedTypeReference.tokens.length];
if(qualifiedTypeReference instanceof ParameterizedQualifiedTypeReference) {
ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference =
(ParameterizedQualifiedTypeReference)qualifiedTypeReference;
TypeReference[][] typeArguments = parameterizedQualifiedTypeReference.typeArguments;
TypeReference[][] newTypeArguments = new TypeReference[qualifiedTypeReference.tokens.length][];
for (int j = newTypeArguments.length - 1, k = typeArguments.length -1; j > -1 && k > -1;) {
newTypeArguments[j] = typeArguments[k];
j--;
k--;
}
}
}
}
}