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()));
}
}
}
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);
}
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);
}
}
}
}
}
Aggregations