use of com.google.errorprone.VisitorState in project error-prone by google.
the class Matchers method enclosingNode.
/**
* Matches an AST node that is enclosed by some node that matches the given matcher.
*
* <p>TODO(eaftan): This could be used instead of enclosingBlock and enclosingClass.
*/
public static <T extends Tree> Matcher<Tree> enclosingNode(final Matcher<T> matcher) {
return new Matcher<Tree>() {
// TODO(cushon): this should take a Class<T>
@SuppressWarnings("unchecked")
@Override
public boolean matches(Tree t, VisitorState state) {
TreePath path = state.getPath().getParentPath();
while (path != null) {
Tree node = path.getLeaf();
state = state.withPath(path);
if (matcher.matches((T) node, state)) {
return true;
}
path = path.getParentPath();
}
return false;
}
};
}
use of com.google.errorprone.VisitorState in project error-prone by google.
the class Matchers method receiverSameAsArgument.
/**
* Matches when the receiver of an instance method is the same reference as a particular argument
* to the method. For example, receiverSameAsArgument(1) would match {@code obj.method("", obj)}
*
* @param argNum The number of the argument to compare against (zero-based.
*/
public static Matcher<? super MethodInvocationTree> receiverSameAsArgument(final int argNum) {
return new Matcher<MethodInvocationTree>() {
@Override
public boolean matches(MethodInvocationTree t, VisitorState state) {
List<? extends ExpressionTree> args = t.getArguments();
if (args.size() <= argNum) {
return false;
}
ExpressionTree arg = args.get(argNum);
JCExpression methodSelect = (JCExpression) t.getMethodSelect();
if (methodSelect instanceof JCFieldAccess) {
JCFieldAccess fieldAccess = (JCFieldAccess) methodSelect;
return ASTHelpers.sameVariable(fieldAccess.getExpression(), arg);
} else if (methodSelect instanceof JCIdent) {
// A bare method call: "equals(foo)". Receiver is implicitly "this".
return "this".equals(arg.toString());
}
return false;
}
};
}
use of com.google.errorprone.VisitorState in project error-prone by google.
the class TypeParameterShadowing method findDuplicatesOf.
private Description findDuplicatesOf(Tree tree, List<? extends TypeParameterTree> typeParameters, VisitorState state) {
Symbol symbol = ASTHelpers.getSymbol(tree);
if (symbol == null) {
return Description.NO_MATCH;
}
List<TypeVariableSymbol> enclosingTypeSymbols = typeVariablesEnclosing(symbol);
if (enclosingTypeSymbols.isEmpty()) {
return Description.NO_MATCH;
}
List<TypeVariableSymbol> conflictingTypeSymbols = new ArrayList<>();
typeParameters.forEach(param -> enclosingTypeSymbols.stream().filter(tvs -> tvs.name.contentEquals(param.getName())).findFirst().ifPresent(conflictingTypeSymbols::add));
if (conflictingTypeSymbols.isEmpty()) {
return Description.NO_MATCH;
}
Description.Builder descriptionBuilder = buildDescription(tree);
String message = "Found aliased type parameters: " + conflictingTypeSymbols.stream().map(tvs -> tvs.name + " declared in " + tvs.owner.getSimpleName()).collect(Collectors.joining("\n"));
descriptionBuilder.setMessage(message);
Set<String> typeVarsInScope = Streams.concat(enclosingTypeSymbols.stream(), symbol.getTypeParameters().stream()).map(v -> v.name.toString()).collect(toImmutableSet());
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
conflictingTypeSymbols.stream().map(v -> renameTypeVariable(typeParameterInList(typeParameters, v), tree, replacementTypeVarName(v.name, typeVarsInScope), state)).forEach(fixBuilder::merge);
descriptionBuilder.addFix(fixBuilder.build());
return descriptionBuilder.build();
}
use of com.google.errorprone.VisitorState in project error-prone by google.
the class UngroupedOverloads method checkOverloads.
private void checkOverloads(VisitorState state, List<? extends Tree> members, Name name, Collection<MemberWithIndex> overloads) {
if (overloads.size() <= 1) {
return;
}
// check if the indices of the overloads in the member list are sequential
MemberWithIndex first = overloads.iterator().next();
boolean grouped = Streams.zip(Stream.iterate(first.index(), i -> i + 1), overloads.stream().map(m -> m.index()), (a, b) -> Objects.equals(a, b)).allMatch(x -> x);
if (grouped) {
return;
}
if (overloads.stream().anyMatch(m -> isSuppressed(m.tree()))) {
return;
}
// build a fix that deletes all but the first overload, and adds them back immediately after
// the first overload
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
StringBuilder sb = new StringBuilder("\n");
overloads.stream().filter(o -> o != first).forEach(o -> {
int start = state.getEndPosition(members.get(o.index() - 1));
int end = state.getEndPosition(o.tree());
sb.append(state.getSourceCode(), start, end).append('\n');
fixBuilder.replace(start, end, "");
});
fixBuilder.postfixWith(first.tree(), sb.toString());
SuggestedFix fix = fixBuilder.build();
String message = String.format("Overloads of '%s' are not grouped together.", name);
// emit findings for each overload
overloads.stream().forEach(o -> state.reportMatch(buildDescription(o.tree()).addFix(fix).setMessage(message).build()));
}
use of com.google.errorprone.VisitorState in project error-prone by google.
the class UnnecessaryDefaultInEnumSwitch method matchSwitch.
@Override
public Description matchSwitch(SwitchTree tree, VisitorState state) {
TypeSymbol switchType = ((JCSwitch) tree).getExpression().type.tsym;
if (switchType.getKind() != ElementKind.ENUM) {
return NO_MATCH;
}
CaseTree caseBeforeDefault = null;
CaseTree defaultCase = null;
for (CaseTree caseTree : tree.getCases()) {
if (caseTree.getExpression() == null) {
defaultCase = caseTree;
break;
} else {
caseBeforeDefault = caseTree;
}
}
if (defaultCase == null) {
return NO_MATCH;
}
Set<String> handledCases = tree.getCases().stream().map(CaseTree::getExpression).filter(IdentifierTree.class::isInstance).map(p -> ((IdentifierTree) p).getName().toString()).collect(toImmutableSet());
if (!ASTHelpers.enumValues(switchType).equals(handledCases)) {
return NO_MATCH;
}
Fix fix;
List<? extends StatementTree> defaultStatements = defaultCase.getStatements();
if (trivialDefault(defaultStatements)) {
// deleting `default:` or `default: break;` is a no-op
fix = SuggestedFix.delete(defaultCase);
} else {
String defaultSource = state.getSourceCode().subSequence(((JCTree) defaultStatements.get(0)).getStartPosition(), state.getEndPosition(getLast(defaultStatements))).toString();
String initialComments = comments(state, defaultCase, defaultStatements);
if (!canCompleteNormally(tree)) {
// if the switch statement cannot complete normally, then deleting the default
// and moving its statements to after the switch statement is a no-op
fix = SuggestedFix.builder().delete(defaultCase).postfixWith(tree, initialComments + defaultSource).build();
} else {
// and the code is unreachable -- so use (2) as the strategy. Otherwise, use (1).
if (!SuggestedFixes.compilesWithFix(SuggestedFix.delete(defaultCase), state)) {
// case (3)
return NO_MATCH;
}
if (!canCompleteNormally(caseBeforeDefault)) {
// case (2) -- If the case before the default can't complete normally,
// it's OK to to delete the default.
fix = SuggestedFix.delete(defaultCase);
} else {
// case (1) -- If it can complete, we need to merge the default into it.
fix = SuggestedFix.builder().delete(defaultCase).postfixWith(caseBeforeDefault, initialComments + defaultSource).build();
}
}
}
return describeMatch(defaultCase, fix);
}
Aggregations