Search in sources :

Example 11 with Pair

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

the class AnnotationFileParser method processFakeOverride.

/**
 * Process a fake override: copy its annotations to the fake overrides part of {@code
 * #annotationFileAnnos}.
 *
 * @param element a real element
 * @param decl a fake override of the element
 * @param fakeLocation where the fake override was defined
 */
private void processFakeOverride(ExecutableElement element, CallableDeclaration<?> decl, TypeElement fakeLocation) {
    // This is a fresh type, which this code may side-effect.
    AnnotatedExecutableType methodType = atypeFactory.getAnnotatedType(element);
    // Here is a hacky solution that does not use the visitor.  It just handles the return type.
    // TODO: Walk the type and the declaration, copying annotations from the declaration to the
    // element.  I think PR #3977 has a visitor that does that, which I should use after it is
    // merged.
    // The annotations on the method.  These include type annotations on the return type.
    NodeList<AnnotationExpr> annotations = decl.getAnnotations();
    annotate(methodType.getReturnType(), ((MethodDeclaration) decl).getType(), annotations, decl);
    List<Pair<TypeMirror, AnnotatedTypeMirror>> l = annotationFileAnnos.fakeOverrides.computeIfAbsent(element, __ -> new ArrayList<>());
    l.add(Pair.of(fakeLocation.asType(), methodType));
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotationExpr(com.github.javaparser.ast.expr.AnnotationExpr) MarkerAnnotationExpr(com.github.javaparser.ast.expr.MarkerAnnotationExpr) SingleMemberAnnotationExpr(com.github.javaparser.ast.expr.SingleMemberAnnotationExpr) NormalAnnotationExpr(com.github.javaparser.ast.expr.NormalAnnotationExpr) Pair(org.checkerframework.javacutil.Pair) MemberValuePair(com.github.javaparser.ast.expr.MemberValuePair)

Example 12 with Pair

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

the class AnnotationFileElementTypes method getFakeOverride.

/**
 * Returns the method type of the most specific fake override for the given element, when used as
 * a member of the given type.
 *
 * @param elt element for which annotations are returned
 * @param receiverType the type of the class that contains member (or a subtype of it)
 * @return the most specific AnnotatedTypeMirror for {@code elt} that is a fake override, or null
 *     if there are no fake overrides
 */
@Nullable
public AnnotatedExecutableType getFakeOverride(Element elt, AnnotatedTypeMirror receiverType) {
    if (parsing) {
        throw new BugInCF("parsing while calling getFakeOverride");
    }
    if (elt.getKind() != ElementKind.METHOD) {
        return null;
    }
    ExecutableElement method = (ExecutableElement) elt;
    // This is a list of pairs of (where defined, method type) for fake overrides.  The second
    // element of each pair is currently always an AnnotatedExecutableType.
    List<Pair<TypeMirror, AnnotatedTypeMirror>> candidates = annotationFileAnnos.fakeOverrides.get(method);
    if (candidates == null || candidates.isEmpty()) {
        return null;
    }
    TypeMirror receiverTypeMirror = receiverType.getUnderlyingType();
    // A list of fake receiver types.
    List<TypeMirror> applicableClasses = new ArrayList<>();
    List<TypeMirror> applicableInterfaces = new ArrayList<>();
    for (Pair<TypeMirror, AnnotatedTypeMirror> candidatePair : candidates) {
        TypeMirror fakeLocation = candidatePair.first;
        AnnotatedExecutableType candidate = (AnnotatedExecutableType) candidatePair.second;
        if (factory.types.isSameType(receiverTypeMirror, fakeLocation)) {
            return candidate;
        } else if (factory.types.isSubtype(receiverTypeMirror, fakeLocation)) {
            TypeElement fakeElement = TypesUtils.getTypeElement(fakeLocation);
            switch(fakeElement.getKind()) {
                case CLASS:
                case ENUM:
                    applicableClasses.add(fakeLocation);
                    break;
                case INTERFACE:
                case ANNOTATION_TYPE:
                    applicableInterfaces.add(fakeLocation);
                    break;
                default:
                    throw new BugInCF("What type? %s %s %s", fakeElement.getKind(), fakeElement.getClass(), fakeElement);
            }
        }
    }
    if (applicableClasses.isEmpty() && applicableInterfaces.isEmpty()) {
        return null;
    }
    TypeMirror fakeReceiverType = TypesUtils.mostSpecific(!applicableClasses.isEmpty() ? applicableClasses : applicableInterfaces, factory.getProcessingEnv());
    if (fakeReceiverType == null) {
        StringJoiner message = new StringJoiner(System.lineSeparator());
        message.add(String.format("No most specific fake override found for %s with receiver %s." + " These fake overrides are applicable:", elt, receiverTypeMirror));
        for (TypeMirror candidate : applicableClasses) {
            message.add("  class candidate: " + candidate);
        }
        for (TypeMirror candidate : applicableInterfaces) {
            message.add("  interface candidate: " + candidate);
        }
        throw new BugInCF(message.toString());
    }
    for (Pair<TypeMirror, AnnotatedTypeMirror> candidatePair : candidates) {
        TypeMirror candidateReceiverType = candidatePair.first;
        if (factory.types.isSameType(fakeReceiverType, candidateReceiverType)) {
            return (AnnotatedExecutableType) candidatePair.second;
        }
    }
    throw new BugInCF("No match for %s in %s %s %s", fakeReceiverType, candidates, applicableClasses, applicableInterfaces);
}
Also used : AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) ArrayList(java.util.ArrayList) BugInCF(org.checkerframework.javacutil.BugInCF) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) StringJoiner(java.util.StringJoiner) Pair(org.checkerframework.javacutil.Pair) Nullable(org.checkerframework.checker.nullness.qual.Nullable)

Example 13 with Pair

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

the class TADescriptions method runDriver.

protected void runDriver(Object object) throws Exception {
    int passed = 0, failed = 0;
    Class<?> clazz = object.getClass();
    out.println("Tests for " + clazz.getName());
    // Find methods
    for (Method method : clazz.getMethods()) {
        List<Pair<String, TypeAnnotation.Position>> expected = expectedOf(method);
        if (expected == null) {
            continue;
        }
        if (method.getReturnType() != String.class) {
            throw new IllegalArgumentException("Test method needs to return a string: " + method);
        }
        String testClass = PersistUtil.testClassOf(method);
        try {
            String compact = (String) method.invoke(object);
            String fullFile = PersistUtil.wrap(compact);
            ClassFile cf = PersistUtil.compileAndReturn(fullFile, testClass);
            boolean ignoreConstructors = !clazz.getName().equals("Constructors");
            List<TypeAnnotation> actual = ReferenceInfoUtil.extendedAnnotationsOf(cf, ignoreConstructors);
            String diagnostic = String.join("; ", "Tests for " + clazz.getName(), "compact=" + compact, "fullFile=" + fullFile, "testClass=" + testClass);
            ReferenceInfoUtil.compare(expected, actual, cf, diagnostic);
            out.println("PASSED:  " + method.getName());
            ++passed;
        } catch (Throwable e) {
            out.println("FAILED:  " + method.getName());
            out.println("    " + e);
            ++failed;
        }
    }
    out.println();
    int total = passed + failed;
    out.println(total + " total tests: " + passed + " PASSED, " + failed + " FAILED");
    out.flush();
    if (failed != 0) {
        throw new RuntimeException(failed + " tests failed");
    }
}
Also used : TypeAnnotation(com.sun.tools.classfile.TypeAnnotation) ClassFile(com.sun.tools.classfile.ClassFile) Method(java.lang.reflect.Method) Pair(org.checkerframework.javacutil.Pair)

Example 14 with Pair

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

the class CFAbstractStore method isMonotonicUpdate.

/**
 * Return true if fieldAcc is an update of a monotonic qualifier to its target qualifier.
 * (e.g. @MonotonicNonNull to @NonNull). Always returns false if {@code sequentialSemantics} is
 * true.
 *
 * @return true if fieldAcc is an update of a monotonic qualifier to its target qualifier
 *     (e.g. @MonotonicNonNull to @NonNull)
 */
protected boolean isMonotonicUpdate(FieldAccess fieldAcc, V value) {
    if (analysis.atypeFactory.getSupportedMonotonicTypeQualifiers().isEmpty()) {
        return false;
    }
    boolean isMonotonic = false;
    // TODO: Update the javadoc of this method when the above to-do item is addressed.
    if (!sequentialSemantics) {
        // only compute if necessary
        AnnotatedTypeFactory atypeFactory = this.analysis.atypeFactory;
        List<Pair<AnnotationMirror, AnnotationMirror>> fieldAnnotations = atypeFactory.getAnnotationWithMetaAnnotation(fieldAcc.getField(), MonotonicQualifier.class);
        for (Pair<AnnotationMirror, AnnotationMirror> fieldAnnotation : fieldAnnotations) {
            AnnotationMirror monotonicAnnotation = fieldAnnotation.second;
            // permitted for use in the framework
            @SuppressWarnings("deprecation") Name annotation = AnnotationUtils.getElementValueClassName(monotonicAnnotation, "value", false);
            AnnotationMirror target = AnnotationBuilder.fromName(atypeFactory.getElementUtils(), annotation);
            // Make sure the 'target' annotation is present.
            if (AnnotationUtils.containsSame(value.getAnnotations(), target)) {
                isMonotonic = true;
                break;
            }
        }
    }
    return isMonotonic;
}
Also used : AnnotationMirror(javax.lang.model.element.AnnotationMirror) GenericAnnotatedTypeFactory(org.checkerframework.framework.type.GenericAnnotatedTypeFactory) AnnotatedTypeFactory(org.checkerframework.framework.type.AnnotatedTypeFactory) Pair(org.checkerframework.javacutil.Pair) Name(javax.lang.model.element.Name) ClassName(org.checkerframework.dataflow.expression.ClassName)

Example 15 with Pair

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

the class CFAbstractStore method updateForMethodCall.

/* --------------------------------------------------------- */
/* Handling of fields */
/* --------------------------------------------------------- */
/**
 * Remove any information that might not be valid any more after a method call, and add
 * information guaranteed by the method.
 *
 * <ol>
 *   <li>If the method is side-effect-free (as indicated by {@link
 *       org.checkerframework.dataflow.qual.SideEffectFree} or {@link
 *       org.checkerframework.dataflow.qual.Pure}), then no information needs to be removed.
 *   <li>Otherwise, all information about field accesses {@code a.f} needs to be removed, except
 *       if the method {@code n} cannot modify {@code a.f} (e.g., if {@code a} is a local variable
 *       or {@code this}, and {@code f} is final).
 *   <li>Furthermore, if the field has a monotonic annotation, then its information can also be
 *       kept.
 * </ol>
 *
 * Furthermore, if the method is deterministic, we store its result {@code val} in the store.
 */
public void updateForMethodCall(MethodInvocationNode n, AnnotatedTypeFactory atypeFactory, V val) {
    ExecutableElement method = n.getTarget().getMethod();
    // case 1: remove information if necessary
    if (!(analysis.checker.hasOption("assumeSideEffectFree") || analysis.checker.hasOption("assumePure") || isSideEffectFree(atypeFactory, method))) {
        boolean sideEffectsUnrefineAliases = ((GenericAnnotatedTypeFactory) atypeFactory).sideEffectsUnrefineAliases;
        // isUnmodifiableByOtherCode.  Example: @KeyFor("valueThatCanBeMutated").
        if (sideEffectsUnrefineAliases) {
            localVariableValues.entrySet().removeIf(e -> !e.getKey().isUnmodifiableByOtherCode());
        }
        // update this value
        if (sideEffectsUnrefineAliases) {
            thisValue = null;
        }
        // update field values
        if (sideEffectsUnrefineAliases) {
            fieldValues.entrySet().removeIf(e -> !e.getKey().isUnmodifiableByOtherCode());
        } else {
            Map<FieldAccess, V> newFieldValues = new HashMap<>(CollectionsPlume.mapCapacity(fieldValues));
            for (Map.Entry<FieldAccess, V> e : fieldValues.entrySet()) {
                FieldAccess fieldAccess = e.getKey();
                V otherVal = e.getValue();
                // case 3: the field has a monotonic annotation
                if (!((GenericAnnotatedTypeFactory<?, ?, ?, ?>) atypeFactory).getSupportedMonotonicTypeQualifiers().isEmpty()) {
                    List<Pair<AnnotationMirror, AnnotationMirror>> fieldAnnotations = atypeFactory.getAnnotationWithMetaAnnotation(fieldAccess.getField(), MonotonicQualifier.class);
                    V newOtherVal = null;
                    for (Pair<AnnotationMirror, AnnotationMirror> fieldAnnotation : fieldAnnotations) {
                        AnnotationMirror monotonicAnnotation = fieldAnnotation.second;
                        // permitted for use in the framework
                        @SuppressWarnings("deprecation") Name annotation = AnnotationUtils.getElementValueClassName(monotonicAnnotation, "value", false);
                        AnnotationMirror target = AnnotationBuilder.fromName(atypeFactory.getElementUtils(), annotation);
                        // Make sure the 'target' annotation is present.
                        if (AnnotationUtils.containsSame(otherVal.getAnnotations(), target)) {
                            newOtherVal = analysis.createSingleAnnotationValue(target, otherVal.getUnderlyingType()).mostSpecific(newOtherVal, null);
                        }
                    }
                    if (newOtherVal != null) {
                        // keep information for all hierarchies where we had a
                        // monotone annotation.
                        newFieldValues.put(fieldAccess, newOtherVal);
                        continue;
                    }
                }
                // case 2:
                if (!fieldAccess.isUnassignableByOtherCode()) {
                    // remove information completely
                    continue;
                }
                // keep information
                newFieldValues.put(fieldAccess, otherVal);
            }
            fieldValues = newFieldValues;
        }
        // update array values
        arrayValues.clear();
        // update method values
        methodValues.keySet().removeIf(e -> !e.isUnmodifiableByOtherCode());
    }
    // store information about method call if possible
    JavaExpression methodCall = JavaExpression.fromNode(n);
    replaceValue(methodCall, val);
}
Also used : GenericAnnotatedTypeFactory(org.checkerframework.framework.type.GenericAnnotatedTypeFactory) JavaExpression(org.checkerframework.dataflow.expression.JavaExpression) HashMap(java.util.HashMap) ExecutableElement(javax.lang.model.element.ExecutableElement) Name(javax.lang.model.element.Name) ClassName(org.checkerframework.dataflow.expression.ClassName) AnnotationMirror(javax.lang.model.element.AnnotationMirror) FieldAccess(org.checkerframework.dataflow.expression.FieldAccess) HashMap(java.util.HashMap) Map(java.util.Map) Pair(org.checkerframework.javacutil.Pair)

Aggregations

Pair (org.checkerframework.javacutil.Pair)31 AnnotationMirror (javax.lang.model.element.AnnotationMirror)12 ArrayList (java.util.ArrayList)11 LinkedHashSet (java.util.LinkedHashSet)8 TypeElement (javax.lang.model.element.TypeElement)7 TypeMirror (javax.lang.model.type.TypeMirror)7 MethodTree (com.sun.source.tree.MethodTree)6 Tree (com.sun.source.tree.Tree)6 HashMap (java.util.HashMap)6 ExecutableElement (javax.lang.model.element.ExecutableElement)6 VariableElement (javax.lang.model.element.VariableElement)6 ClassTree (com.sun.source.tree.ClassTree)5 VariableTree (com.sun.source.tree.VariableTree)5 ExpressionTree (com.sun.source.tree.ExpressionTree)4 NewClassTree (com.sun.source.tree.NewClassTree)4 LinkedHashMap (java.util.LinkedHashMap)4 Map (java.util.Map)4 Element (javax.lang.model.element.Element)4 Nullable (org.checkerframework.checker.nullness.qual.Nullable)4 Receiver (org.checkerframework.dataflow.analysis.FlowExpressions.Receiver)4