Skip to content

Commit

Permalink
Variable scope and reference query
Browse files Browse the repository at this point in the history
  • Loading branch information
pvojtechovsky committed Jan 18, 2017
1 parent e5e9812 commit b2b5ed8
Show file tree
Hide file tree
Showing 6 changed files with 748 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ public DirectReferenceFilter(CtReference reference) {
}

public boolean matches(T reference) {
if (super.matches(reference) == false) {
return false;
}
return this.reference.equals(reference);
}
}
56 changes: 56 additions & 0 deletions src/main/java/spoon/reflect/visitor/filter/SubtypeFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.reflect.visitor.filter;

import spoon.reflect.declaration.CtType;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.Filter;

/**
* Matches all CtType elements which are sub type of {@link #superType}
* Call {@link #includingSelf(boolean)} with value false, if instance of {@link #superType} should no match this {@link Filter}
*/
public class SubtypeFilter implements Filter<CtType<?>> {

private CtTypeReference<?> superType;
private String superTypeQualifiedName;

public SubtypeFilter(CtTypeReference<?> superType) {
this.superType = superType;
}

/**
* @param includingSelf if false then element which is equal to to #superType is not matching
*/
public SubtypeFilter includingSelf(boolean includingSelf) {
if (includingSelf) {
superTypeQualifiedName = null;
} else {
superTypeQualifiedName = superType.getQualifiedName();
}
return this;
}

@Override
public boolean matches(CtType<?> mayBeSubType) {
if (superTypeQualifiedName != null && superTypeQualifiedName.equals(mayBeSubType.getQualifiedName())) {
//we should not accept superType
return false;
}
return mayBeSubType.isSubtypeOf(superType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.reflect.visitor.query;

import spoon.reflect.code.CtCatchVariable;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtParameter;
import spoon.reflect.declaration.CtVariable;
import spoon.reflect.reference.CtCatchVariableReference;
import spoon.reflect.reference.CtFieldReference;
import spoon.reflect.reference.CtLocalVariableReference;
import spoon.reflect.reference.CtParameterReference;
import spoon.reflect.reference.CtVariableReference;
import spoon.reflect.visitor.filter.DirectReferenceFilter;

/**
* The mapping function, accepting {@link CtVariable}
* and returning all the references {@link CtVariableReference} to that variable.
* Supports all variable types:
* <ul>
* <li>CtLocalVariable - local variable declared in body
* <li>CtField - member field of an type
* <li>CtParameter - method parameter
* <li>CtCatchVariable - try - catch variable
* </ul>
*/
public class VariableReferenceQuery extends VariableScopeQuery {

@Override
protected <T> void visitCtCatchVariable(CtCatchVariable<T> catchVariable) {
filter = new DirectReferenceFilter<CtCatchVariableReference<?>>(catchVariable.getReference());
super.visitCtCatchVariable(catchVariable);
}

@Override
protected <T> void visitCtField(CtField<T> field) {
filter = new DirectReferenceFilter<CtFieldReference<?>>(field.getReference());
super.visitCtField(field);
}

@Override
protected <T> void visitCtLocalVariable(CtLocalVariable<T> localVariable) {
filter = new DirectReferenceFilter<CtLocalVariableReference<T>>(localVariable.getReference());
super.visitCtLocalVariable(localVariable);
}

@Override
protected <T> void visitCtParameter(CtParameter<T> parameter) {
filter = new DirectReferenceFilter<CtParameterReference<?>>(parameter.getReference());
super.visitCtParameter(parameter);
}
}
192 changes: 192 additions & 0 deletions src/main/java/spoon/reflect/visitor/query/VariableScopeQuery.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.reflect.visitor.query;

import java.util.List;

import spoon.SpoonException;
import spoon.reflect.code.CtCatch;
import spoon.reflect.code.CtCatchVariable;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtStatement;
import spoon.reflect.code.CtStatementList;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtExecutable;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtParameter;
import spoon.reflect.declaration.CtVariable;
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.visitor.CtScanner;
import spoon.reflect.visitor.Filter;
import spoon.reflect.visitor.chain.CtConsumableFunction;
import spoon.reflect.visitor.chain.CtConsumer;
import spoon.reflect.visitor.chain.CtQueryImpl;
import spoon.reflect.visitor.filter.SubtypeFilter;

/**
* The mapping function, accepting {@link CtVariable}
* and returning all the CtElements, which exists in visibility scope of this variable
* <ul>
* <li>CtLocalVariable - local variable declared in body
* <li>CtField - member field of an type
* <li>CtParameter - method parameter
* <li>CtCatchVariable - try - catch variable
* </ul>
*/
public class VariableScopeQuery implements CtConsumableFunction<CtVariable<?>> {

Visitor visitor = new Visitor();
CtConsumer<Object> outputConsumer;
protected Filter<? extends CtElement> filter = MATCH_ALL_FILTER;

@Override
public void apply(CtVariable<?> variable, CtConsumer<Object> outputConsumer) {
this.outputConsumer = outputConsumer;
variable.accept(visitor);
}

protected class Visitor extends CtScanner {
@Override
protected void enter(CtElement e) {
throw new SpoonException("Unsupported variable of type " + e.getClass().getName());
}
/**
* calls outputConsumer for each reference of the field
*/
@Override
public <T> void visitCtField(CtField<T> field) {
VariableScopeQuery.this.visitCtField(field);
}

/**
* calls outputConsumer for each reference of the localVariable
*/
@Override
public <T> void visitCtLocalVariable(CtLocalVariable<T> localVariable) {
VariableScopeQuery.this.visitCtLocalVariable(localVariable);
}

/**
* calls outputConsumer for each reference of the parameter
*/
@Override
public <T> void visitCtParameter(CtParameter<T> parameter) {
VariableScopeQuery.this.visitCtParameter(parameter);
}

/**
* calls outputConsumer for each reference of the catch parameter
*/
@Override
public <T> void visitCtCatchVariable(CtCatchVariable<T> catchVariable) {
VariableScopeQuery.this.visitCtCatchVariable(catchVariable);
}
}
/**
* calls outputConsumer for each element in scope of visibility of field
*/
protected <T> void visitCtField(CtField<T> field) {
if (field.hasModifier(ModifierKind.PRIVATE)) {
searchForPrivateField(field);
} else if (field.hasModifier(ModifierKind.PUBLIC)) {
searchForPublicField(field);
} else if (field.hasModifier(ModifierKind.PROTECTED)) {
searchForProtectedField(field);
} else {
searchForPackageProtectedField(field);
}
}

/**
* calls outputConsumer for each element in scope of visibility of the localVariable
*/
protected <T> void visitCtLocalVariable(CtLocalVariable<T> localVariable) {
CtStatementList statements = localVariable.getParent(CtStatementList.class);
if (statements == null) {
//cannot search for parameter references of parameter which has no executable
return;
}
//create query which will be evaluated on each statement after local variable declaration
CtQueryImpl query = (CtQueryImpl) localVariable.getFactory().createQuery().filterChildren(getFilter());
List<CtStatement> stats = statements.getStatements();
int idxOfVar = stats.indexOf(localVariable);
if (idxOfVar < 0) {
throw new SpoonException("Cannot found index of local variable declaration " + localVariable + " in statement list " + statements);
}
for (int i = idxOfVar + 1; i < stats.size(); i++) {
query.evaluate(stats.get(i), outputConsumer);
}
}

/**
* calls outputConsumer for each element in scope of visibility of the parameter
*/
protected <T> void visitCtParameter(CtParameter<T> parameter) {
CtExecutable<?> exec = parameter.getParent(CtExecutable.class);
if (exec == null) {
//cannot search for parameter references of parameter which has no executable
return;
}
exec.filterChildren(getFilter()).forEach(outputConsumer);
}

/**
* calls outputConsumer for each element in scope of visibility of the catch parameter
*/
protected <T> void visitCtCatchVariable(CtCatchVariable<T> catchVariable) {
catchVariable.getParent(CtCatch.class).getBody().filterChildren(getFilter())
.forEach(outputConsumer);
}

protected void searchForPrivateField(CtField<?> field) {
//private field can be referred from the scope of current top level type only
field.getTopLevelType()
.filterChildren(getFilter())
.forEach(outputConsumer);
}
protected void searchForProtectedField(CtField<?> field) {
//protected field can be referred from the scope of current top level type only
field.getFactory().getModel().getRootPackage()
.filterChildren(new SubtypeFilter(field.getDeclaringType().getReference()))
.filterChildren(getFilter())
.forEach(outputConsumer);
}
protected void searchForPublicField(CtField<?> field) {
field.getFactory().getModel().getRootPackage()
.filterChildren(getFilter())
.forEach(outputConsumer);
}
protected void searchForPackageProtectedField(CtField<?> field) {
field.getTopLevelType().getPackage()
.filterChildren(getFilter())
.forEach(outputConsumer);
}
protected static final Filter<CtElement> MATCH_ALL_FILTER = new Filter<CtElement>() {
public boolean matches(CtElement element) {
return true;
};
};
public Filter<? extends CtElement> getFilter() {
return filter;
}

public VariableScopeQuery setFilter(Filter<? extends CtElement> filter) {
this.filter = filter;
return this;
}

}
Loading

0 comments on commit b2b5ed8

Please sign in to comment.