use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class BaseTypeVisitor method visitReturn.
/**
* Checks that the type of the return expression is a subtype of the enclosing method required
* return type. If not, it issues a "return" error.
*/
@Override
public Void visitReturn(ReturnTree node, Void p) {
// Don't try to check return expressions for void methods.
if (node.getExpression() == null) {
return super.visitReturn(node, p);
}
Tree enclosing = TreePathUtil.enclosingOfKind(getCurrentPath(), new HashSet<>(Arrays.asList(Tree.Kind.METHOD, Tree.Kind.LAMBDA_EXPRESSION)));
AnnotatedTypeMirror ret = null;
if (enclosing.getKind() == Tree.Kind.METHOD) {
MethodTree enclosingMethod = TreePathUtil.enclosingMethod(getCurrentPath());
boolean valid = validateTypeOf(enclosing);
if (valid) {
ret = atypeFactory.getMethodReturnType(enclosingMethod, node);
}
} else {
AnnotatedExecutableType result = atypeFactory.getFunctionTypeFromTree((LambdaExpressionTree) enclosing);
ret = result.getReturnType();
}
if (ret != null) {
commonAssignmentCheck(ret, node.getExpression(), "return");
}
return super.visitReturn(node, p);
}
use of com.sun.source.tree.MethodTree 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 com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class InterningVisitor method processClassTree.
/**
* Method to implement the @UsesObjectEquals functionality. If a class is annotated
* with @UsesObjectEquals, it must:
*
* <ul>
* <li>not override .equals(Object) and be a subclass of a class annotated
* with @UsesObjectEquals, or
* <li>override equals(Object) with body "this == arg"
* </ul>
*
* If a class is not annotated with @UsesObjectEquals, it must:
*
* <ul>
* <li>not have a superclass annotated with @UsesObjectEquals
* </ul>
*
* @see
* org.checkerframework.common.basetype.BaseTypeVisitor#visitClass(com.sun.source.tree.ClassTree,
* java.lang.Object)
*/
@Override
public void processClassTree(ClassTree classTree) {
TypeElement elt = TreeUtils.elementFromDeclaration(classTree);
AnnotationMirror annotation = atypeFactory.getDeclAnnotation(elt, UsesObjectEquals.class);
// and its supertype is Object or is annotated with @UsesObjectEquals.
if (annotation != null) {
MethodTree equalsMethod = equalsImplementation(classTree);
if (equalsMethod != null) {
if (!isReferenceEqualityImplementation(equalsMethod)) {
checker.reportError(classTree, "overrides.equals");
}
} else {
// Does not override equals()
TypeMirror superClass = elt.getSuperclass();
if (superClass != null && // The super class of an interface is "none" rather than null.
superClass.getKind() == TypeKind.DECLARED) {
TypeElement superClassElement = TypesUtils.getTypeElement(superClass);
if (superClassElement != null && !ElementUtils.isObject(superClassElement) && atypeFactory.getDeclAnnotation(superClassElement, UsesObjectEquals.class) == null) {
checker.reportError(classTree, "superclass.notannotated");
}
}
}
}
super.processClassTree(classTree);
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class InterningVisitor method equalsImplementation.
// **********************************************************************
// Helper methods
// **********************************************************************
/**
* Returns the method that overrides Object.equals, or null.
*
* @param node a class
* @return the class's implementation of equals, or null
*/
private MethodTree equalsImplementation(ClassTree node) {
List<? extends Tree> members = node.getMembers();
for (Tree member : members) {
if (member instanceof MethodTree) {
MethodTree mTree = (MethodTree) member;
ExecutableElement enclosing = TreeUtils.elementFromDeclaration(mTree);
if (overrides(enclosing, Object.class, "equals")) {
return mTree;
}
}
}
return null;
}
use of com.sun.source.tree.MethodTree in project checker-framework by typetools.
the class SourceChecker method shouldSuppressWarnings.
/**
* Determines whether all the warnings pertaining to a given tree should be suppressed. Returns
* true if the tree is within the scope of a @SuppressWarnings annotation, one of whose values
* suppresses the checker's warnings. Also, returns true if the {@code errKey} matches a string in
* {@code -AsuppressWarnings}.
*
* @param tree the tree that might be a source of a warning
* @param errKey the error key the checker is emitting
* @return true if no warning should be emitted for the given tree because it is contained by a
* declaration with an appropriately-valued {@literal @}SuppressWarnings annotation; false
* otherwise
*/
public boolean shouldSuppressWarnings(Tree tree, String errKey) {
Collection<String> prefixes = getSuppressWarningsPrefixes();
if (prefixes.isEmpty() || (prefixes.contains(SUPPRESS_ALL_PREFIX) && prefixes.size() == 1)) {
throw new BugInCF("Checker must provide a SuppressWarnings prefix." + " SourceChecker#getSuppressWarningsPrefixes was not overridden correctly.");
}
if (shouldSuppress(getSuppressWarningsStringsFromOption(), errKey)) {
return true;
}
if (shouldSuppress(getSuppressWarningsStringsFromOption(), errKey)) {
// the warning.
return true;
}
// trees.getPath might be slow, but this is only used in error reporting
@Nullable TreePath path = trees.getPath(this.currentRoot, tree);
@Nullable VariableTree var = TreePathUtil.enclosingVariable(path);
if (var != null && shouldSuppressWarnings(TreeUtils.elementFromTree(var), errKey)) {
return true;
}
@Nullable MethodTree method = TreePathUtil.enclosingMethod(path);
if (method != null) {
@Nullable Element elt = TreeUtils.elementFromTree(method);
if (shouldSuppressWarnings(elt, errKey)) {
return true;
}
if (isAnnotatedForThisCheckerOrUpstreamChecker(elt)) {
// because they may not have an @AnnotatedFor.
return false;
}
}
@Nullable ClassTree cls = TreePathUtil.enclosingClass(path);
if (cls != null) {
@Nullable Element elt = TreeUtils.elementFromTree(cls);
if (shouldSuppressWarnings(elt, errKey)) {
return true;
}
if (isAnnotatedForThisCheckerOrUpstreamChecker(elt)) {
// because they may not have an @AnnotatedFor.
return false;
}
}
if (useConservativeDefault("source")) {
// false, we DO suppress the warning.
return true;
}
return false;
}
Aggregations