Search in sources :

Example 1 with WholeProgramInference

use of org.checkerframework.common.wholeprograminference.WholeProgramInference in project checker-framework by typetools.

the class InitializationVisitor method checkFieldsInitialized.

/**
 * Checks that all fields (all static fields if {@code staticFields} is true) are initialized in
 * the given store.
 *
 * @param node a {@link ClassTree} if {@code staticFields} is true; a {@link MethodTree} for a
 *     constructor if {@code staticFields} is false. This is where errors are reported, if they
 *     are not reported at the fields themselves
 * @param staticFields whether to check static fields or instance fields
 * @param store the store
 * @param receiverAnnotations the annotations on the receiver
 */
// TODO: the code for checking if fields are initialized should be re-written,
// as the current version contains quite a few ugly parts, is hard to understand,
// and it is likely that it does not take full advantage of the information
// about initialization we compute in
// GenericAnnotatedTypeFactory.initializationStaticStore and
// GenericAnnotatedTypeFactory.initializationStore.
protected void checkFieldsInitialized(Tree node, boolean staticFields, Store store, List<? extends AnnotationMirror> receiverAnnotations) {
    // If the store is null, then the constructor cannot terminate successfully
    if (store == null) {
        return;
    }
    // check for uninitialized fields in them:
    if (node.getKind() == Tree.Kind.METHOD && TreeUtils.isCompactCanonicalRecordConstructor((MethodTree) node)) {
        return;
    }
    Pair<List<VariableTree>, List<VariableTree>> uninitializedFields = atypeFactory.getUninitializedFields(store, getCurrentPath(), staticFields, receiverAnnotations);
    List<VariableTree> violatingFields = uninitializedFields.first;
    List<VariableTree> nonviolatingFields = uninitializedFields.second;
    // Remove fields that have already been initialized by an initializer block.
    if (staticFields) {
        violatingFields.removeAll(initializedFields);
        nonviolatingFields.removeAll(initializedFields);
    } else {
        violatingFields.removeAll(initializedFields);
        nonviolatingFields.removeAll(initializedFields);
    }
    // Errors are issued at the field declaration if the field is static or if the constructor
    // is the default constructor.
    // Errors are issued at the constructor declaration if the field is non-static and the
    // constructor is non-default.
    boolean errorAtField = staticFields || TreeUtils.isSynthetic((MethodTree) node);
    String FIELDS_UNINITIALIZED_KEY = (staticFields ? "initialization.static.field.uninitialized" : errorAtField ? "initialization.field.uninitialized" : "initialization.fields.uninitialized");
    // Remove fields with a relevant @SuppressWarnings annotation.
    violatingFields.removeIf(f -> checker.shouldSuppressWarnings(TreeUtils.elementFromTree(f), FIELDS_UNINITIALIZED_KEY));
    nonviolatingFields.removeIf(f -> checker.shouldSuppressWarnings(TreeUtils.elementFromTree(f), FIELDS_UNINITIALIZED_KEY));
    if (!violatingFields.isEmpty()) {
        if (errorAtField) {
            // Issue each error at the relevant field
            for (VariableTree f : violatingFields) {
                checker.reportError(f, FIELDS_UNINITIALIZED_KEY, f.getName());
            }
        } else {
            // Issue all the errors at the relevant constructor
            StringJoiner fieldsString = new StringJoiner(", ");
            for (VariableTree f : violatingFields) {
                fieldsString.add(f.getName());
            }
            checker.reportError(node, FIELDS_UNINITIALIZED_KEY, fieldsString);
        }
    }
    // Support -Ainfer command-line argument.
    WholeProgramInference wpi = atypeFactory.getWholeProgramInference();
    if (wpi != null) {
        // For each uninitialized field, treat it as if the default value is assigned to it.
        List<VariableTree> uninitFields = new ArrayList<>(violatingFields);
        uninitFields.addAll(nonviolatingFields);
        for (VariableTree fieldTree : uninitFields) {
            Element elt = TreeUtils.elementFromTree(fieldTree);
            wpi.updateFieldFromType(fieldTree, elt, fieldTree.getName().toString(), atypeFactory.getDefaultValueAnnotatedType(elt.asType()));
        }
    }
}
Also used : MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) VariableTree(com.sun.source.tree.VariableTree) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) WholeProgramInference(org.checkerframework.common.wholeprograminference.WholeProgramInference) StringJoiner(java.util.StringJoiner)

Example 2 with WholeProgramInference

use of org.checkerframework.common.wholeprograminference.WholeProgramInference in project checker-framework by typetools.

the class FormatterVisitor method visitMethodInvocation.

@Override
public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
    FormatterTreeUtil ftu = atypeFactory.treeUtil;
    FormatCall fc = ftu.create(node, atypeFactory);
    if (fc != null) {
        MethodTree enclosingMethod = TreePathUtil.enclosingMethod(atypeFactory.getPath(fc.invocationTree));
        Result<String> errMissingFormat = fc.errMissingFormatAnnotation();
        if (errMissingFormat != null) {
            // The string's type has no @Format annotation.
            if (isWrappedFormatCall(fc, enclosingMethod)) {
            // Nothing to do, because call is legal.
            } else {
                // I.1
                ftu.failure(errMissingFormat, "format.string", errMissingFormat.value());
            }
        } else {
            // The string has a @Format annotation.
            Result<InvocationType> invc = fc.getInvocationType();
            ConversionCategory[] formatCats = fc.getFormatCategories();
            switch(invc.value()) {
                case VARARG:
                    Result<TypeMirror>[] argTypes = fc.getArgTypes();
                    int argl = argTypes.length;
                    int formatl = formatCats.length;
                    if (argl < formatl) {
                        // For assignments, format.missing.arguments is issued from commonAssignmentCheck.
                        // II.1
                        ftu.failure(invc, "format.missing.arguments", formatl, argl);
                    } else {
                        if (argl > formatl) {
                            // II.2
                            ftu.warning(invc, "format.excess.arguments", formatl, argl);
                        }
                        for (int i = 0; i < formatl; ++i) {
                            ConversionCategory formatCat = formatCats[i];
                            Result<TypeMirror> arg = argTypes[i];
                            TypeMirror argType = arg.value();
                            switch(formatCat) {
                                case UNUSED:
                                    // I.2
                                    ftu.warning(arg, "format.argument.unused", " " + (1 + i));
                                    break;
                                case NULL:
                                    // I.3
                                    if (argType.getKind() == TypeKind.NULL) {
                                        ftu.warning(arg, "format.specifier.null", " " + (1 + i));
                                    } else {
                                        ftu.failure(arg, "format.specifier.null", " " + (1 + i));
                                    }
                                    break;
                                case GENERAL:
                                    break;
                                default:
                                    if (!fc.isValidArgument(formatCat, argType)) {
                                        // II.3
                                        ExecutableElement method = TreeUtils.elementFromUse(node);
                                        CharSequence methodName = ElementUtils.getSimpleNameOrDescription(method);
                                        ftu.failure(arg, "argument", "in varargs position", methodName, argType, formatCat);
                                    }
                                    break;
                            }
                        }
                    }
                    break;
                case ARRAY:
                    // III
                    if (!isWrappedFormatCall(fc, enclosingMethod)) {
                        ftu.warning(invc, "format.indirect.arguments");
                    }
                // fall through
                case NULLARRAY:
                    for (ConversionCategory cat : formatCats) {
                        if (cat == ConversionCategory.NULL) {
                            // I.3
                            if (invc.value() == FormatterTreeUtil.InvocationType.NULLARRAY) {
                                ftu.warning(invc, "format.specifier.null", "");
                            } else {
                                ftu.failure(invc, "format.specifier.null", "");
                            }
                        }
                        if (cat == ConversionCategory.UNUSED) {
                            // I.2
                            ftu.warning(invc, "format.argument.unused", "");
                        }
                    }
                    break;
            }
        }
        // Support -Ainfer command-line argument.
        WholeProgramInference wpi = atypeFactory.getWholeProgramInference();
        if (wpi != null && forwardsArguments(node, enclosingMethod)) {
            wpi.addMethodDeclarationAnnotation(TreeUtils.elementFromDeclaration(enclosingMethod), atypeFactory.FORMATMETHOD);
        }
    }
    return super.visitMethodInvocation(node, p);
}
Also used : ConversionCategory(org.checkerframework.checker.formatter.qual.ConversionCategory) FormatCall(org.checkerframework.checker.formatter.FormatterTreeUtil.FormatCall) MethodTree(com.sun.source.tree.MethodTree) ExecutableElement(javax.lang.model.element.ExecutableElement) InvocationType(org.checkerframework.checker.formatter.FormatterTreeUtil.InvocationType) Result(org.checkerframework.checker.formatter.FormatterTreeUtil.Result) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) TypeMirror(javax.lang.model.type.TypeMirror) WholeProgramInference(org.checkerframework.common.wholeprograminference.WholeProgramInference)

Example 3 with WholeProgramInference

use of org.checkerframework.common.wholeprograminference.WholeProgramInference in project checker-framework by typetools.

the class BaseTypeVisitor method checkPurity.

/**
 * Check method purity if needed. Note that overriding rules are checked as part of {@link
 * #checkOverride(MethodTree, AnnotatedTypeMirror.AnnotatedExecutableType,
 * AnnotatedTypeMirror.AnnotatedDeclaredType, AnnotatedTypeMirror.AnnotatedExecutableType,
 * AnnotatedTypeMirror.AnnotatedDeclaredType)}.
 *
 * @param node the method tree to check
 */
protected void checkPurity(MethodTree node) {
    if (!checkPurity) {
        return;
    }
    if (!suggestPureMethods && !PurityUtils.hasPurityAnnotation(atypeFactory, node)) {
        // There is nothing to check.
        return;
    }
    // check "no" purity
    EnumSet<Pure.Kind> kinds = PurityUtils.getPurityKinds(atypeFactory, node);
    // @Deterministic makes no sense for a void method or constructor
    boolean isDeterministic = kinds.contains(Pure.Kind.DETERMINISTIC);
    if (isDeterministic) {
        if (TreeUtils.isConstructor(node)) {
            checker.reportWarning(node, "purity.deterministic.constructor");
        } else if (TreeUtils.typeOf(node.getReturnType()).getKind() == TypeKind.VOID) {
            checker.reportWarning(node, "purity.deterministic.void.method");
        }
    }
    TreePath body = atypeFactory.getPath(node.getBody());
    PurityResult r;
    if (body == null) {
        r = new PurityResult();
    } else {
        r = PurityChecker.checkPurity(body, atypeFactory, checker.hasOption("assumeSideEffectFree") || checker.hasOption("assumePure"), checker.hasOption("assumeDeterministic") || checker.hasOption("assumePure"));
    }
    if (!r.isPure(kinds)) {
        reportPurityErrors(r, node, kinds);
    }
    if (suggestPureMethods && !TreeUtils.isSynthetic(node)) {
        // Issue a warning if the method is pure, but not annotated as such.
        EnumSet<Pure.Kind> additionalKinds = r.getKinds().clone();
        additionalKinds.removeAll(kinds);
        if (TreeUtils.isConstructor(node)) {
            additionalKinds.remove(Pure.Kind.DETERMINISTIC);
        }
        if (!additionalKinds.isEmpty()) {
            if (infer) {
                if (inferPurity) {
                    WholeProgramInference wpi = atypeFactory.getWholeProgramInference();
                    ExecutableElement methodElt = TreeUtils.elementFromDeclaration(node);
                    if (additionalKinds.size() == 2) {
                        wpi.addMethodDeclarationAnnotation(methodElt, PURE);
                    } else if (additionalKinds.contains(Pure.Kind.SIDE_EFFECT_FREE)) {
                        wpi.addMethodDeclarationAnnotation(methodElt, SIDE_EFFECT_FREE);
                    } else if (additionalKinds.contains(Pure.Kind.DETERMINISTIC)) {
                        wpi.addMethodDeclarationAnnotation(methodElt, DETERMINISTIC);
                    } else {
                        throw new BugInCF("Unexpected purity kind in " + additionalKinds);
                    }
                }
            } else {
                if (additionalKinds.size() == 2) {
                    checker.reportWarning(node, "purity.more.pure", node.getName());
                } else if (additionalKinds.contains(Pure.Kind.SIDE_EFFECT_FREE)) {
                    checker.reportWarning(node, "purity.more.sideeffectfree", node.getName());
                } else if (additionalKinds.contains(Pure.Kind.DETERMINISTIC)) {
                    checker.reportWarning(node, "purity.more.deterministic", node.getName());
                } else {
                    throw new BugInCF("Unexpected purity kind in " + additionalKinds);
                }
            }
        }
    }
}
Also used : PurityResult(org.checkerframework.dataflow.util.PurityChecker.PurityResult) TreePath(com.sun.source.util.TreePath) ReferenceKind(com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind) TypeKind(javax.lang.model.type.TypeKind) Kind(javax.tools.Diagnostic.Kind) ElementKind(javax.lang.model.element.ElementKind) ExecutableElement(javax.lang.model.element.ExecutableElement) WholeProgramInference(org.checkerframework.common.wholeprograminference.WholeProgramInference) BugInCF(org.checkerframework.javacutil.BugInCF)

Aggregations

ExecutableElement (javax.lang.model.element.ExecutableElement)3 WholeProgramInference (org.checkerframework.common.wholeprograminference.WholeProgramInference)3 MethodTree (com.sun.source.tree.MethodTree)2 VariableTree (com.sun.source.tree.VariableTree)1 TreePath (com.sun.source.util.TreePath)1 ReferenceKind (com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1 StringJoiner (java.util.StringJoiner)1 Element (javax.lang.model.element.Element)1 ElementKind (javax.lang.model.element.ElementKind)1 TypeKind (javax.lang.model.type.TypeKind)1 TypeMirror (javax.lang.model.type.TypeMirror)1 Kind (javax.tools.Diagnostic.Kind)1 FormatCall (org.checkerframework.checker.formatter.FormatterTreeUtil.FormatCall)1 InvocationType (org.checkerframework.checker.formatter.FormatterTreeUtil.InvocationType)1 Result (org.checkerframework.checker.formatter.FormatterTreeUtil.Result)1 ConversionCategory (org.checkerframework.checker.formatter.qual.ConversionCategory)1 PurityResult (org.checkerframework.dataflow.util.PurityChecker.PurityResult)1 AnnotatedTypeMirror (org.checkerframework.framework.type.AnnotatedTypeMirror)1