use of spoon.reflect.code.CtStatement in project spoon by INRIA.
the class TemplateMatcher method matchCollections.
@SuppressWarnings("unchecked")
private boolean matchCollections(Collection<?> target, Collection<?> template) {
final List<Object> teList = new ArrayList<>(template);
final List<Object> taList = new ArrayList<>(target);
// inMulti keeps the multiElement templateVariable we are at
CtElement inMulti = nextListStatement(teList, null);
// multi keeps the values to assign to inMulti
List<Object> multi = new ArrayList<>();
if (null == inMulti) {
// the sizes should then be the same
if (teList.size() != taList.size()) {
return false;
}
for (int te = 0, ta = 0; (te < teList.size()) && (ta < taList.size()); te++, ta++) {
if (!helperMatch(taList.get(ta), teList.get(te))) {
return false;
}
}
return true;
}
for (int te = 0, ta = 0; (te < teList.size()) && (ta < taList.size()); te++, ta++) {
if (isCurrentTemplate(teList.get(te), inMulti)) {
// te index points to template parameter, which accepts multiple statements
if (te + 1 >= teList.size()) {
// it is the last parameter of template list. Add all remaining target list items
multi.addAll(taList.subList(te, taList.size()));
// create statement list and add match
CtStatementList tpl = templateType.getFactory().Core().createStatementList();
tpl.setStatements((List<CtStatement>) (List<?>) multi);
if (!invokeCallBack(tpl, inMulti)) {
return false;
}
boolean ret = addMatch(inMulti, multi);
return ret;
}
// there is next template parameter. Move to it
te++;
// adds all target list items, which are not matching to next template parameter, to the actual template parameter
while ((te < teList.size()) && (ta < taList.size()) && !helperMatch(taList.get(ta), teList.get(te))) {
multi.add(taList.get(ta));
ta++;
}
// we have found first target parameter, which fits to next template parameter
// create statement list for previous parameter and add it's match
CtStatementList tpl = templateType.getFactory().Core().createStatementList();
tpl.setStatements((List<CtStatement>) (List<?>) multi);
if (!invokeCallBack(tpl, inMulti)) {
return false;
}
addMatch(inMulti, tpl);
// update inMulti
inMulti = nextListStatement(teList, inMulti);
multi = new ArrayList<>();
} else {
// parameter on te index is not a multivalue statement
if (!helperMatch(taList.get(ta), teList.get(te))) {
return false;
}
if (!(ta + 1 < taList.size()) && (inMulti != null)) {
/*
* there is no next target item in taList,
* but there is still some template parameter,
* which expects one
*/
CtStatementList tpl = templateType.getFactory().Core().createStatementList();
for (Object o : multi) {
tpl.addStatement((CtStatement) o);
}
// so it returns empty statement list
if (!invokeCallBack(tpl, inMulti)) {
return false;
}
addMatch(inMulti, tpl);
// update inMulti
inMulti = nextListStatement(teList, inMulti);
multi = new ArrayList<>();
}
}
}
return true;
}
use of spoon.reflect.code.CtStatement in project spoon by INRIA.
the class TemplateMatcher method helperMatch.
/**
* Detects whether `template` AST node and `target` AST node are matching.
* This method is called for each node of to be matched template
* and for appropriate node of `target`
*
* @param target actually checked AST node from target model
* @param template actually checked AST node from template
*
* @return true if template matches this node, false if it does not matches
*
* note: Made private to hide the Objects.
*/
private boolean helperMatch(Object target, Object template) {
if ((target == null) && (template == null)) {
return true;
}
if ((target == null) || (template == null)) {
return false;
}
if (containsSame(variables, template) || containsSame(typeVariables, template)) {
/*
* we are just matching a template parameter.
* Check that defined ParameterMatcher matches the target too
*/
boolean add = invokeCallBack(target, template);
if (add) {
// ParameterMatcher matches the target too, add that match
return addMatch(template, target);
}
return false;
}
if (target.getClass() != template.getClass()) {
return false;
}
if ((template instanceof CtTypeReference) && template.equals(templateType.getReference())) {
return true;
}
if ((template instanceof CtPackageReference) && template.equals(templateType.getPackage())) {
return true;
}
if (template instanceof CtReference) {
CtReference tRef = (CtReference) template;
/*
* Check whether name of a template reference matches with name of target reference
* after replacing of variables in template name
*/
boolean ok = matchNames(tRef.getSimpleName(), ((CtReference) target).getSimpleName());
if (ok && !template.equals(target)) {
boolean remove = !invokeCallBack(target, template);
if (remove) {
matches.remove(tRef.getSimpleName());
return false;
}
return true;
}
}
if (template instanceof CtNamedElement) {
CtNamedElement named = (CtNamedElement) template;
boolean ok = matchNames(named.getSimpleName(), ((CtNamedElement) target).getSimpleName());
if (ok && !template.equals(target)) {
boolean remove = !invokeCallBack(target, template);
if (remove) {
matches.remove(named.getSimpleName());
return false;
}
}
}
if (template instanceof Collection) {
return matchCollections((Collection<?>) target, (Collection<?>) template);
}
if (template instanceof Map) {
if (template.equals(target)) {
return true;
}
Map<?, ?> temMap = (Map<?, ?>) template;
Map<?, ?> tarMap = (Map<?, ?>) target;
if (!temMap.keySet().equals(tarMap.keySet())) {
return false;
}
return matchCollections(tarMap.values(), temMap.values());
}
if (template instanceof CtBlock<?>) {
final List<CtStatement> statements = ((CtBlock) template).getStatements();
if (statements.size() == 1 && statements.get(0) instanceof CtInvocation) {
final CtInvocation ctStatement = (CtInvocation) statements.get(0);
if ("S".equals(ctStatement.getExecutable().getSimpleName()) && CtBlock.class.equals(ctStatement.getType().getActualClass())) {
return true;
}
}
}
if (target instanceof CtElement) {
for (Field f : RtHelper.getAllFields(target.getClass())) {
f.setAccessible(true);
if (Modifier.isStatic(f.getModifiers())) {
continue;
}
if (f.getName().equals("parent")) {
continue;
}
if (f.getName().equals("position")) {
continue;
}
if (f.getName().equals("docComment")) {
continue;
}
if (f.getName().equals("factory")) {
continue;
}
if (f.getName().equals("comments")) {
continue;
}
if (f.getName().equals("metadata")) {
continue;
}
try {
if (!helperMatch(f.get(target), f.get(template))) {
return false;
}
} catch (IllegalAccessException ignore) {
}
}
return true;
} else if (target instanceof String) {
return matchNames((String) template, (String) target);
} else {
return target.equals(template);
}
}
use of spoon.reflect.code.CtStatement in project spoon by INRIA.
the class VisitorPartialEvaluator method visitCtBlock.
public <R> void visitCtBlock(CtBlock<R> block) {
CtBlock<?> b = block.getFactory().Core().createBlock();
for (CtStatement s : block.getStatements()) {
CtElement res = evaluate(s);
if (res != null) {
if (res instanceof CtStatement) {
b.addStatement((CtStatement) res);
} else {
// the context expectes statement. We cannot simplify in this case
b.addStatement(s);
}
}
// do not copy unreachable statements
if (flowEnded) {
break;
}
}
setResult(b);
}
use of spoon.reflect.code.CtStatement in project spoon by INRIA.
the class TemplateClassAccessTest method testClassAccessTest.
@Test
public void testClassAccessTest() throws Exception {
// contract: the template engine supports class access substitution
Launcher spoon = new Launcher();
spoon.addTemplateResource(new FileSystemFile("./src/test/java/spoon/test/template/testclasses/ClassAccessTemplate.java"));
spoon.buildModel();
Factory factory = spoon.getFactory();
CtClass<?> resultKlass = factory.Class().create("Result");
CtStatement result = new ClassAccessTemplate(String.class).apply(resultKlass);
assertEquals("java.lang.String.class.getName()", result.toString());
// I do not know if it makes sense to use null. But this kind of null handling is probably the best
CtStatement result2 = new ClassAccessTemplate(null).apply(resultKlass);
assertEquals("null.getName()", result2.toString());
}
use of spoon.reflect.code.CtStatement in project spoon by INRIA.
the class TemplateArrayAccessTest method testArrayAccess.
@Test
public void testArrayAccess() throws Exception {
// contract: the template engine supports variable access, typed as Array substitution
Launcher spoon = new Launcher();
spoon.addTemplateResource(new FileSystemFile("./src/test/java/spoon/test/template/testclasses/SubstituteArrayAccessTemplate.java"));
spoon.buildModel();
Factory factory = spoon.getFactory();
CtClass<?> resultKlass = factory.Class().create("Result");
CtStatement result = new SubstituteArrayAccessTemplate(new String[] { "a", null, "b" }).apply(resultKlass);
assertEquals("new java.lang.String[]{ \"a\", null, \"b\" }.toString()", result.toString());
}
Aggregations