All Downloads are FREE. Search and download functionalities are using the official Maven repository.

checker.src.org.checkerframework.checker.formatter.FormatterVisitor Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java’s type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.42.0
Show newest version
package org.checkerframework.checker.formatter;
/*>>>
import org.checkerframework.checker.compilermsgs.qual.CompilerMessageKey;
*/
import org.checkerframework.checker.formatter.FormatterTreeUtil.FormatCall;
import org.checkerframework.checker.formatter.FormatterTreeUtil.InvocationType;
import org.checkerframework.checker.formatter.FormatterTreeUtil.Result;
import org.checkerframework.checker.formatter.qual.ConversionCategory;
import org.checkerframework.common.basetype.BaseTypeChecker;
import org.checkerframework.common.basetype.BaseTypeVisitor;
import org.checkerframework.framework.type.AnnotatedTypeMirror;
import org.checkerframework.javacutil.AnnotationUtils;

import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.type.TypeMirror;

import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.Tree;

/**
 * Whenever a format method invocation is found in the syntax tree,
 * the following checks happen, read the code, seriously! (otherwise see manual 12.2)
 *
 * @author Konstantin Weitz
 */
public class FormatterVisitor extends BaseTypeVisitor {
    public FormatterVisitor(BaseTypeChecker checker) {
        super(checker);
    }

    @Override
    public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
        FormatterTreeUtil tu = atypeFactory.treeUtil;
        if (tu.isFormatCall(node, atypeFactory)) {
            FormatCall fc = atypeFactory.treeUtil.new FormatCall(node, atypeFactory);

            Result sat = fc.isIllegalFormat();
            if (sat.value() != null) {
                // I.1
                tu.failure(sat, "format.string.invalid", sat.value());
            } else {
                Result invc = fc.getInvocationType();
                ConversionCategory[] formatCats = fc.getFormatCategories();
                switch (invc.value()) {
                case VARARG:
                    Result[] paramTypes = fc.getParamTypes();
                    int paraml = paramTypes.length;
                    int formatl = formatCats.length;
                    if (paraml < formatl) {
                        // For assignments, format.missing.arguments is issued
                        // from commonAssignmentCheck.
                        // II.1
                        tu.failure(invc, "format.missing.arguments", formatl, paraml);
                    } else {
                        if (paraml > formatl) {
                            // II.2
                            tu.warning(invc, "format.excess.arguments", formatl, paraml);
                        }
                        for (int i = 0; i < formatl; ++i) {
                            ConversionCategory formatCat = formatCats[i];
                            Result param = paramTypes[i];
                            TypeMirror paramType = param.value();

                            switch (formatCat) {
                            case UNUSED:
                                // I.2
                                tu.warning(param, "format.argument.unused"," "+(1+i));
                                break;
                            case NULL:
                                // I.3
                                tu.failure(param, "format.specifier.null"," "+(1+i));
                                break;
                            case GENERAL:
                                break;
                            default:
                                if (!fc.isValidParameter(formatCat, paramType)) {
                                    // II.3
                                    tu.failure(param, "argument.type.incompatible", paramType,
                                            formatCat);
                                }
                                break;
                            }
                        }
                    }
                    break;
                case NULLARRAY:
                    /* continue */
                case ARRAY:
                    for (ConversionCategory cat : formatCats) {
                        if (cat == ConversionCategory.NULL) {
                            // I.3
                            tu.failure(invc, "format.specifier.null","");
                        }
                        if (cat == ConversionCategory.UNUSED) {
                            // I.2
                            tu.warning(invc, "format.argument.unused","");
                        }
                    }
                    // III
                    tu.warning(invc, "format.indirect.arguments");
                    break;
                }
            }
        }
        return super.visitMethodInvocation(node, p);
    }

    @Override
    protected void commonAssignmentCheck(AnnotatedTypeMirror varType,
            AnnotatedTypeMirror valueType, Tree valueTree, /*@CompilerMessageKey*/ String errorKey) {
        super.commonAssignmentCheck(varType, valueType, valueTree, errorKey);

        AnnotationMirror rhs = valueType.getAnnotationInHierarchy(atypeFactory.UNKNOWNFORMAT);
        AnnotationMirror lhs = varType.getAnnotationInHierarchy(atypeFactory.UNKNOWNFORMAT);

        // From the manual:
        // It is legal to use a format string with fewer format specifiers
        // than required, but a warning is issued.
        // The format.missing.arguments warning is issued here for assignments.
        // For method calls, it is issued in visitMethodInvocation.
        if (AnnotationUtils.areSameIgnoringValues(rhs, atypeFactory.FORMAT) &&
            AnnotationUtils.areSameIgnoringValues(lhs, atypeFactory.FORMAT)) {
            ConversionCategory[] rhsArgTypes =
                    atypeFactory.treeUtil.formatAnnotationToCategories(rhs);
            ConversionCategory[] lhsArgTypes =
                    atypeFactory.treeUtil.formatAnnotationToCategories(lhs);

            if (rhsArgTypes.length < lhsArgTypes.length) {
                checker.report(org.checkerframework.framework.source.Result.warning("format.missing.arguments",
                        varType.toString(), valueType.toString()), valueTree);
            }
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy