blob: 16b5ef4f8d027cefe04dbbea6ce6adcbf12e527a [file] [log] [blame]
package com.github.javaparser.generator;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.MarkerAnnotationExpr;
import com.github.javaparser.ast.expr.Name;
import com.github.javaparser.metamodel.BaseNodeMetaModel;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.utils.Log;
import com.github.javaparser.utils.SourceRoot;
import java.util.Optional;
import static com.github.javaparser.ast.Modifier.PUBLIC;
/**
* Makes it easier to generate visitor classes.
* It will create missing visit methods on the fly,
* and will ask you to fill in the bodies of the visit methods.
*/
public abstract class VisitorGenerator extends Generator {
private final String pkg;
private final String visitorClassName;
private final String returnType;
private final String argumentType;
private final boolean createMissingVisitMethods;
protected VisitorGenerator(SourceRoot sourceRoot, String pkg, String visitorClassName, String returnType, String argumentType, boolean createMissingVisitMethods) {
super(sourceRoot);
this.pkg = pkg;
this.visitorClassName = visitorClassName;
this.returnType = returnType;
this.argumentType = argumentType;
this.createMissingVisitMethods = createMissingVisitMethods;
}
public final void generate() throws Exception {
Log.info("Running %s", getClass().getSimpleName());
final CompilationUnit compilationUnit = sourceRoot.tryToParse(pkg, visitorClassName + ".java").getResult().get();
Optional<ClassOrInterfaceDeclaration> visitorClassOptional = compilationUnit.getClassByName(visitorClassName);
if (!visitorClassOptional.isPresent()) {
visitorClassOptional = compilationUnit.getInterfaceByName(visitorClassName);
}
final ClassOrInterfaceDeclaration visitorClass = visitorClassOptional.get();
JavaParserMetaModel.getNodeMetaModels().stream()
.filter((baseNodeMetaModel) -> !baseNodeMetaModel.isAbstract())
.forEach(node -> generateVisitMethodForNode(node, visitorClass, compilationUnit));
after();
}
protected void after() throws Exception {
}
private void generateVisitMethodForNode(BaseNodeMetaModel node, ClassOrInterfaceDeclaration visitorClass, CompilationUnit compilationUnit) {
final Optional<MethodDeclaration> existingVisitMethod = visitorClass.getMethods().stream()
.filter(m -> m.getNameAsString().equals("visit"))
.filter(m -> m.getParameter(0).getType().toString().equals(node.getTypeName()))
.findFirst();
if (existingVisitMethod.isPresent()) {
generateVisitMethodBody(node, existingVisitMethod.get(), compilationUnit);
} else if (createMissingVisitMethods) {
MethodDeclaration newVisitMethod = visitorClass.addMethod("visit")
.addParameter(node.getTypeNameGenerified(), "n")
.addParameter(argumentType, "arg")
.setType(returnType);
if (!visitorClass.isInterface()) {
newVisitMethod
.addAnnotation(new MarkerAnnotationExpr(new Name("Override")))
.addModifier(PUBLIC);
}
generateVisitMethodBody(node, newVisitMethod, compilationUnit);
}
}
protected abstract void generateVisitMethodBody(BaseNodeMetaModel node, MethodDeclaration visitMethod, CompilationUnit compilationUnit);
}