use of com.sun.source.util.TreePath in project error-prone by google.
the class DataFlow method findEnclosingMethodOrLambdaOrInitializer.
// TODO(user), remove once we merge jdk8 specific's with core
private static <T> TreePath findEnclosingMethodOrLambdaOrInitializer(TreePath path) {
while (path != null) {
if (path.getLeaf() instanceof MethodTree) {
return path;
}
TreePath parent = path.getParentPath();
if (parent != null) {
if (parent.getLeaf() instanceof ClassTree) {
if (path.getLeaf() instanceof BlockTree) {
// this is a class or instance initializer block
return path;
}
if (path.getLeaf() instanceof VariableTree && ((VariableTree) path.getLeaf()).getInitializer() != null) {
// this is a field with an inline initializer
return path;
}
}
if (parent.getLeaf() instanceof LambdaExpressionTree) {
return parent;
}
}
path = parent;
}
return null;
}
use of com.sun.source.util.TreePath in project error-prone by google.
the class StrictFormatStringValidation method validateFormatStringVariable.
/**
* Helps {@code validate()} validate a format string that is a variable, but not a parameter. This
* method assumes that the format string variable has already been asserted to be final or
* effectively final.
*/
private static ValidationResult validateFormatStringVariable(ExpressionTree formatStringTree, final Symbol formatStringSymbol, final List<? extends ExpressionTree> args, final VisitorState state) {
if (formatStringSymbol.getKind() != ElementKind.LOCAL_VARIABLE) {
return ValidationResult.create(null, String.format("Variables used as format strings that are not local variables must be compile time" + " consant.\n%s is not a local variable and is not compile time constant.", formatStringTree));
}
// Find the Tree for the block in which the variable is defined. If it is not defined in this
// class (though it may have been in a super class). We require compile time constant values in
// that case.
Symbol owner = formatStringSymbol.owner;
TreePath path = TreePath.getPath(state.getPath(), formatStringTree);
while (path != null && ASTHelpers.getSymbol(path.getLeaf()) != owner) {
path = path.getParentPath();
}
// impossible.
if (path == null) {
throw new IllegalStateException(String.format("Could not find the Tree where local variable %s is declared. " + "This should be impossible.", formatStringTree));
}
// Scan down from the scope where the variable was declared
ValidationResult result = path.getLeaf().accept(new TreeScanner<ValidationResult, Void>() {
@Override
public ValidationResult visitVariable(VariableTree node, Void unused) {
if (ASTHelpers.getSymbol(node) == formatStringSymbol) {
if (node.getInitializer() == null) {
return ValidationResult.create(null, String.format("Variables used as format strings must be initialized when they are" + " declared.\nInvalid declaration: %s", node));
}
return validateStringFromAssignment(node, node.getInitializer(), args, state);
}
return super.visitVariable(node, unused);
}
@Override
public ValidationResult reduce(ValidationResult r1, ValidationResult r2) {
if (r1 == null && r2 == null) {
return null;
}
return MoreObjects.firstNonNull(r1, r2);
}
}, null);
return result;
}
use of com.sun.source.util.TreePath in project error-prone by google.
the class FieldMissingNullable method matchAssignment.
@Override
public Description matchAssignment(AssignmentTree tree, VisitorState state) {
Symbol assigned = ASTHelpers.getSymbol(tree.getVariable());
if (assigned == null || assigned.getKind() != ElementKind.FIELD || assigned.type.isPrimitive()) {
// not a field of nullable type
return Description.NO_MATCH;
}
// Best-effort try to avoid running the dataflow analysis
// TODO(kmb): bail on more non-null expressions, such as "this", arithmethic, logical, and &&/||
ExpressionTree expression = tree.getExpression();
if (ASTHelpers.constValue(expression) != null) {
// This should include literals such as "true" or a string
return Description.NO_MATCH;
}
if (TrustingNullnessAnalysis.hasNullableAnnotation(assigned)) {
// field already annotated
return Description.NO_MATCH;
}
VariableTree fieldDecl = findDeclaration(state, assigned);
if (fieldDecl == null) {
// skip fields declared elsewhere for simplicity
return Description.NO_MATCH;
}
// Don't need dataflow to tell us that null is nullable
if (expression.getKind() == Tree.Kind.NULL_LITERAL) {
return makeFix(state, fieldDecl, tree, "Assigning null literal to field");
}
// OK let's see what dataflow says
Nullness nullness = TrustingNullnessAnalysis.instance(state.context).getNullness(new TreePath(state.getPath(), expression), state.context);
if (nullness == null) {
// TODO(b/69154806): Make dataflow work for that case.
return Description.NO_MATCH;
}
switch(nullness) {
case BOTTOM:
case NONNULL:
return Description.NO_MATCH;
case NULL:
return makeFix(state, fieldDecl, tree, "Assigning null to field");
case NULLABLE:
return makeFix(state, fieldDecl, tree, "May assign null to field");
default:
throw new AssertionError("Impossible: " + nullness);
}
}
use of com.sun.source.util.TreePath in project error-prone by google.
the class ForOverrideChecker method getOutermostClass.
/**
* Get the outermost class/interface/enum of an element, or null if none.
*/
private Type getOutermostClass(VisitorState state) {
TreePath path = state.getPath();
Type type = null;
while (path != null) {
if (path.getLeaf().getKind() == Kind.CLASS || path.getLeaf().getKind() == Kind.INTERFACE || path.getLeaf().getKind() == Kind.ENUM) {
type = ASTHelpers.getSymbol(path.getLeaf()).type;
}
path = path.getParentPath();
}
return type;
}
use of com.sun.source.util.TreePath in project error-prone by google.
the class InconsistentCapitalization method matchClass.
@Override
public Description matchClass(ClassTree tree, VisitorState state) {
ImmutableSet<Symbol> fields = FieldScanner.findFields(tree);
if (fields.isEmpty()) {
return Description.NO_MATCH;
}
ImmutableMap<String, Symbol> fieldNamesMap = fields.stream().collect(toImmutableMap(symbol -> symbol.toString().toLowerCase(), identity()));
ImmutableMap<TreePath, Symbol> matchedParameters = MatchingParametersScanner.findMatchingParameters(fieldNamesMap, state.getPath());
if (matchedParameters.isEmpty()) {
return Description.NO_MATCH;
}
for (Entry<TreePath, Symbol> entry : matchedParameters.entrySet()) {
TreePath parameterPath = entry.getKey();
Symbol field = entry.getValue();
String fieldName = field.getSimpleName().toString();
VariableTree parameterTree = (VariableTree) parameterPath.getLeaf();
SuggestedFix.Builder fix = SuggestedFix.builder().merge(SuggestedFixes.renameVariable(parameterTree, fieldName, state));
if (parameterPath.getParentPath() != null) {
String qualifiedName = getExplicitQualification(parameterPath, tree, state) + field.getSimpleName();
// If the field was accessed in a non-qualified way, by renaming the parameter this may
// cause clashes with it. Thus, it is required to qualify all uses of the field within the
// parameter's scope just in case.
parameterPath.getParentPath().getLeaf().accept(new TreeScanner<Void, Void>() {
@Override
public Void visitIdentifier(IdentifierTree tree, Void unused) {
if (field.equals(ASTHelpers.getSymbol(tree))) {
fix.replace(tree, qualifiedName);
}
return null;
}
}, null);
}
state.reportMatch(buildDescription(parameterPath.getLeaf()).setMessage(String.format("Found the field '%s' with the same name as the parameter '%s' but with " + "different capitalization.", fieldName, ((VariableTree) parameterPath.getLeaf()).getName())).addFix(fix.build()).build());
}
return Description.NO_MATCH;
}
Aggregations