package io.vertx.codegen.type;
import com.sun.source.tree.AnnotatedTypeTree;
import com.sun.source.tree.AnnotationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ParameterizedTypeTree;
import com.sun.source.tree.Tree;
import com.sun.source.util.Trees;
import com.sun.tools.javac.tree.JCTree;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
class TreeTypeInternal implements TypeUse.TypeInternal {
public static final TypeUse.TypeInternalProvider PROVIDER = new TypeUse.TypeInternalProvider() {
public TypeUse.TypeInternal forParam(ProcessingEnvironment env, ExecutableElement methodElt, int paramIndex) {
Trees trees = Trees.instance(env);
if (trees == null) {
return null;
}
MethodTree tree = trees.getTree(methodElt);
if (tree == null) {
return null;
}
Tree type = tree.getParameters().get(paramIndex).getType();
return new TreeTypeInternal(type, isNullable(type));
}
public TypeUse.TypeInternal forReturn(ProcessingEnvironment env, ExecutableElement methodElt) {
Trees trees = Trees.instance(env);
if (trees == null) {
return null;
}
JCTree.JCMethodDecl tree = (JCTree.JCMethodDecl) trees.getTree(methodElt);
if (tree == null) {
return null;
}
JCTree type = tree.getReturnType();
boolean nullable = isNullable(type);
if (!nullable) {
JCTree.JCModifiers mods = tree.mods;
for (JCTree.JCAnnotation jca : mods.annotations) {
if (jca.type.toString().equals(TypeUse.NULLABLE)) {
nullable = true;
break;
}
}
}
return new TreeTypeInternal(type, nullable);
}
};
private final Tree type;
private final boolean nullable;
private TreeTypeInternal(Tree type, boolean nullable) {
this.type = type;
this.nullable = nullable;
}
public boolean isNullable() {
return nullable;
}
@Override
public String rawName() {
if (type instanceof ParameterizedTypeTree) {
ParameterizedTypeTree parameterizedType = (ParameterizedTypeTree) type;
return ((TypeElement)((JCTree.JCTypeApply) parameterizedType).type.asElement()).getQualifiedName().toString();
}
return null;
}
public TypeUse.TypeInternal getArgAt(int index) {
ParameterizedTypeTree parameterizedType = (ParameterizedTypeTree) type;
Tree type = parameterizedType.getTypeArguments().get(index);
return new TreeTypeInternal(type, isNullable(type));
}
private static boolean isNullable(Tree type) {
TypeMirror typeMirror = ((JCTree)type).type;
if (typeMirror instanceof com.sun.tools.javac.code.Type.AnnotatedType) {
com.sun.tools.javac.code.Type.AnnotatedType abc = (com.sun.tools.javac.code.Type.AnnotatedType) typeMirror;
for (AnnotationMirror mirror : abc.getAnnotationMirrors()) {
if (mirror.getAnnotationType().toString().equals(TypeUse.NULLABLE)) {
return true;
}
}
}
if (type instanceof JCTree.JCTypeApply) {
JCTree.JCExpression expr = ((JCTree.JCTypeApply) type).clazz;
if (expr instanceof AnnotatedTypeTree) {
AnnotatedTypeTree tree2 = (AnnotatedTypeTree) expr;
for (AnnotationTree mirror : tree2.getAnnotations()) {
if (mirror instanceof JCTree.JCAnnotation) {
JCTree.JCAnnotation jca = (JCTree.JCAnnotation) mirror;
if (jca.type.toString().equals(TypeUse.NULLABLE)) {
return true;
}
}
}
}
}
return false;
}
}