Search in sources :

Example 31 with CtTypeReference

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;
}
Also used : ParentNotInitializedException(spoon.reflect.declaration.ParentNotInitializedException) CtElement(spoon.reflect.declaration.CtElement) CtFieldReference(spoon.reflect.reference.CtFieldReference) LinkedList(java.util.LinkedList) CtInvocation(spoon.reflect.code.CtInvocation) StringTokenizer(java.util.StringTokenizer) CtLiteral(spoon.reflect.code.CtLiteral) CtReference(spoon.reflect.reference.CtReference) CtTypeReference(spoon.reflect.reference.CtTypeReference) CtField(spoon.reflect.declaration.CtField) CtExecutableReference(spoon.reflect.reference.CtExecutableReference) CtPackage(spoon.reflect.declaration.CtPackage) CtMethod(spoon.reflect.declaration.CtMethod) HashSet(java.util.HashSet)

Example 32 with CtTypeReference

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;
}
Also used : CtFieldAccess(spoon.reflect.code.CtFieldAccess) CtInvocation(spoon.reflect.code.CtInvocation) ParentNotInitializedException(spoon.reflect.declaration.ParentNotInitializedException) CtPackageReference(spoon.reflect.reference.CtPackageReference) CtReference(spoon.reflect.reference.CtReference) CtElement(spoon.reflect.declaration.CtElement) CtTypeReference(spoon.reflect.reference.CtTypeReference) CtFieldReference(spoon.reflect.reference.CtFieldReference) CtExecutableReference(spoon.reflect.reference.CtExecutableReference) CtExecutable(spoon.reflect.declaration.CtExecutable)

Example 33 with CtTypeReference

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();
            }
        }
    });
}
Also used : CtType(spoon.reflect.declaration.CtType) CtTypeReference(spoon.reflect.reference.CtTypeReference) SubInheritanceHierarchyResolver(spoon.support.visitor.SubInheritanceHierarchyResolver)

Example 34 with CtTypeReference

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
        }
    });
}
Also used : SuperInheritanceHierarchyFunction(spoon.reflect.visitor.filter.SuperInheritanceHierarchyFunction) SpoonException(spoon.SpoonException) CtElement(spoon.reflect.declaration.CtElement) CtQuery(spoon.reflect.visitor.chain.CtQuery) CtTypeInformation(spoon.reflect.declaration.CtTypeInformation) ArrayDeque(java.util.ArrayDeque) ScanningMode(spoon.reflect.visitor.chain.ScanningMode) CtType(spoon.reflect.declaration.CtType) CtTypeReference(spoon.reflect.reference.CtTypeReference) CtScannerFunction(spoon.reflect.visitor.filter.CtScannerFunction) CtScannerListener(spoon.reflect.visitor.chain.CtScannerListener) HashSet(java.util.HashSet)

Example 35 with CtTypeReference

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;
}
Also used : CtTypeReference(spoon.reflect.reference.CtTypeReference)

Aggregations

CtTypeReference (spoon.reflect.reference.CtTypeReference)121 Test (org.junit.Test)56 Launcher (spoon.Launcher)43 Factory (spoon.reflect.factory.Factory)32 CtMethod (spoon.reflect.declaration.CtMethod)26 CtType (spoon.reflect.declaration.CtType)24 ArrayList (java.util.ArrayList)22 TypeFilter (spoon.reflect.visitor.filter.TypeFilter)17 CtClass (spoon.reflect.declaration.CtClass)16 CtField (spoon.reflect.declaration.CtField)16 List (java.util.List)15 CtElement (spoon.reflect.declaration.CtElement)14 CtInvocation (spoon.reflect.code.CtInvocation)13 CtReference (spoon.reflect.reference.CtReference)13 CtParameter (spoon.reflect.declaration.CtParameter)12 CtExpression (spoon.reflect.code.CtExpression)11 CtExecutableReference (spoon.reflect.reference.CtExecutableReference)11 CtTypeParameterReference (spoon.reflect.reference.CtTypeParameterReference)11 CtStatement (spoon.reflect.code.CtStatement)9 NamedElementFilter (spoon.reflect.visitor.filter.NamedElementFilter)9