use of spoon.reflect.visitor.filter.PotentialVariableDeclarationFunction in project spoon by INRIA.
the class DefaultJavaPrettyPrinter method printCtFieldAccess.
private <T> void printCtFieldAccess(CtFieldAccess<T> f) {
enterCtExpression(f);
try (Writable _context = context.modify()) {
if ((f.getVariable().isStatic() || "class".equals(f.getVariable().getSimpleName())) && f.getTarget() instanceof CtTypeAccess) {
_context.ignoreGenerics(true);
}
CtExpression<?> target = f.getTarget();
if (target != null) {
boolean isInitializeStaticFinalField = isInitializeStaticFinalField(f.getTarget());
boolean isStaticField = f.getVariable().isStatic();
boolean isImportedField = this.isImported(f.getVariable());
if (!isInitializeStaticFinalField && !(isStaticField && isImportedField)) {
if (target.isImplicit() && !(f.getVariable().getFieldDeclaration() == null && this.env.getNoClasspath())) {
/*
* target is implicit, check whether there is no conflict with an local variable, catch variable or parameter
* in case of conflict make it explicit, otherwise the field access is shadowed by that variable.
* Search for potential variable declaration until we found a class which declares or inherits this field
*/
final CtField<?> field = f.getVariable().getFieldDeclaration();
if (field != null) {
final String fieldName = field.getSimpleName();
CtVariable<?> var = f.getVariable().map(new PotentialVariableDeclarationFunction(fieldName)).first();
if (var != field) {
// another variable declaration was found which is hiding the field declaration for this field access. Make the field access expicit
target.setImplicit(false);
}
} else {
// There is a model inconsistency
printer.writeComment(f.getFactory().createComment("ERROR: Missing field \"" + f.getVariable().getSimpleName() + "\", please check your model. The code may not compile.", CommentType.BLOCK)).writeSpace();
}
}
// the implicit drives the separator
if (!target.isImplicit()) {
scan(target);
printer.writeSeparator(".");
}
}
_context.ignoreStaticAccess(true);
}
scan(f.getVariable());
}
exitCtExpression(f);
}
use of spoon.reflect.visitor.filter.PotentialVariableDeclarationFunction 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();
}
use of spoon.reflect.visitor.filter.PotentialVariableDeclarationFunction in project spoon by INRIA.
the class VariableReferencesTest method testPotentialVariableAccessFromStaticMethod.
@Test
public void testPotentialVariableAccessFromStaticMethod() throws Exception {
Factory factory = ModelUtils.build(VariableReferencesFromStaticMethod.class);
CtClass<?> clazz = factory.Class().get(VariableReferencesFromStaticMethod.class);
CtMethod staticMethod = clazz.getMethodsByName("staticMethod").get(0);
CtStatement stmt = staticMethod.getBody().getStatements().get(1);
assertEquals("org.junit.Assert.assertTrue((field == 2))", stmt.toString());
CtLocalVariableReference varRef = stmt.filterChildren(new TypeFilter<>(CtLocalVariableReference.class)).first();
List<CtVariable> vars = varRef.map(new PotentialVariableDeclarationFunction()).list();
assertEquals("Found unexpected variable declaration.", 1, vars.size());
}
use of spoon.reflect.visitor.filter.PotentialVariableDeclarationFunction in project spoon by INRIA.
the class CtLocalVariableReferenceImpl method getDeclaration.
@SuppressWarnings("unchecked")
@Override
public CtLocalVariable<T> getDeclaration() {
// without a factory, we are not able to filter for local variables
final Factory factory = getFactory();
if (factory == null) {
return null;
}
final String simpleName = getSimpleName();
// handle the CtLocalVariableReference which were created by CtLocalVariable#getReference() and which are not yet part of model, so we cannot found them using standard rules
if (parent instanceof CtLocalVariable) {
CtLocalVariable<T> var = (CtLocalVariable<T>) parent;
if (simpleName.equals(var.getSimpleName())) {
return var;
}
}
try {
// successively iterate through all parents of this reference and
// return first result (which must be the closest declaration
// respecting visible scope)
CtVariable<?> var = map(new PotentialVariableDeclarationFunction(simpleName)).first();
if (var instanceof CtLocalVariable) {
return (CtLocalVariable<T>) var;
}
if (var != null) {
// handle it as not found
return null;
}
} catch (ParentNotInitializedException e) {
// handle this case as 'not found'
}
return null;
}
Aggregations