package org.checkerframework.framework.type; /** Created by jburke on 11/20/14. */ import com.sun.source.tree.LambdaExpressionTree; import com.sun.source.tree.MethodTree; import com.sun.source.tree.Tree; import com.sun.source.tree.Tree.Kind; import com.sun.source.tree.VariableTree; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedDeclaredType; import org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType; import org.checkerframework.javacutil.Pair; import org.checkerframework.javacutil.TreeUtils; /** * Converts a field or methods tree into an AnnotatedTypeMirror * * @see org.checkerframework.framework.type.TypeFromTree */ class TypeFromMemberVisitor extends TypeFromTreeVisitor { @Override public AnnotatedTypeMirror visitVariable(VariableTree node, AnnotatedTypeFactory f) { // Create the ATM and add non-primary annotations // (node.getType() does not include primary annotations, those are in // node.getModifier() AnnotatedTypeMirror result = TypeFromTree.fromTypeTree(f, node.getType()); // Add primary annotations Element elt = TreeUtils.elementFromDeclaration(node); ElementAnnotationApplier.apply(result, elt, f); inferLambdaParamAnnotations(f, result, elt); return result; /* An alternative I played around with. It unfortunately * ignores stub files, which is not good. com.sun.tools.javac.code.Type undType = ((JCTree)node).type; AnnotatedTypeMirror result; if (undType != null) { result = f.toAnnotatedType(undType); } else { // node.getType() ignores the top-level modifiers, which are // in node.getModifiers() result = f.fromTypeTree(node.getType()); // We still need to remove all annotations. // result.clearAnnotations(); } // TODO: Additionally decoding should NOT be necessary. // However, the underlying javac Type doesn't contain // type argument annotations. Element elt = TreeUtils.elementFromDeclaration(node); ElementAnnotationUtils.apply(result, elt, f); return result;*/ } @Override public AnnotatedTypeMirror visitMethod(MethodTree node, AnnotatedTypeFactory f) { ExecutableElement elt = TreeUtils.elementFromDeclaration(node); AnnotatedExecutableType result = (AnnotatedExecutableType) f.toAnnotatedType(elt.asType(), false); result.setElement(elt); ElementAnnotationApplier.apply(result, elt, f); return result; } private static void inferLambdaParamAnnotations( AnnotatedTypeFactory f, AnnotatedTypeMirror result, Element paramElement) { if (f.declarationFromElement(paramElement) == null || f.getPath(f.declarationFromElement(paramElement)) == null || f.getPath(f.declarationFromElement(paramElement)).getParentPath() == null) { return; } Tree declaredInTree = f.getPath(f.declarationFromElement(paramElement)).getParentPath().getLeaf(); if (declaredInTree.getKind() == Kind.LAMBDA_EXPRESSION) { LambdaExpressionTree lambdaDecl = (LambdaExpressionTree) declaredInTree; int index = lambdaDecl.getParameters().indexOf(f.declarationFromElement(paramElement)); Pair<AnnotatedDeclaredType, AnnotatedExecutableType> res = f.getFnInterfaceFromTree(lambdaDecl); AnnotatedExecutableType fnMethod = res.second; AnnotatedTypeMirror declaredParam = fnMethod.getParameterTypes().get(index); // TODO: Should we infer nested types (e.g. List<@x String>) result.addMissingAnnotations(declaredParam.getAnnotations()); } } }