io.vertx.codetrans.CodeTranslator Maven / Gradle / Ivy
package io.vertx.codetrans;
import com.sun.source.util.Trees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.comp.Attr;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.util.Context;
import io.vertx.codegen.type.TypeInfo;
import io.vertx.codegen.type.TypeUse;
import io.vertx.codegen.type.TypeMirrorFactory;
import io.vertx.codetrans.statement.StatementModel;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;
import javax.lang.model.util.Types;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author Julien Viet
*/
public class CodeTranslator {
private final Trees trees;
private final DeclaredType SystemType;
private final DeclaredType ThrowableType;
private final Attr attr;
private final TypeMirrorFactory factory;
private final Types typeUtils;
public CodeTranslator(ProcessingEnvironment processingEnv) {
this.trees = Trees.instance(processingEnv);
this.SystemType = (DeclaredType) processingEnv.getElementUtils().getTypeElement(System.class.getName()).asType();
this.ThrowableType = (DeclaredType) processingEnv.getElementUtils().getTypeElement(Throwable.class.getName()).asType();
Context context = ((JavacProcessingEnvironment)processingEnv).getContext();
this.attr = Attr.instance(context);
this.typeUtils = processingEnv.getTypeUtils();
this.factory = new TypeMirrorFactory(processingEnv.getElementUtils(), processingEnv.getTypeUtils()) {
@Override
public TypeInfo create(TypeUse use, TypeMirror type) {
if (type.getKind() == TypeKind.WILDCARD) {
WildcardType wildcardType = (WildcardType) type;
if (wildcardType.getExtendsBound() != null) {
return super.create(wildcardType.getExtendsBound());
} else if (wildcardType.getSuperBound() != null) {
return super.create(use, wildcardType.getSuperBound());
}
}
return super.create(use, type);
}
};
}
public String translate(ExecutableElement methodElt, Lang lang) {
return translate(methodElt, false, lang, RenderMode.SNIPPET);
}
public String translate(ExecutableElement methodElt, boolean isVerticle, Lang lang) {
return translate(methodElt, isVerticle, lang, RenderMode.SNIPPET);
}
public String translate(ExecutableElement methodElt, boolean isVerticle, Lang lang, RenderMode renderMode) {
TypeElement typeElt = (TypeElement) methodElt.getEnclosingElement();
attributeClass(typeElt);
ModelBuilder builder = new ModelBuilder(trees, typeElt, SystemType, ThrowableType, factory, typeUtils, lang);
VisitContext visitContext = new VisitContext(lang.codeBuilder());
MethodModel main = builder.build(methodElt, visitContext);
Map methods = new HashMap<>();
Map fields = new HashMap<>();
Map pending = visitContext.getReferencedMethods().stream().collect(Collectors.toMap(k -> k, k -> true));
visitContext.getReferencedFields().forEach(field -> {
pending.put(field, false);
});
while (pending.size() > 0) {
Iterator> it = pending.entrySet().iterator();
Map.Entry entry = it.next();
String name = entry.getKey();
it.remove();
VisitContext other = null;
if (entry.getValue()) {
for (Element enclosed : typeElt.getEnclosedElements()) {
if (enclosed instanceof ExecutableElement && enclosed.getSimpleName().toString().equals(name)) {
other = new VisitContext(visitContext.builder);
MethodModel method = builder.build((ExecutableElement) enclosed, other);
methods.put(name, method);
}
}
} else {
for (Element enclosed : typeElt.getEnclosedElements()) {
if (enclosed instanceof VariableElement && enclosed.getSimpleName().toString().equals(name)) {
other = new VisitContext(visitContext.builder);
StatementModel statement = builder.build((VariableElement) enclosed, other);
fields.put(name, statement);
}
}
}
if (other == null) {
throw new UnsupportedOperationException("Field / method " + name + " could not be resolved ");
}
for (String method : other.getReferencedMethods()) {
if (fields.containsKey(method)) {
throw new UnsupportedOperationException("Duplicate field / method " + method);
}
if (!methods.containsKey(method)) {
pending.put(method, true);
}
}
for (String field : other.getReferencedFields()) {
if (methods.containsKey(field)) {
throw new UnsupportedOperationException("Duplicate field / method " + field);
}
if (!fields.containsKey(field)) {
pending.put(field, false);
}
}
}
RunnableCompilationUnit unit = new RunnableCompilationUnit(isVerticle, main, methods, fields);
return visitContext.builder.render(unit, renderMode);
}
private void attributeClass(Element classElement) {
assert classElement.getKind() == ElementKind.CLASS;
JCTree.JCClassDecl ct = (JCTree.JCClassDecl) trees.getTree(classElement);
if (ct.sym != null) {
if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) {
attr.attribClass(ct.pos(), ct.sym);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy