/**
* 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.generating;
import spoon.processing.AbstractManualProcessor;
import spoon.reflect.code.CtComment;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtVariableAccess;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtTypeMember;
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.CtScanner;
import spoon.reflect.visitor.filter.TypeFilter;
import java.util.List;
public class CtBiScannerGenerator extends AbstractManualProcessor {
private static final String TARGET_BISCANNER_PACKAGE = "spoon.reflect.visitor";
private static final String GENERATING_BISCANNER_PACKAGE = "spoon.generating.scanner";
private static final String GENERATING_BISCANNER = GENERATING_BISCANNER_PACKAGE + ".CtBiScannerTemplate";
public void process() {
final CtLocalVariable<?> peekElement = getFactory().Class()
.get(GENERATING_BISCANNER_PACKAGE + ".PeekElementTemplate")
.getMethod("statement")
.getBody().getStatement(0);
final CtClass<Object> target = createBiScanner();
for (CtTypeMember tm : getFactory().Class().get(CtScanner.class).getTypeMembers()) {
if (!(tm instanceof CtMethod)) {
continue;
}
CtMethod<?> element = (CtMethod) tm;
if (!element.getSimpleName().startsWith("visitCt")) {
continue;
}
Factory factory = element.getFactory();
CtMethod<?> clone = factory.Core().clone(element);
clone.addComment(getFactory().Code().createComment("autogenerated by " + getClass().getSimpleName(), CtComment.CommentType.INLINE));
// Peek element from Stack.
final CtLocalVariable<?> peek = factory.Core().clone(peekElement);
final CtTypeReference type = factory.Core().clone(clone.getParameters().get(0).getType());
type.getActualTypeArguments().clear();
peek.getDefaultExpression().addTypeCast(type);
peek.setType(type);
clone.getBody().insertBegin(peek);
for (int i = 2; i < clone.getBody().getStatements().size() - 1; i++) {
final CtInvocation targetInvocation = (CtInvocation) ((CtInvocation) clone.getBody().getStatement(i)).getArguments().get(0);
if ("getValue".equals(targetInvocation.getExecutable().getSimpleName()) && "CtLiteral".equals(targetInvocation.getExecutable().getDeclaringType().getSimpleName())) {
clone.getBody().getStatement(i--).delete();
continue;
}
CtInvocation replace = (CtInvocation) factory.Core().clone(clone.getBody().getStatement(i));
// Changes to biScan method.
replace.getExecutable().setSimpleName("biScan");
// Creates other inv.
final CtVariableAccess<?> otherRead = factory.Code().createVariableRead(peek.getReference(), false);
replace.addArgument(factory.Code().createInvocation(otherRead, ((CtInvocation) replace.getArguments().get(0)).getExecutable()));
if ("Map".equals(targetInvocation.getExecutable().getType().getSimpleName())) {
((CtExpression) replace.getArguments().get(0)).replace(factory.Code().createInvocation(targetInvocation, factory.Executable().createReference("List Map#values()")));
replace.getArguments().add(1, factory.Code().createInvocation((CtExpression) replace.getArguments().get(1), factory.Executable().createReference("List Map#values()")));
replace.getArguments().remove(2);
}
clone.getBody().getStatement(i).replace(replace);
}
target.addMethod(clone);
}
}
private CtClass<Object> createBiScanner() {
final CtPackage aPackage = getFactory().Package().getOrCreate(TARGET_BISCANNER_PACKAGE);
final CtClass<Object> target = getFactory().Class().get(GENERATING_BISCANNER);
target.setSimpleName("CtBiScannerDefault");
target.addModifier(ModifierKind.PUBLIC);
aPackage.addType(target);
target.addComment(getFactory().Code().createComment("autogenerated by " + getClass().getSimpleName(), CtComment.CommentType.INLINE));
final List<CtTypeReference> references = target.getElements(new TypeFilter<CtTypeReference>(CtTypeReference.class) {
@Override
public boolean matches(CtTypeReference reference) {
return GENERATING_BISCANNER.equals(reference.getQualifiedName());
}
});
for (CtTypeReference reference : references) {
reference.setSimpleName("CtBiScannerDefault");
reference.setPackage(aPackage.getReference());
}
return target;
}
}