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;
}
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;
}
}
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
}
}
});
});
}
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);
}
}
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();
}
Aggregations