use of com.google.errorprone.matchers.Description in project error-prone by google.
the class CollectionIncompatibleType method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
MatchResult directResult = firstNonNullMatchResult(DIRECT_MATCHERS, tree, state);
MatchResult typeArgResult = null;
if (directResult == null) {
typeArgResult = firstNonNullMatchResult(TYPE_ARG_MATCHERS, tree, state);
}
if (directResult == null && typeArgResult == null) {
return Description.NO_MATCH;
}
Verify.verify(directResult == null ^ typeArgResult == null);
MatchResult result = MoreObjects.firstNonNull(directResult, typeArgResult);
Types types = state.getTypes();
TypeCompatibilityReport compatibilityReport = EqualsIncompatibleType.compatibilityOfTypes(result.targetType(), result.sourceType(), state);
if (compatibilityReport.compatible()) {
return Description.NO_MATCH;
}
// For error message, use simple names instead of fully qualified names unless they are
// identical.
String sourceTreeType = Signatures.prettyType(ASTHelpers.getType(result.sourceTree()));
String sourceType = Signatures.prettyType(result.sourceType());
String targetType = Signatures.prettyType(result.targetType());
if (sourceType.equals(targetType)) {
sourceType = result.sourceType().toString();
targetType = result.targetType().toString();
}
Description.Builder description = buildDescription(tree);
if (typeArgResult != null) {
description.setMessage(String.format("Argument '%s' should not be passed to this method; its type %s has a type argument " + "%s that is not compatible with its collection's type argument %s", result.sourceTree(), sourceTreeType, sourceType, targetType));
} else {
description.setMessage(String.format("Argument '%s' should not be passed to this method; its type %s is not compatible " + "with its collection's type argument %s", result.sourceTree(), sourceType, targetType));
}
switch(fixType) {
case PRINT_TYPES_AS_COMMENT:
description.addFix(SuggestedFix.prefixWith(tree, String.format("/* expected: %s, actual: %s */", ASTHelpers.getUpperBound(result.targetType(), types), result.sourceType())));
break;
case CAST:
Fix fix;
if (typeArgResult != null) {
TypeArgOfMethodArgMatcher matcher = (TypeArgOfMethodArgMatcher) typeArgResult.matcher();
String fullyQualifiedType = matcher.getMethodArgTypeName();
String simpleType = Iterables.getLast(Splitter.on('.').split(fullyQualifiedType));
fix = SuggestedFix.builder().prefixWith(result.sourceTree(), String.format("(%s<?>) ", simpleType)).addImport(fullyQualifiedType).build();
} else {
fix = SuggestedFix.prefixWith(result.sourceTree(), "(Object) ");
}
description.addFix(fix);
break;
case SUPPRESS_WARNINGS:
SuggestedFix.Builder builder = SuggestedFix.builder();
builder.prefixWith(result.sourceTree(), String.format("/* expected: %s, actual: %s */ ", targetType, sourceType));
addSuppressWarnings(builder, state, "CollectionIncompatibleType");
description.addFix(builder.build());
break;
case NONE:
break;
}
return description.build();
}
use of com.google.errorprone.matchers.Description in project error-prone by google.
the class DoubleCheckedLocking method handleField.
/**
* Report a {@link Description} if a field used in double-checked locking is not volatile.
*
* <p>If the AST node for the field declaration can be located in the current compilation unit,
* suggest adding the volatile modifier.
*/
private Description handleField(IfTree outerIf, VarSymbol sym, VisitorState state) {
if (sym.getModifiers().contains(Modifier.VOLATILE)) {
return Description.NO_MATCH;
}
if (isImmutable(sym.type, state)) {
return Description.NO_MATCH;
}
Description.Builder builder = buildDescription(outerIf);
JCTree fieldDecl = findFieldDeclaration(state.getPath(), sym);
if (fieldDecl != null) {
builder.addFix(SuggestedFixes.addModifiers(fieldDecl, state, Modifier.VOLATILE));
}
return builder.build();
}
use of com.google.errorprone.matchers.Description in project error-prone by google.
the class InconsistentOverloads method processGroupMethods.
private void processGroupMethods(List<MethodTree> groupMethodTrees, VisitorState state) {
Preconditions.checkArgument(!groupMethodTrees.isEmpty());
for (ParameterOrderingViolation violation : getViolations(groupMethodTrees)) {
MethodSymbol methodSymbol = getSymbol(violation.methodTree());
if (ASTHelpers.findSuperMethods(methodSymbol, state.getTypes()).isEmpty()) {
Description.Builder description = buildDescription(violation.methodTree());
description.setMessage(violation.getDescription());
state.reportMatch(description.build());
}
}
}
use of com.google.errorprone.matchers.Description in project error-prone by google.
the class ConstantField method matchVariable.
@Override
public Description matchVariable(VariableTree tree, VisitorState state) {
Symbol.VarSymbol sym = ASTHelpers.getSymbol(tree);
if (sym == null || sym.getKind() != ElementKind.FIELD) {
return Description.NO_MATCH;
}
String name = sym.getSimpleName().toString();
if (sym.isStatic() && sym.getModifiers().contains(Modifier.FINAL)) {
return checkImmutable(tree, state, sym, name);
}
if (!name.equals(name.toUpperCase())) {
return Description.NO_MATCH;
}
Description.Builder fixBuilder = buildDescription(tree);
if (canBecomeStaticMember(sym)) {
fixBuilder.addFix(SuggestedFixes.addModifiers(tree, state, Modifier.FINAL, Modifier.STATIC));
}
return fixBuilder.addFix(SuggestedFixes.renameVariable(tree, CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, name), state)).build();
}
use of com.google.errorprone.matchers.Description in project error-prone by google.
the class FloatCast method matchTypeCast.
@Override
public Description matchTypeCast(TypeCastTree tree, VisitorState state) {
Tree parent = state.getPath().getParentPath().getLeaf();
if (!(parent instanceof BinaryTree)) {
return NO_MATCH;
}
BinaryTree binop = (BinaryTree) parent;
if (!binop.getLeftOperand().equals(tree)) {
// the precedence is unambiguous for e.g. `i + (int) f`
return NO_MATCH;
}
if (binop.getKind() != Kind.MULTIPLY) {
// there's a bound on the imprecision for +, -, /
return NO_MATCH;
}
Type castType = ASTHelpers.getType(tree.getType());
Type operandType = ASTHelpers.getType(tree.getExpression());
if (castType == null || operandType == null) {
return NO_MATCH;
}
Symtab symtab = state.getSymtab();
if (isSameType(ASTHelpers.getType(parent), symtab.stringType, state)) {
// string concatenation doesn't count
return NO_MATCH;
}
switch(castType.getKind()) {
case LONG:
case INT:
case SHORT:
case CHAR:
case BYTE:
break;
default:
return NO_MATCH;
}
switch(operandType.getKind()) {
case FLOAT:
case DOUBLE:
break;
default:
return NO_MATCH;
}
if (BLACKLIST.matches(tree.getExpression(), state)) {
return NO_MATCH;
}
if (POW.matches(tree.getExpression(), state)) {
MethodInvocationTree pow = (MethodInvocationTree) tree.getExpression();
if (pow.getArguments().stream().map(ASTHelpers::getType).filter(x -> x != null).map(state.getTypes()::unboxedTypeOrType).map(Type::getKind).allMatch(INTEGRAL::contains)) {
return NO_MATCH;
}
}
// Find the outermost enclosing binop, to suggest e.g. `(long) (f * a * b)` instead of
// `(long) (f * a) * b`.
Tree enclosing = binop;
TreePath path = state.getPath().getParentPath().getParentPath();
while (path != null) {
if (!(path.getLeaf() instanceof BinaryTree)) {
break;
}
BinaryTree enclosingBinop = (BinaryTree) path.getLeaf();
if (!enclosingBinop.getLeftOperand().equals(enclosing)) {
break;
}
enclosing = enclosingBinop;
path = path.getParentPath();
}
return buildDescription(tree).addFix(SuggestedFix.builder().prefixWith(tree.getExpression(), "(").postfixWith(enclosing, ")").build()).addFix(SuggestedFix.builder().prefixWith(tree, "(").postfixWith(tree, ")").build()).build();
}
Aggregations