use of com.google.errorprone.VisitorState in project error-prone by google.
the class WakelockReleasedDangerously method wakelockMayThrow.
/**
* Whether the given WakeLock may throw an unexpected RuntimeException when released.
*
* <p>Returns true if: 1) the given WakeLock was acquired with timeout, and 2) the given WakeLock
* is reference counted.
*/
private boolean wakelockMayThrow(Symbol wakelockSymbol, VisitorState state) {
ClassTree enclosingClass = getTopLevelClass(state);
ImmutableMultimap<String, MethodInvocationTree> map = methodCallsForSymbol(wakelockSymbol, enclosingClass);
// Was acquired with timeout.
return map.get("acquire").stream().anyMatch(m -> m.getArguments().size() == 1) && // Is reference counted, i.e., referenceCounted not explicitly set to false.
map.get("setReferenceCounted").stream().noneMatch(m -> Boolean.FALSE.equals(constValue(m.getArguments().get(0), Boolean.class)));
}
use of com.google.errorprone.VisitorState in project error-prone by google.
the class UnsafeFinalization method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
MethodSymbol sym = ASTHelpers.getSymbol(tree);
// Match invocations of static native methods.
if (sym == null || !sym.isStatic() || !Flags.asFlagSet(sym.flags()).contains(Flag.NATIVE)) {
return NO_MATCH;
}
// Find the enclosing method declaration where the invocation occurs.
MethodTree method = enclosingMethod(state);
if (method == null) {
return NO_MATCH;
}
// Don't check native methods called from static methods and constructors:
// static methods don't have an instance to finalize, and we shouldn't need to worry about
// finalization during construction.
MethodSymbol enclosing = ASTHelpers.getSymbol(method);
if (enclosing == null || enclosing.isStatic() || enclosing.isConstructor()) {
return NO_MATCH;
}
// Check if any arguments of the static native method are members (e.g. fields) of the enclosing
// class. We're only looking for cases where the static native uses state of the enclosing class
// that may become invalid after finalization.
ImmutableList<Symbol> arguments = tree.getArguments().stream().map(ASTHelpers::getSymbol).filter(x -> x != null).collect(toImmutableList());
if (arguments.stream().filter(x -> EnumSet.of(TypeKind.INT, TypeKind.LONG).contains(state.getTypes().unboxedTypeOrType(x.asType()).getKind())).noneMatch(arg -> arg.isMemberOf(enclosing.enclClass(), state.getTypes()))) {
// no instance state is passed to the native method
return NO_MATCH;
}
if (arguments.stream().anyMatch(arg -> arg.getSimpleName().contentEquals("this") && arg.isMemberOf(enclosing.enclClass(), state.getTypes()))) {
// the instance is passed to the native method
return NO_MATCH;
}
Symbol finalizeSym = getFinalizer(state, enclosing.enclClass());
if (finalizeSym.equals(enclosing)) {
// Don't check native methods called from within the implementation of finalize.
return NO_MATCH;
}
if (finalizeSym.enclClass().equals(state.getSymtab().objectType.asElement())) {
// Inheriting finalize from Object doesn't count.
return NO_MATCH;
}
boolean[] sawFence = { false };
new TreeScanner<Void, Void>() {
@Override
public Void visitMethodInvocation(MethodInvocationTree tree, Void unused) {
if (FENCE_MATCHER.matches(tree, state)) {
sawFence[0] = true;
}
return null;
}
}.scan(state.getPath().getCompilationUnit(), null);
if (sawFence[0]) {
// Ignore methods that contain a use of reachabilityFence.
return NO_MATCH;
}
return describeMatch(tree);
}
use of com.google.errorprone.VisitorState in project error-prone by google.
the class UnsafeFinalization method getFinalizer.
private static Symbol getFinalizer(VisitorState state, ClassSymbol enclosing) {
Type finalizerType = state.getTypeFromString("com.google.common.labs.base.Finalizer");
Optional<VarSymbol> finalizerField = state.getTypes().closure(enclosing.asType()).stream().flatMap(s -> getFields(s.asElement())).filter(s -> ASTHelpers.isSameType(finalizerType, s.asType(), state)).findFirst();
if (finalizerField.isPresent()) {
return finalizerField.get();
}
return ASTHelpers.resolveExistingMethod(state, enclosing.enclClass(), state.getName("finalize"), /* argTypes= */
ImmutableList.of(), /* tyargTypes= */
ImmutableList.of());
}
use of com.google.errorprone.VisitorState in project error-prone by google.
the class RefasterRuleBuilderScanner method visitMethod.
@Override
public Void visitMethod(MethodTree tree, Void v) {
try {
VisitorState state = new VisitorState(context);
logger.log(FINE, "Discovered method with name {0}", tree.getName());
if (ASTHelpers.hasAnnotation(tree, Placeholder.class, state)) {
checkArgument(tree.getModifiers().getFlags().contains(Modifier.ABSTRACT), "@Placeholder methods are expected to be abstract");
UTemplater templater = new UTemplater(context);
ImmutableMap.Builder<UVariableDecl, ImmutableClassToInstanceMap<Annotation>> params = ImmutableMap.builder();
for (VariableTree param : tree.getParameters()) {
params.put(templater.visitVariable(param, null), UTemplater.annotationMap(ASTHelpers.getSymbol(param)));
}
MethodSymbol sym = ASTHelpers.getSymbol(tree);
placeholderMethods.put(sym, PlaceholderMethod.create(tree.getName(), templater.template(sym.getReturnType()), params.build(), UTemplater.annotationMap(sym)));
} else if (ASTHelpers.hasAnnotation(tree, BeforeTemplate.class, state)) {
checkState(afterTemplates.isEmpty(), "BeforeTemplate must come before AfterTemplate");
Template<?> template = UTemplater.createTemplate(context, tree);
beforeTemplates.add(template);
if (template instanceof BlockTemplate) {
context.put(UTemplater.REQUIRE_BLOCK_KEY, /* data= */
true);
}
} else if (ASTHelpers.hasAnnotation(tree, AfterTemplate.class, state)) {
afterTemplates.add(UTemplater.createTemplate(context, tree));
} else if (tree.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
throw new IllegalArgumentException("Placeholder methods must have @Placeholder, but abstract method does not: " + tree);
}
return null;
} catch (Throwable t) {
throw new RuntimeException("Error analysing: " + tree.getName(), t);
}
}
use of com.google.errorprone.VisitorState in project error-prone by google.
the class ComparisonContractViolated method matchMethod.
@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
if (tree.getBody() == null) {
return Description.NO_MATCH;
}
// Test that the match is in a Comparable.compareTo or Comparator.compare method.
ClassTree declaringClass = ASTHelpers.findEnclosingNode(state.getPath(), ClassTree.class);
if (!COMPARABLE_CLASS_MATCHER.matches(declaringClass, state) && !COMPARATOR_CLASS_MATCHER.matches(declaringClass, state)) {
return Description.NO_MATCH;
}
if (!COMPARABLE_METHOD_MATCHER.matches(tree, state) && !COMPARATOR_METHOD_MATCHER.matches(tree, state)) {
return Description.NO_MATCH;
}
final Set<ComparisonResult> seenResults = EnumSet.noneOf(ComparisonResult.class);
final TreeVisitor<Void, VisitorState> visitReturnExpression = new SimpleTreeVisitor<Void, VisitorState>() {
@Override
protected Void defaultAction(Tree node, VisitorState state) {
seenResults.add(node.accept(CONSTANT_VISITOR, state));
return null;
}
@Override
public Void visitConditionalExpression(ConditionalExpressionTree node, VisitorState state) {
node.getTrueExpression().accept(this, state);
node.getFalseExpression().accept(this, state);
return null;
}
};
tree.getBody().accept(new TreeScanner<Void, VisitorState>() {
@Override
public Void visitReturn(ReturnTree node, VisitorState state) {
return node.getExpression().accept(visitReturnExpression, state);
}
}, state);
if (seenResults.isEmpty() || seenResults.contains(ComparisonResult.NONCONSTANT)) {
return Description.NO_MATCH;
}
if (!seenResults.contains(ComparisonResult.ZERO)) {
if (tree.getBody().getStatements().size() == 1 && tree.getBody().getStatements().get(0).getKind() == Kind.RETURN) {
ReturnTree returnTree = (ReturnTree) tree.getBody().getStatements().get(0);
if (returnTree.getExpression().getKind() == Kind.CONDITIONAL_EXPRESSION) {
ConditionalExpressionTree condTree = (ConditionalExpressionTree) returnTree.getExpression();
ExpressionTree conditionExpr = condTree.getCondition();
conditionExpr = ASTHelpers.stripParentheses(conditionExpr);
if (!(conditionExpr instanceof BinaryTree)) {
return describeMatch(tree);
}
ComparisonResult trueConst = condTree.getTrueExpression().accept(CONSTANT_VISITOR, state);
ComparisonResult falseConst = condTree.getFalseExpression().accept(CONSTANT_VISITOR, state);
boolean trueFirst;
if (trueConst == ComparisonResult.NEGATIVE_CONSTANT && falseConst == ComparisonResult.POSITIVE_CONSTANT) {
trueFirst = true;
} else if (trueConst == ComparisonResult.POSITIVE_CONSTANT && falseConst == ComparisonResult.NEGATIVE_CONSTANT) {
trueFirst = false;
} else {
return describeMatch(tree);
}
switch(conditionExpr.getKind()) {
case LESS_THAN:
case LESS_THAN_EQUAL:
break;
case GREATER_THAN:
case GREATER_THAN_EQUAL:
trueFirst = !trueFirst;
break;
default:
return describeMatch(tree);
}
BinaryTree binaryExpr = (BinaryTree) conditionExpr;
Type ty = ASTHelpers.getType(binaryExpr.getLeftOperand());
Types types = Types.instance(state.context);
Symtab symtab = Symtab.instance(state.context);
ExpressionTree first = trueFirst ? binaryExpr.getLeftOperand() : binaryExpr.getRightOperand();
ExpressionTree second = trueFirst ? binaryExpr.getRightOperand() : binaryExpr.getLeftOperand();
String compareType;
if (types.isSameType(ty, symtab.intType)) {
compareType = "Integer";
} else if (types.isSameType(ty, symtab.longType)) {
compareType = "Long";
} else {
return describeMatch(tree);
}
return describeMatch(condTree, SuggestedFix.replace(condTree, String.format("%s.compare(%s, %s)", compareType, state.getSourceForNode(first), state.getSourceForNode(second))));
}
}
return describeMatch(tree);
}
if (COMPARATOR_METHOD_MATCHER.matches(tree, state) && (seenResults.contains(ComparisonResult.NEGATIVE_CONSTANT) != seenResults.contains(ComparisonResult.POSITIVE_CONSTANT))) {
// See e.g. com.google.common.collect.Cut.BelowAll.
return describeMatch(tree);
} else {
return Description.NO_MATCH;
}
}
Aggregations