use of spoon.reflect.reference.CtTypeReference in project spoon by INRIA.
the class ImportScannerImpl method isTypeInCollision.
/**
* Test if the reference can be imported, i.e. test if the importation could lead to a collision.
* @param ref
* @return true if the ref should be imported.
*/
protected boolean isTypeInCollision(CtReference ref, boolean fqnMode) {
if (targetType != null && targetType.getSimpleName().equals(ref.getSimpleName()) && !targetType.equals(ref)) {
return true;
}
try {
CtElement parent;
if (ref instanceof CtTypeReference) {
parent = ref.getParent();
} else {
parent = ref;
}
// i.e. a string, an int, etc.
if (parent instanceof CtLiteral) {
return false;
}
Set<String> localVariablesOfBlock = new HashSet<>();
if (parent instanceof CtField) {
this.fieldAndMethodsNames.add(((CtField) parent).getSimpleName());
} else if (parent instanceof CtMethod) {
this.fieldAndMethodsNames.add(((CtMethod) parent).getSimpleName());
} else {
localVariablesOfBlock = this.lookForLocalVariables(parent);
}
while (!(parent instanceof CtPackage)) {
if ((parent instanceof CtFieldReference) || (parent instanceof CtExecutableReference) || (parent instanceof CtInvocation)) {
CtReference parentType;
if (parent instanceof CtInvocation) {
parentType = ((CtInvocation) parent).getExecutable();
} else {
parentType = (CtReference) parent;
}
LinkedList<String> qualifiedNameTokens = new LinkedList<>();
// we don't want to test the current ref name, as we risk to create field import and make autoreference
if (parentType != parent) {
qualifiedNameTokens.add(parentType.getSimpleName());
}
CtTypeReference typeReference;
if (parent instanceof CtFieldReference) {
typeReference = ((CtFieldReference) parent).getDeclaringType();
} else if (parent instanceof CtExecutableReference) {
typeReference = ((CtExecutableReference) parent).getDeclaringType();
} else {
typeReference = ((CtInvocation) parent).getExecutable().getDeclaringType();
}
if (typeReference != null) {
qualifiedNameTokens.addFirst(typeReference.getSimpleName());
if (typeReference.getPackage() != null) {
StringTokenizer token = new StringTokenizer(typeReference.getPackage().getSimpleName(), CtPackage.PACKAGE_SEPARATOR);
int index = 0;
while (token.hasMoreElements()) {
qualifiedNameTokens.add(index, token.nextToken());
index++;
}
}
}
if (!qualifiedNameTokens.isEmpty()) {
// if the first package name is a variable name somewhere, it could lead to a collision
if (fieldAndMethodsNames.contains(qualifiedNameTokens.getFirst()) || localVariablesOfBlock.contains(qualifiedNameTokens.getFirst())) {
qualifiedNameTokens.removeFirst();
if (fqnMode) {
// for example: spoon.Launcher if a field spoon and another one Launcher exists
if (ref instanceof CtTypeReference) {
if (qualifiedNameTokens.isEmpty()) {
return true;
}
// but if the other package names are not a variable name, it's ok to import
for (int i = 0; i < qualifiedNameTokens.size(); i++) {
String testedToken = qualifiedNameTokens.get(i);
if (!fieldAndMethodsNames.contains(testedToken) && !localVariablesOfBlock.contains(testedToken)) {
return true;
}
}
return false;
// However if it is a static method/field, we always accept to import them in this case
// It is the last possibility for managing import for us
} else {
return true;
}
} else {
// but if the other package names are not a variable name, it's ok to import
for (int i = 0; i < qualifiedNameTokens.size(); i++) {
String testedToken = qualifiedNameTokens.get(i);
if (!fieldAndMethodsNames.contains(testedToken) && !localVariablesOfBlock.contains(testedToken)) {
return false;
}
}
return true;
}
}
}
}
parent = parent.getParent();
}
} catch (ParentNotInitializedException e) {
return false;
}
return false;
}
use of spoon.reflect.reference.CtTypeReference in project spoon by INRIA.
the class ImportScannerImpl method addClassImport.
/**
* Adds a type to the classImports.
*/
protected boolean addClassImport(CtTypeReference<?> ref) {
this.exploredReferences.add(ref);
if (ref == null) {
return false;
}
if (targetType != null && targetType.getSimpleName().equals(ref.getSimpleName()) && !targetType.equals(ref)) {
return false;
}
if (classImports.containsKey(ref.getSimpleName())) {
return isImportedInClassImports(ref);
}
// don't import unnamed package elements
if (ref.getPackage() == null || ref.getPackage().isUnnamedPackage()) {
return false;
}
if (targetType != null && targetType.canAccess(ref) == false) {
// ref type is not visible in targetType we must not add import for it, java compiler would fail on that.
return false;
}
if (this.isThereAnotherClassWithSameNameInAnotherPackage(ref)) {
return false;
}
if (targetType != null) {
try {
CtElement parent = ref.getParent();
if (parent != null) {
parent = parent.getParent();
if (parent != null) {
if ((parent instanceof CtFieldAccess) || (parent instanceof CtExecutable) || (parent instanceof CtInvocation)) {
CtTypeReference declaringType;
CtReference reference;
CtPackageReference pack = targetType.getPackage();
if (parent instanceof CtFieldAccess) {
CtFieldAccess field = (CtFieldAccess) parent;
CtFieldReference localReference = field.getVariable();
declaringType = localReference.getDeclaringType();
reference = localReference;
} else if (parent instanceof CtExecutable) {
CtExecutable exec = (CtExecutable) parent;
CtExecutableReference localReference = exec.getReference();
declaringType = localReference.getDeclaringType();
reference = localReference;
} else if (parent instanceof CtInvocation) {
CtInvocation invo = (CtInvocation) parent;
CtExecutableReference localReference = invo.getExecutable();
declaringType = localReference.getDeclaringType();
reference = localReference;
} else {
declaringType = null;
reference = null;
}
if (reference != null && isImported(reference)) {
// if we are in the **same** package we do the import for test with method isImported
if (declaringType != null) {
if (declaringType.getPackage() != null && !declaringType.getPackage().isUnnamedPackage()) {
// ignore java.lang package
if (!declaringType.getPackage().getSimpleName().equals("java.lang")) {
// ignore type in same package
if (declaringType.getPackage().getSimpleName().equals(pack.getSimpleName())) {
classImports.put(ref.getSimpleName(), ref);
return true;
}
}
}
}
}
}
}
}
} catch (ParentNotInitializedException e) {
}
CtPackageReference pack = targetType.getPackage();
if (pack != null && ref.getPackage() != null && !ref.getPackage().isUnnamedPackage()) {
// ignore java.lang package
if (!ref.getPackage().getSimpleName().equals("java.lang")) {
// ignore type in same package
if (ref.getPackage().getSimpleName().equals(pack.getSimpleName())) {
return false;
}
}
}
}
classImports.put(ref.getSimpleName(), ref);
return true;
}
use of spoon.reflect.reference.CtTypeReference in project spoon by INRIA.
the class SubInheritanceHierarchyFunction method apply.
@Override
public void apply(CtTypeInformation input, final CtConsumer<Object> outputConsumer) {
final SubInheritanceHierarchyResolver fnc = new SubInheritanceHierarchyResolver(((CtElement) input).getFactory().getModel().getRootPackage()).failOnClassNotFound(failOnClassNotFound).includingInterfaces(includingInterfaces);
if (includingSelf) {
if (input instanceof CtTypeReference) {
outputConsumer.accept(((CtTypeReference<?>) input).getTypeDeclaration());
} else {
outputConsumer.accept(((CtType<?>) input));
}
}
fnc.addSuperType(input);
fnc.forEachSubTypeInPackage(new CtConsumer<CtType>() {
@Override
public void accept(CtType typeInfo) {
outputConsumer.accept(typeInfo);
if (query.isTerminated()) {
// Cannot terminate, because it's support was removed.
// I think there are cases where it might be useful.
// fnc.terminate();
}
}
});
}
use of spoon.reflect.reference.CtTypeReference in project spoon by INRIA.
the class SubInheritanceHierarchyResolver method forEachSubTypeInPackage.
/**
* Calls `outputConsumer.apply(subType)` for each sub type of the targetSuperTypes that are found in `inputPackage`.
* Each sub type is returned only once.
* It makes sense to call this method again for example after new super types are added
* by {@link #addSuperType(CtTypeInformation)}.
*
* If this method is called again with same input and configuration, nothing in sent to outputConsumer
* @param outputConsumer the consumer for found sub types
*/
public <T extends CtType<?>> void forEachSubTypeInPackage(final CtConsumer<T> outputConsumer) {
/*
* Set of qualified names of all visited types, independent on whether they are sub types or not.
*/
final Set<String> allVisitedTypeNames = new HashSet<>();
/*
* the queue of types whose super inheritance hierarchy we are just visiting.
* They are potential sub types of an `targetSuperTypes`
*/
final Deque<CtTypeReference<?>> currentSubTypes = new ArrayDeque<>();
// algorithm
// 1) query step: scan input package for sub classes and sub interfaces
final CtQuery q = inputPackage.map(new CtScannerFunction());
// 2) query step: visit only required CtTypes
if (includingInterfaces) {
// the client is interested in sub inheritance hierarchy of interfaces too. Check interfaces, classes, enums, Annotations, but not CtTypeParameters.
q.select(typeFilter);
} else {
// the client is not interested in sub inheritance hierarchy of interfaces. Check only classes and enums.
q.select(classFilter);
}
/*
* 3) query step: for each found CtType, visit it's super inheritance hierarchy and search there for a type which is equal to one of targetSuperTypes.
* If found then all sub types in hierarchy (variable `currentSubTypes`) are sub types of targetSuperTypes. So return them
*/
q.map(new SuperInheritanceHierarchyFunction().includingInterfaces(hasSuperInterface).failOnClassNotFound(failOnClassNotFound).setListener(new CtScannerListener() {
@Override
public ScanningMode enter(CtElement element) {
final CtTypeReference<?> typeRef = (CtTypeReference<?>) element;
String qName = typeRef.getQualifiedName();
if (targetSuperTypes.contains(qName)) {
/*
* FOUND! we are in super inheritance hierarchy, which extends from an searched super type(s).
* All `currentSubTypes` are sub types of searched super type
*/
while (currentSubTypes.size() > 0) {
final CtTypeReference<?> currentTypeRef = currentSubTypes.pop();
String currentQName = currentTypeRef.getQualifiedName();
/*
* Send them to outputConsumer and add then as targetSuperTypes too, to perform faster with detection of next sub types.
*/
if (!targetSuperTypes.contains(currentQName)) {
targetSuperTypes.add(currentQName);
outputConsumer.accept((T) currentTypeRef.getTypeDeclaration());
}
}
// but continue visiting of siblings (do not terminate query)
return SKIP_ALL;
}
if (allVisitedTypeNames.add(qName) == false) {
/*
* this type was already visited, by another way. So it is not sub type of `targetSuperTypes`.
* Stop visiting it's inheritance hierarchy.
*/
return SKIP_ALL;
}
/*
* This type was not visited yet.
* We still do not know whether this type is a sub type of any target super type(s)
* continue searching in super inheritance hierarchy
*/
currentSubTypes.push(typeRef);
return NORMAL;
}
@Override
public void exit(CtElement element) {
CtTypeInformation type = (CtTypeInformation) element;
if (currentSubTypes.isEmpty() == false) {
// remove current type, which is not a sub type of targetSuperTypes from the currentSubTypes
CtTypeInformation stackType = currentSubTypes.pop();
if (stackType != type) {
// the enter/exit was not called consistently. There is a bug in SuperInheritanceHierarchyFunction
throw new SpoonException("CtScannerListener#exit was not called after enter.");
}
}
}
})).forEach(new CtConsumer<CtType<?>>() {
@Override
public void accept(CtType<?> type) {
// we do not care about types visited by query `q`.
// the result of whole mapping function was already produced by `sendResult` call
// but we have to consume all these results to let query running
}
});
}
use of spoon.reflect.reference.CtTypeReference in project spoon by INRIA.
the class CtProvidedServiceImpl method setImplementationTypes.
@Override
public <T extends CtProvidedService> T setImplementationTypes(List<CtTypeReference> usedTypes) {
getFactory().getEnvironment().getModelChangeListener().onListDeleteAll(this, CtRole.IMPLEMENTATION_TYPE, this.implementationTypes, new ArrayList<>(this.implementationTypes));
if (usedTypes == null || usedTypes.size() == 0) {
this.implementationTypes = CtElementImpl.emptyList();
return (T) this;
}
if (this.implementationTypes == CtElementImpl.<CtTypeReference>emptyList()) {
this.implementationTypes = new ArrayList<>();
}
this.implementationTypes.clear();
for (CtTypeReference usedType : usedTypes) {
this.addImplementationType(usedType);
}
return (T) this;
}
Aggregations