Search in sources :

Example 1 with CtVariable

use of spoon.reflect.declaration.CtVariable in project spoon by INRIA.

the class ImportScannerImpl method lookForLocalVariables.

protected Set<String> lookForLocalVariables(CtElement parent) {
    Set<String> result = new HashSet<>();
    // if the first container is the class, then we are not in a block and we can quit now.
    while (parent != null && !(parent instanceof CtBlock)) {
        if (parent instanceof CtClass) {
            return result;
        }
        parent = parent.getParent();
    }
    if (parent != null) {
        CtBlock block = (CtBlock) parent;
        boolean innerClass = false;
        // now we have the first container block, we want to check if we're not in an inner class
        while (parent != null && !(parent instanceof CtClass)) {
            parent = parent.getParent();
        }
        if (parent != null) {
            // let's find the last block BEFORE the class call: some collision could occur because of variables defined in that block
            if (!(parent.getParent() instanceof CtPackage)) {
                while (parent != null && !(parent instanceof CtBlock)) {
                    parent = parent.getParent();
                }
                if (parent != null) {
                    block = (CtBlock) parent;
                }
            }
        }
        AccessibleVariablesFinder avf = new AccessibleVariablesFinder(block);
        List<CtVariable> variables = avf.find();
        for (CtVariable variable : variables) {
            result.add(variable.getSimpleName());
        }
    }
    return result;
}
Also used : CtClass(spoon.reflect.declaration.CtClass) CtBlock(spoon.reflect.code.CtBlock) CtVariable(spoon.reflect.declaration.CtVariable) CtPackage(spoon.reflect.declaration.CtPackage) HashSet(java.util.HashSet)

Example 2 with CtVariable

use of spoon.reflect.declaration.CtVariable in project spoon by INRIA.

the class PotentialVariableDeclarationFunction method apply.

@Override
public void apply(CtElement input, CtConsumer<Object> outputConsumer) {
    isTypeOnTheWay = false;
    isInStaticScope = false;
    // Search previous siblings for element which may represents the declaration of this local variable
    CtQuery siblingsQuery = input.getFactory().createQuery().map(new SiblingsFunction().mode(SiblingsFunction.Mode.PREVIOUS)).select(new TypeFilter<>(CtVariable.class));
    if (variableName != null) {
        // variable name is defined so we have to search only for variables with that name
        siblingsQuery = siblingsQuery.select(new NamedElementFilter<>(CtNamedElement.class, variableName));
    }
    CtElement scopeElement = input;
    // Search input and then all parents until first CtPackage for element which may represents the declaration of this local variable
    while (scopeElement != null && !(scopeElement instanceof CtPackage) && scopeElement.isParentInitialized()) {
        CtElement parent = scopeElement.getParent();
        if (parent instanceof CtType<?>) {
            isTypeOnTheWay = true;
            // visit each CtField of `parent` CtType
            CtQuery q = parent.map(new AllTypeMembersFunction(CtField.class));
            q.forEach((CtField<?> field) -> {
                if (isInStaticScope && field.hasModifier(ModifierKind.STATIC) == false) {
                    /*
						 * the variable reference is used in static scope,
						 * but the field is not static - ignore it
						 */
                    return;
                }
                // else send field as potential variable declaration
                if (sendToOutput(field, outputConsumer)) {
                    // and terminate the internal query q if outer query is already terminated
                    q.terminate();
                }
            });
            if (query.isTerminated()) {
                return;
            }
        } else if (parent instanceof CtBodyHolder || parent instanceof CtStatementList) {
            // visit all previous CtVariable siblings of scopeElement element in parent BodyHolder or Statement list
            siblingsQuery.setInput(scopeElement).forEach(outputConsumer);
            if (query.isTerminated()) {
                return;
            }
            // visit parameters of CtCatch and CtExecutable (method, lambda)
            if (parent instanceof CtCatch) {
                CtCatch ctCatch = (CtCatch) parent;
                if (sendToOutput(ctCatch.getParameter(), outputConsumer)) {
                    return;
                }
            } else if (parent instanceof CtExecutable) {
                CtExecutable<?> exec = (CtExecutable<?>) parent;
                for (CtParameter<?> param : exec.getParameters()) {
                    if (sendToOutput(param, outputConsumer)) {
                        return;
                    }
                }
            }
        }
        if (parent instanceof CtModifiable) {
            isInStaticScope = isInStaticScope || ((CtModifiable) parent).hasModifier(ModifierKind.STATIC);
        }
        scopeElement = parent;
    }
}
Also used : CtElement(spoon.reflect.declaration.CtElement) CtQuery(spoon.reflect.visitor.chain.CtQuery) CtExecutable(spoon.reflect.declaration.CtExecutable) CtBodyHolder(spoon.reflect.code.CtBodyHolder) CtType(spoon.reflect.declaration.CtType) CtField(spoon.reflect.declaration.CtField) CtVariable(spoon.reflect.declaration.CtVariable) CtPackage(spoon.reflect.declaration.CtPackage) CtStatementList(spoon.reflect.code.CtStatementList) CtCatch(spoon.reflect.code.CtCatch) CtModifiable(spoon.reflect.declaration.CtModifiable)

Example 3 with CtVariable

use of spoon.reflect.declaration.CtVariable in project spoon by INRIA.

the class CtRenameLocalVariableRefactoringTest method testRenameAllLocalVariablesOfRenameTestSubject.

/**
 * The {@link CtRenameLocalVariableRefactoringTestSubject} class is loaded as spoon model. Then:
 * - It looks for each CtVariable and it's CtAnnotation and tries to rename that variable to the name defined by annotation.
 * - If the annotation name is prefixed with "-", then that refactoring should fail.
 * - If the annotation name is not prefixed, then that refactoring should pass.
 * If it behaves different then expected, then this test fails
 */
@Test
public void testRenameAllLocalVariablesOfRenameTestSubject() throws Exception {
    final Launcher launcher = new Launcher();
    final SpoonModelBuilder comp = launcher.createCompiler();
    comp.addInputSources(SpoonResourceHelper.resources("./src/test/java/" + CtRenameLocalVariableRefactoringTestSubject.class.getName().replace('.', '/') + ".java"));
    comp.build();
    final Factory factory = comp.getFactory();
    CtClass<?> varRenameClass = (CtClass<?>) factory.Type().get(CtRenameLocalVariableRefactoringTestSubject.class);
    CtTypeReference<TestTryRename> tryRename = varRenameClass.getFactory().createCtTypeReference(TestTryRename.class);
    varRenameClass.getMethods().forEach(method -> {
        // debugging support
        if (DEBUG.length == 3 && DEBUG[0].equals(method.getSimpleName()) == false)
            return;
        method.filterChildren((CtVariable var) -> true).map((CtVariable var) -> var.getAnnotation(tryRename)).forEach((CtAnnotation<TestTryRename> annotation) -> {
            String[] newNames = annotation.getActualAnnotation().value();
            CtVariable<?> targetVariable = (CtVariable<?>) annotation.getAnnotatedElement();
            for (String newName : newNames) {
                boolean renameShouldPass = newName.startsWith("-") == false;
                if (!renameShouldPass) {
                    newName = newName.substring(1);
                }
                if (targetVariable instanceof CtLocalVariable<?>) {
                    // debugging support
                    if (DEBUG.length == 3 && DEBUG[1].equals(targetVariable.getSimpleName()) && DEBUG[2].equals(newName)) {
                        // put breakpoint here and continue debugging of the buggy case
                        this.getClass();
                    }
                    checkLocalVariableRename(launcher, (CtLocalVariable<?>) targetVariable, newName, renameShouldPass);
                } else {
                // TODO test rename of other variables, e.g. parameters and catch... later
                }
            }
        });
    });
}
Also used : SpoonModelBuilder(spoon.SpoonModelBuilder) CtAnnotation(spoon.reflect.declaration.CtAnnotation) Factory(spoon.reflect.factory.Factory) CtLocalVariable(spoon.reflect.code.CtLocalVariable) CtClass(spoon.reflect.declaration.CtClass) TestTryRename(spoon.test.refactoring.testclasses.TestTryRename) CtVariable(spoon.reflect.declaration.CtVariable) Launcher(spoon.Launcher) CtRenameLocalVariableRefactoringTestSubject(spoon.test.refactoring.testclasses.CtRenameLocalVariableRefactoringTestSubject) Test(org.junit.Test)

Example 4 with CtVariable

use of spoon.reflect.declaration.CtVariable in project spoon by INRIA.

the class CloneReferenceTest method testGetDeclarationAfterClone.

@Test
public void testGetDeclarationAfterClone() throws Exception {
    // contract: all variable references of the clone (but fields) should point to the variable of the clone
    Launcher spoon = new Launcher();
    List<String> names = Arrays.asList("f1", "f2", "a", "b", "x", "param", "e");
    spoon.addInputResource("./src/test/resources/noclasspath/A2.java");
    spoon.getEnvironment().setComplianceLevel(8);
    spoon.getEnvironment().setNoClasspath(true);
    spoon.buildModel();
    final CtClass<Object> a = spoon.getFactory().Class().get("A2");
    // test before clone
    for (String name : names) {
        CtVariable var1 = findVariable(a, name);
        CtVariable var2 = findReference(a, name).getDeclaration();
        assertTrue(var1 == var2);
    }
    CtClass b = a.clone();
    // test after clone
    for (String name : names) {
        CtVariable var1 = findVariable(b, name);
        CtVariableReference refVar1 = findReference(b, name);
        CtVariable var2 = refVar1.getDeclaration();
        assertTrue("Var1 and var2 are not the same element", var1 == var2);
    }
}
Also used : CtClass(spoon.reflect.declaration.CtClass) CtVariableReference(spoon.reflect.reference.CtVariableReference) CtVariable(spoon.reflect.declaration.CtVariable) Launcher(spoon.Launcher) Test(org.junit.Test)

Example 5 with CtVariable

use of spoon.reflect.declaration.CtVariable in project spoon by INRIA.

the class CtRenameLocalVariableRefactoring method detectNameConflicts.

@Override
protected void detectNameConflicts() {
    /*
		 * There can be these conflicts
		 * 1) target variable would shadow before declared variable (parameter, localVariable, catchVariable)
		 * --------------------------------------------------------------------------------------------------
		 */
    PotentialVariableDeclarationFunction potentialDeclarationFnc = new PotentialVariableDeclarationFunction(newName);
    CtVariable<?> var = getTarget().map(potentialDeclarationFnc).first();
    if (var != null) {
        if (var instanceof CtField) {
        /*
				 * we have found a field of same name.
				 * It is not problem, because variables can hide field declaration.
				 * Do nothing - OK
				 */
        } else if (potentialDeclarationFnc.isTypeOnTheWay()) {
            /*
				 * There is a local class declaration between future variable reference and variable declaration `var`.
				 * The found variable declaration `var` can be hidden by target variable with newName
				 * as long as there is no reference to `var` in visibility scope of the target variable.
				 * So search for such `var` reference now
				 */
            CtVariableReference<?> shadowedVar = target.map(new SiblingsFunction().includingSelf(true).mode(Mode.NEXT)).map(new VariableReferenceFunction(var)).first();
            if (shadowedVar != null) {
                // found variable reference, which would be shadowed by variable after rename.
                createNameConflictIssue(var, shadowedVar);
            } else {
            /*
					 * there is no local variable reference, which would be shadowed by variable after rename.
					 * OK
					 */
            }
        } else {
            /*
				 * the found variable is in conflict with target variable with newName
				 */
            createNameConflictIssue(var);
        }
    }
    /*
		 * 2) target variable is shadowed by later declared variable
		 * ---------------------------------------------------------
		 */
    final QueryDriver queryDriver = new QueryDriver();
    getTarget().map(new LocalVariableScopeFunction(queryDriver)).select(new Filter<CtElement>() {

        /**
         * return true for all CtVariables, which are in conflict
         */
        @Override
        public boolean matches(CtElement element) {
            if (element instanceof CtType<?>) {
                CtType<?> localClass = (CtType<?>) element;
                // TODO use faster hasField, implemented using map(new AllFieldsFunction()).select(new NameFilter(newName)).first()!=null
                Collection<CtFieldReference<?>> fields = localClass.getAllFields();
                for (CtFieldReference<?> fieldRef : fields) {
                    if (newName.equals(fieldRef.getSimpleName())) {
                        /*
							 * we have found a local class field, which will shadow input local variable if it's reference is in visibility scope of that field.
							 * Search for target variable reference in visibility scope of this field.
							 * If found than we cannot rename target variable to newName, because that reference would be shadowed
							 */
                        queryDriver.ignoreChildrenOf(element);
                        CtLocalVariableReference<?> shadowedVar = element.map(new LocalVariableReferenceFunction(target)).first();
                        if (shadowedVar != null) {
                            createNameConflictIssue(fieldRef.getFieldDeclaration(), shadowedVar);
                            return true;
                        }
                        return false;
                    }
                }
                return false;
            }
            if (element instanceof CtVariable<?>) {
                CtVariable<?> variable = (CtVariable<?>) element;
                if (newName.equals(variable.getSimpleName()) == false) {
                    // the variable with different name. Ignore it
                    return false;
                }
                // we have found a variable with new name
                if (variable instanceof CtField) {
                    throw new SpoonException("This should not happen. The children of local class which contains a field with new name should be skipped!");
                }
                if (variable instanceof CtCatchVariable || variable instanceof CtLocalVariable || variable instanceof CtParameter) {
                    /*
						 * we have found a catch variable or local variable or parameter with new name.
						 */
                    if (queryDriver.isInContextOfLocalClass()) {
                        /*
							 * We are in context of local class.
							 * This variable would shadow input local variable after rename
							 * so we cannot rename if there exist a local variable reference in variable visibility scope.
							 */
                        queryDriver.ignoreChildrenOf(variable.getParent());
                        CtQueryable searchScope;
                        if (variable instanceof CtLocalVariable) {
                            searchScope = variable.map(new SiblingsFunction().includingSelf(true).mode(Mode.NEXT));
                        } else {
                            searchScope = variable.getParent();
                        }
                        CtLocalVariableReference<?> shadowedVar = searchScope.map(new LocalVariableReferenceFunction(target)).first();
                        if (shadowedVar != null) {
                            // found local variable reference, which would be shadowed by variable after rename.
                            createNameConflictIssue(variable, shadowedVar);
                            return true;
                        }
                        // there is no local variable reference, which would be shadowed by variable after rename.
                        return false;
                    } else {
                        /*
							 * We are not in context of local class.
							 * So this variable is in conflict. Return it
							 */
                        createNameConflictIssue(variable);
                        return true;
                    }
                } else {
                    // Any new variable type???
                    throw new SpoonException("Unexpected variable " + variable.getClass().getName());
                }
            }
            return false;
        }
    }).first();
}
Also used : CtVariableReference(spoon.reflect.reference.CtVariableReference) SiblingsFunction(spoon.reflect.visitor.filter.SiblingsFunction) SpoonException(spoon.SpoonException) CtElement(spoon.reflect.declaration.CtElement) VariableReferenceFunction(spoon.reflect.visitor.filter.VariableReferenceFunction) LocalVariableReferenceFunction(spoon.reflect.visitor.filter.LocalVariableReferenceFunction) CtFieldReference(spoon.reflect.reference.CtFieldReference) CtParameter(spoon.reflect.declaration.CtParameter) CtLocalVariable(spoon.reflect.code.CtLocalVariable) CtType(spoon.reflect.declaration.CtType) Filter(spoon.reflect.visitor.Filter) CtField(spoon.reflect.declaration.CtField) CtQueryable(spoon.reflect.visitor.chain.CtQueryable) CtVariable(spoon.reflect.declaration.CtVariable) PotentialVariableDeclarationFunction(spoon.reflect.visitor.filter.PotentialVariableDeclarationFunction) CtCatchVariable(spoon.reflect.code.CtCatchVariable) LocalVariableScopeFunction(spoon.reflect.visitor.filter.LocalVariableScopeFunction) LocalVariableReferenceFunction(spoon.reflect.visitor.filter.LocalVariableReferenceFunction)

Aggregations

CtVariable (spoon.reflect.declaration.CtVariable)11 Test (org.junit.Test)7 Factory (spoon.reflect.factory.Factory)4 CtLocalVariable (spoon.reflect.code.CtLocalVariable)3 CtStatement (spoon.reflect.code.CtStatement)3 CtClass (spoon.reflect.declaration.CtClass)3 CtElement (spoon.reflect.declaration.CtElement)3 CtField (spoon.reflect.declaration.CtField)3 CtPackage (spoon.reflect.declaration.CtPackage)3 CtType (spoon.reflect.declaration.CtType)3 NamedElementFilter (spoon.reflect.visitor.filter.NamedElementFilter)3 ArrayList (java.util.ArrayList)2 Launcher (spoon.Launcher)2 CtCatch (spoon.reflect.code.CtCatch)2 CtStatementList (spoon.reflect.code.CtStatementList)2 CtExecutable (spoon.reflect.declaration.CtExecutable)2 CtMethod (spoon.reflect.declaration.CtMethod)2 CtVariableReference (spoon.reflect.reference.CtVariableReference)2 PotentialVariableDeclarationFunction (spoon.reflect.visitor.filter.PotentialVariableDeclarationFunction)2 VariableReferencesModelTest (spoon.test.query_function.testclasses.VariableReferencesModelTest)2