Search in sources :

Example 61 with BugInCF

use of org.checkerframework.javacutil.BugInCF in project checker-framework by typetools.

the class WholeProgramInferenceJavaParserStorage method createWrappersForClass.

/**
 * The first two arugments are a javac tree and a JavaParser node representing the same class.
 * This method creates wrappers around all the classes, fields, and methods in that class, and
 * stores those wrappers in {@code sourceAnnos}.
 *
 * @param javacClass javac tree for class
 * @param javaParserClass JavaParser node corresponding to the same class as {@code javacClass}
 * @param sourceAnnos compilation unit wrapper to add new wrappers to
 */
private void createWrappersForClass(ClassTree javacClass, TypeDeclaration<?> javaParserClass, CompilationUnitAnnos sourceAnnos) {
    JointJavacJavaParserVisitor visitor = new DefaultJointVisitor() {

        @Override
        public void processClass(ClassTree javacTree, ClassOrInterfaceDeclaration javaParserNode) {
            addClass(javacTree);
        }

        @Override
        public void processClass(ClassTree javacTree, EnumDeclaration javaParserNode) {
            addClass(javacTree);
        }

        @Override
        public void processClass(ClassTree javacTree, RecordDeclaration javaParserNode) {
            addClass(javacTree);
        }

        @Override
        public void processNewClass(NewClassTree javacTree, ObjectCreationExpr javaParserNode) {
            if (javacTree.getClassBody() != null) {
                addClass(javacTree.getClassBody());
            }
        }

        /**
         * Creates a wrapper around the class for {@code tree} and stores it in {@code
         * sourceAnnos}.
         *
         * @param tree tree to add
         */
        private void addClass(ClassTree tree) {
            TypeElement classElt = TreeUtils.elementFromDeclaration(tree);
            String className = ElementUtils.getBinaryName(classElt);
            ClassOrInterfaceAnnos typeWrapper = new ClassOrInterfaceAnnos();
            if (!classToAnnos.containsKey(className)) {
                classToAnnos.put(className, typeWrapper);
            }
            sourceAnnos.types.add(typeWrapper);
        }

        @Override
        public void processMethod(MethodTree javacTree, MethodDeclaration javaParserNode) {
            addCallableDeclaration(javacTree, javaParserNode);
        }

        @Override
        public void processMethod(MethodTree javacTree, ConstructorDeclaration javaParserNode) {
            addCallableDeclaration(javacTree, javaParserNode);
        }

        /**
         * Creates a wrapper around {@code javacTree} with the corresponding declaration {@code
         * javaParserNode} and stores it in {@code sourceAnnos}.
         *
         * @param javacTree javac tree for declaration to add
         * @param javaParserNode JavaParser node for the same class as {@code javacTree}
         */
        private void addCallableDeclaration(MethodTree javacTree, CallableDeclaration<?> javaParserNode) {
            ExecutableElement elt = TreeUtils.elementFromDeclaration(javacTree);
            String className = ElementUtils.getEnclosingClassName(elt);
            ClassOrInterfaceAnnos enclosingClass = classToAnnos.get(className);
            String executableSignature = JVMNames.getJVMMethodSignature(javacTree);
            if (!enclosingClass.callableDeclarations.containsKey(executableSignature)) {
                enclosingClass.callableDeclarations.put(executableSignature, new CallableDeclarationAnnos(javaParserNode));
            }
        }

        @Override
        public void processVariable(VariableTree javacTree, EnumConstantDeclaration javaParserNode) {
            VariableElement elt = TreeUtils.elementFromDeclaration(javacTree);
            if (!elt.getKind().isField()) {
                throw new BugInCF(elt + " is not a field but a " + elt.getKind());
            }
            String enclosingClassName = ElementUtils.getEnclosingClassName(elt);
            ClassOrInterfaceAnnos enclosingClass = classToAnnos.get(enclosingClassName);
            String fieldName = javacTree.getName().toString();
            enclosingClass.enumConstants.add(fieldName);
            // Ensure that if an enum constant defines a class, that class gets registered properly.
            // See e.g. https://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.1 for
            // the specification of an enum constant, which does permit it to define an anonymous
            // class.
            NewClassTree constructor = (NewClassTree) javacTree.getInitializer();
            if (constructor.getClassBody() != null) {
                addClass(constructor.getClassBody());
            }
        }

        @Override
        public void processVariable(VariableTree javacTree, VariableDeclarator javaParserNode) {
            // below call to TreeUtils.elementFromDeclaration causes a crash.
            if (TreeUtils.elementFromTree(javacTree) == null) {
                return;
            }
            VariableElement elt = TreeUtils.elementFromDeclaration(javacTree);
            if (!elt.getKind().isField()) {
                return;
            }
            String enclosingClassName = ElementUtils.getEnclosingClassName(elt);
            ClassOrInterfaceAnnos enclosingClass = classToAnnos.get(enclosingClassName);
            String fieldName = javacTree.getName().toString();
            if (!enclosingClass.fields.containsKey(fieldName)) {
                enclosingClass.fields.put(fieldName, new FieldAnnos(javaParserNode));
            }
        }
    };
    visitor.visitClass(javacClass, javaParserClass);
}
Also used : ObjectCreationExpr(com.github.javaparser.ast.expr.ObjectCreationExpr) ClassOrInterfaceDeclaration(com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) MethodTree(com.sun.source.tree.MethodTree) TypeElement(javax.lang.model.element.TypeElement) MethodDeclaration(com.github.javaparser.ast.body.MethodDeclaration) ExecutableElement(javax.lang.model.element.ExecutableElement) NewClassTree(com.sun.source.tree.NewClassTree) ClassTree(com.sun.source.tree.ClassTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) VariableElement(javax.lang.model.element.VariableElement) BugInCF(org.checkerframework.javacutil.BugInCF) EnumDeclaration(com.github.javaparser.ast.body.EnumDeclaration) VariableDeclarator(com.github.javaparser.ast.body.VariableDeclarator) RecordDeclaration(com.github.javaparser.ast.body.RecordDeclaration) EnumConstantDeclaration(com.github.javaparser.ast.body.EnumConstantDeclaration) JointJavacJavaParserVisitor(org.checkerframework.framework.ajava.JointJavacJavaParserVisitor) ConstructorDeclaration(com.github.javaparser.ast.body.ConstructorDeclaration) CallableDeclaration(com.github.javaparser.ast.body.CallableDeclaration) DefaultJointVisitor(org.checkerframework.framework.ajava.DefaultJointVisitor)

Example 62 with BugInCF

use of org.checkerframework.javacutil.BugInCF in project checker-framework by typetools.

the class JointJavacJavaParserVisitor method visitWildcard.

@Override
public Void visitWildcard(WildcardTree javacTree, Node javaParserNode) {
    WildcardType node = castNode(WildcardType.class, javaParserNode, javacTree);
    processWildcard(javacTree, node);
    // In javac, whether the bound is an extends or super clause depends on the kind of the tree.
    assert (javacTree.getKind() == Tree.Kind.EXTENDS_WILDCARD) == node.getExtendedType().isPresent();
    assert (javacTree.getKind() == Tree.Kind.SUPER_WILDCARD) == node.getSuperType().isPresent();
    switch(javacTree.getKind()) {
        case UNBOUNDED_WILDCARD:
            break;
        case EXTENDS_WILDCARD:
            javacTree.getBound().accept(this, node.getExtendedType().get());
            break;
        case SUPER_WILDCARD:
            javacTree.getBound().accept(this, node.getSuperType().get());
            break;
        default:
            throw new BugInCF("Unexpected wildcard kind: %s", javacTree);
    }
    return null;
}
Also used : WildcardType(com.github.javaparser.ast.type.WildcardType) BugInCF(org.checkerframework.javacutil.BugInCF)

Example 63 with BugInCF

use of org.checkerframework.javacutil.BugInCF in project checker-framework by typetools.

the class AnnotationFileParser method putMerge.

/**
 * Just like Map.put, but modifies an existing annotated type for the given key in {@code m}. If
 * {@code m} already has an annotated type for {@code key}, each annotation in {@code newType}
 * will replace annotations from the same hierarchy at the same location in the existing annotated
 * type. Annotations in other hierarchies will be preserved.
 *
 * @param m the map to put the new type into
 * @param key the key for the map
 * @param newType the new type for the key
 */
private void putMerge(Map<Element, AnnotatedTypeMirror> m, Element key, AnnotatedTypeMirror newType) {
    if (key == null) {
        throw new BugInCF("AnnotationFileParser: key is null");
    }
    if (m.containsKey(key)) {
        AnnotatedTypeMirror existingType = m.get(key);
        // This works because the JDK is always parsed last, on demand, after all other stub files.
        if (fileType != AnnotationFileType.JDK_STUB) {
            atypeFactory.replaceAnnotations(newType, existingType);
        }
        m.put(key, existingType);
    } else {
        m.put(key, newType);
    }
}
Also used : BugInCF(org.checkerframework.javacutil.BugInCF) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 64 with BugInCF

use of org.checkerframework.javacutil.BugInCF in project checker-framework by typetools.

the class AnnotationFileParser method getAnnotation.

/**
 * Convert {@code annotation} into an AnnotationMirror. Returns null if the annotation isn't
 * supported by the checker or if some error occurred while converting it.
 *
 * @param annotation syntax tree for an annotation
 * @param allAnnotations map from simple name to annotation definition; side-effected by this
 *     method
 * @return the AnnotationMirror for the annotation, or null if it cannot be built
 */
@Nullable
private AnnotationMirror getAnnotation(AnnotationExpr annotation, Map<String, TypeElement> allAnnotations) {
    // https://tinyurl.com/cfissue/3094
    @SuppressWarnings("signature") @FullyQualifiedName String annoNameFq = annotation.getNameAsString();
    TypeElement annoTypeElt = allAnnotations.get(annoNameFq);
    if (annoTypeElt == null) {
        // If the annotation was not imported, then #getImportedAnnotations did not add it to the
        // allAnnotations field. This code adds the annotation when it is encountered (i.e. here).
        // Note that this does not call AnnotationFileParser#getTypeElement to avoid a spurious
        // diagnostic if the annotation is actually unknown.
        annoTypeElt = elements.getTypeElement(annoNameFq);
        if (annoTypeElt == null) {
            // Not a supported annotation -> ignore
            return null;
        }
        putAllNew(allAnnotations, createNameToAnnotationMap(Collections.singletonList(annoTypeElt)));
    }
    // not anonymous, so name is not empty
    @SuppressWarnings("signature") @CanonicalName String annoName = annoTypeElt.getQualifiedName().toString();
    if (annotation instanceof MarkerAnnotationExpr) {
        return AnnotationBuilder.fromName(elements, annoName);
    } else if (annotation instanceof NormalAnnotationExpr) {
        NormalAnnotationExpr nrmanno = (NormalAnnotationExpr) annotation;
        AnnotationBuilder builder = new AnnotationBuilder(processingEnv, annoName);
        List<MemberValuePair> pairs = nrmanno.getPairs();
        if (pairs != null) {
            for (MemberValuePair mvp : pairs) {
                String member = mvp.getNameAsString();
                Expression exp = mvp.getValue();
                try {
                    builderAddElement(builder, member, exp);
                } catch (AnnotationFileParserException e) {
                    warn(exp, "For annotation %s, could not add  %s=%s  because %s", annotation, member, exp, e.getMessage());
                    return null;
                }
            }
        }
        return builder.build();
    } else if (annotation instanceof SingleMemberAnnotationExpr) {
        SingleMemberAnnotationExpr sglanno = (SingleMemberAnnotationExpr) annotation;
        AnnotationBuilder builder = new AnnotationBuilder(processingEnv, annoName);
        Expression valExpr = sglanno.getMemberValue();
        try {
            builderAddElement(builder, "value", valExpr);
        } catch (AnnotationFileParserException e) {
            warn(valExpr, "For annotation %s, could not add  value=%s  because %s", annotation, valExpr, e.getMessage());
            return null;
        }
        return builder.build();
    } else {
        throw new BugInCF("AnnotationFileParser: unknown annotation type: " + annotation);
    }
}
Also used : TypeElement(javax.lang.model.element.TypeElement) FullyQualifiedName(org.checkerframework.checker.signature.qual.FullyQualifiedName) MarkerAnnotationExpr(com.github.javaparser.ast.expr.MarkerAnnotationExpr) BugInCF(org.checkerframework.javacutil.BugInCF) SingleMemberAnnotationExpr(com.github.javaparser.ast.expr.SingleMemberAnnotationExpr) MemberValuePair(com.github.javaparser.ast.expr.MemberValuePair) AnnotationBuilder(org.checkerframework.javacutil.AnnotationBuilder) Expression(com.github.javaparser.ast.expr.Expression) ArrayList(java.util.ArrayList) NodeList(com.github.javaparser.ast.NodeList) List(java.util.List) NormalAnnotationExpr(com.github.javaparser.ast.expr.NormalAnnotationExpr) CanonicalName(org.checkerframework.checker.signature.qual.CanonicalName) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 65 with BugInCF

use of org.checkerframework.javacutil.BugInCF in project checker-framework by typetools.

the class AnnotationFileParser method processTypeDecl.

/**
 * Process a type declaration: copy its annotations to {@code #annotationFileAnnos}.
 *
 * <p>This method stores the declaration's type parameters in {@link #typeParameters}. When
 * processing an ajava file, where traversal is handled externaly by a {@link
 * org.checkerframework.framework.ajava.JointJavacJavaParserVisitor}, these type variables must be
 * removed after processing the type's members. Otherwise, this method removes them.
 *
 * @param typeDecl the type declaration to process
 * @param outertypeName the name of the containing class, when processing a nested class;
 *     otherwise null
 * @param classTree the tree corresponding to typeDecl if processing an ajava file, null otherwise
 * @return a list of types variables for {@code typeDecl}. Only non-null if processing an ajava
 *     file, in which case the contents should be removed from {@link #typeParameters} after
 *     processing the type declaration's members
 */
private List<AnnotatedTypeVariable> processTypeDecl(TypeDeclaration<?> typeDecl, String outertypeName, @Nullable ClassTree classTree) {
    assert typeBeingParsed != null;
    if (skipNode(typeDecl)) {
        return null;
    }
    String innerName;
    @FullyQualifiedName String fqTypeName;
    TypeElement typeElt;
    if (classTree != null) {
        typeElt = TreeUtils.elementFromDeclaration(classTree);
        innerName = typeElt.getQualifiedName().toString();
        typeBeingParsed = new FqName(typeBeingParsed.packageName, innerName);
        fqTypeName = typeBeingParsed.toString();
    } else {
        String packagePrefix = outertypeName == null ? "" : outertypeName + ".";
        innerName = packagePrefix + typeDecl.getNameAsString();
        typeBeingParsed = new FqName(typeBeingParsed.packageName, innerName);
        fqTypeName = typeBeingParsed.toString();
        typeElt = elements.getTypeElement(fqTypeName);
    }
    if (!isAnnotatedForThisChecker(typeDecl.getAnnotations())) {
        return null;
    }
    if (typeElt == null) {
        if (debugAnnotationFileParser || (!warnIfNotFoundIgnoresClasses && !hasNoAnnotationFileParserWarning(typeDecl.getAnnotations()) && !hasNoAnnotationFileParserWarning(packageAnnos))) {
            if (elements.getAllTypeElements(fqTypeName).isEmpty()) {
                stubWarnNotFound(typeDecl, "Type not found: " + fqTypeName);
            } else {
                stubWarnNotFound(typeDecl, "Type not found uniquely: " + fqTypeName + " : " + elements.getAllTypeElements(fqTypeName));
            }
        }
        return null;
    }
    List<AnnotatedTypeVariable> typeDeclTypeParameters = null;
    if (typeElt.getKind() == ElementKind.ENUM) {
        if (!(typeDecl instanceof EnumDeclaration)) {
            warn(typeDecl, innerName + " is an enum, but stub file declared it as " + typeDecl.toString().split("\\R", 2)[0] + "...");
            return null;
        }
        typeDeclTypeParameters = processEnum((EnumDeclaration) typeDecl, typeElt);
        typeParameters.addAll(typeDeclTypeParameters);
    } else if (typeElt.getKind() == ElementKind.ANNOTATION_TYPE) {
        if (!(typeDecl instanceof AnnotationDeclaration)) {
            warn(typeDecl, innerName + " is an annotation, but stub file declared it as " + typeDecl.toString().split("\\R", 2)[0] + "...");
            return null;
        }
        stubWarnNotFound(typeDecl, "Skipping annotation type: " + fqTypeName);
    } else if (typeDecl instanceof ClassOrInterfaceDeclaration) {
        if (!(typeDecl instanceof ClassOrInterfaceDeclaration)) {
            warn(typeDecl, innerName + " is a class or interface, but stub file declared it as " + typeDecl.toString().split("\\R", 2)[0] + "...");
            return null;
        }
        typeDeclTypeParameters = processType(typeDecl, typeElt);
        typeParameters.addAll(typeDeclTypeParameters);
    } else if (typeDecl instanceof RecordDeclaration) {
        typeDeclTypeParameters = processType(typeDecl, typeElt);
        typeParameters.addAll(typeDeclTypeParameters);
    }
    // of this method.
    if (fileType == AnnotationFileType.AJAVA) {
        return typeDeclTypeParameters;
    }
    if (typeDecl instanceof RecordDeclaration) {
        NodeList<Parameter> recordMembers = ((RecordDeclaration) typeDecl).getParameters();
        LinkedHashMap<String, RecordComponentStub> byName = new LinkedHashMap<>();
        for (Parameter recordMember : recordMembers) {
            RecordComponentStub stub = processRecordField(recordMember, findFieldElement(typeElt, recordMember.getNameAsString(), recordMember));
            byName.put(recordMember.getNameAsString(), stub);
        }
        annotationFileAnnos.records.put(typeDecl.getFullyQualifiedName().get(), new RecordStub(byName));
    }
    Pair<Map<Element, BodyDeclaration<?>>, Map<Element, List<BodyDeclaration<?>>>> members = getMembers(typeDecl, typeElt, typeDecl);
    for (Map.Entry<Element, BodyDeclaration<?>> entry : members.first.entrySet()) {
        final Element elt = entry.getKey();
        final BodyDeclaration<?> decl = entry.getValue();
        switch(elt.getKind()) {
            case FIELD:
                processField((FieldDeclaration) decl, (VariableElement) elt);
                break;
            case ENUM_CONSTANT:
                // the TRACKER enum constant annotated with DefaultType:
                if (decl instanceof FieldDeclaration) {
                    processField((FieldDeclaration) decl, (VariableElement) elt);
                } else if (decl instanceof EnumConstantDeclaration) {
                    processEnumConstant((EnumConstantDeclaration) decl, (VariableElement) elt);
                } else {
                    throw new BugInCF("Unexpected decl type " + decl.getClass() + " for ENUM_CONSTANT kind, original: " + decl);
                }
                break;
            case CONSTRUCTOR:
            case METHOD:
                processCallableDeclaration((CallableDeclaration<?>) decl, (ExecutableElement) elt);
                break;
            case CLASS:
            case INTERFACE:
                // Not processing an ajava file, so ignore the return value.
                processTypeDecl((ClassOrInterfaceDeclaration) decl, innerName, null);
                break;
            case ENUM:
                // Not processing an ajava file, so ignore the return value.
                processTypeDecl((EnumDeclaration) decl, innerName, null);
                break;
            default:
                /* do nothing */
                stubWarnNotFound(decl, "AnnotationFileParser ignoring: " + elt);
                break;
        }
    }
    for (Map.Entry<Element, List<BodyDeclaration<?>>> entry : members.second.entrySet()) {
        ExecutableElement fakeOverridden = (ExecutableElement) entry.getKey();
        List<BodyDeclaration<?>> fakeOverrideDecls = entry.getValue();
        for (BodyDeclaration<?> bodyDecl : fakeOverrideDecls) {
            processFakeOverride(fakeOverridden, (CallableDeclaration<?>) bodyDecl, typeElt);
        }
    }
    if (typeDeclTypeParameters != null) {
        typeParameters.removeAll(typeDeclTypeParameters);
    }
    return null;
}
Also used : ClassOrInterfaceDeclaration(com.github.javaparser.ast.body.ClassOrInterfaceDeclaration) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) PackageElement(javax.lang.model.element.PackageElement) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) FullyQualifiedName(org.checkerframework.checker.signature.qual.FullyQualifiedName) VariableElement(javax.lang.model.element.VariableElement) FieldDeclaration(com.github.javaparser.ast.body.FieldDeclaration) LinkedHashMap(java.util.LinkedHashMap) EnumConstantDeclaration(com.github.javaparser.ast.body.EnumConstantDeclaration) ArrayList(java.util.ArrayList) NodeList(com.github.javaparser.ast.NodeList) List(java.util.List) TypeElement(javax.lang.model.element.TypeElement) BugInCF(org.checkerframework.javacutil.BugInCF) EnumDeclaration(com.github.javaparser.ast.body.EnumDeclaration) RecordDeclaration(com.github.javaparser.ast.body.RecordDeclaration) AnnotationDeclaration(com.github.javaparser.ast.body.AnnotationDeclaration) ReceiverParameter(com.github.javaparser.ast.body.ReceiverParameter) Parameter(com.github.javaparser.ast.body.Parameter) TypeParameter(com.github.javaparser.ast.type.TypeParameter) BodyDeclaration(com.github.javaparser.ast.body.BodyDeclaration) AnnotatedTypeVariable(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedTypeVariable) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap)

Aggregations

BugInCF (org.checkerframework.javacutil.BugInCF)127 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)29 ArrayList (java.util.ArrayList)28 AnnotationMirror (javax.lang.model.element.AnnotationMirror)26 TypeElement (javax.lang.model.element.TypeElement)26 TypeMirror (javax.lang.model.type.TypeMirror)25 ExecutableElement (javax.lang.model.element.ExecutableElement)24 MethodTree (com.sun.source.tree.MethodTree)20 ExpressionTree (com.sun.source.tree.ExpressionTree)18 VariableTree (com.sun.source.tree.VariableTree)18 Element (javax.lang.model.element.Element)18 ClassTree (com.sun.source.tree.ClassTree)17 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)17 NewClassTree (com.sun.source.tree.NewClassTree)17 LambdaExpressionTree (com.sun.source.tree.LambdaExpressionTree)16 IOException (java.io.IOException)16 Tree (com.sun.source.tree.Tree)15 Map (java.util.Map)15 List (java.util.List)14 VariableElement (javax.lang.model.element.VariableElement)14