use of com.sun.source.tree.StatementTree 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);
}
use of com.sun.source.tree.StatementTree in project error-prone by google.
the class ThreadJoinLoop method matchMethodInvocation.
@Override
public Description matchMethodInvocation(MethodInvocationTree methodInvocationTree, VisitorState visitorState) {
String threadString;
if (methodInvocationTree.getMethodSelect() instanceof MemberSelectTree) {
threadString = ((MemberSelectTree) methodInvocationTree.getMethodSelect()).getExpression().toString();
} else {
threadString = "this";
}
// with calculating time with declared variables)
if (!methodInvocationTree.getArguments().isEmpty()) {
return Description.NO_MATCH;
}
if (MATCH_THREAD_JOIN.matches(methodInvocationTree, visitorState)) {
TreePath treePath = ASTHelpers.findPathFromEnclosingNodeToTopLevel(visitorState.getPath(), TryTree.class);
if (treePath == null) {
return Description.NO_MATCH;
}
TreePath pathToLoop = ASTHelpers.findPathFromEnclosingNodeToTopLevel(treePath, WhileLoopTree.class);
// checks to make sure that if there is a while loop with only one statement (the try catch
// block)
boolean hasWhileLoopOneStatement = false;
if (pathToLoop != null) {
Tree statements = ((WhileLoopTree) pathToLoop.getLeaf()).getStatement();
if (statements instanceof BlockTree) {
if (((BlockTree) statements).getStatements().size() == 1) {
hasWhileLoopOneStatement = true;
}
}
}
Type interruptedType = visitorState.getSymtab().interruptedExceptionType;
Type exceptionType = visitorState.getSymtab().exceptionType;
TryTree tryTree = (TryTree) treePath.getLeaf();
// scans the try tree block for any other actions so that we do not accidentally delete
// important actions when replacing
TreeScannerMethodInvocations treeScanner = new TreeScannerMethodInvocations();
treeScanner.scan(tryTree.getBlock(), methodInvocationTree.toString());
if (treeScanner.count > 0) {
return Description.NO_MATCH;
}
if (tryTree.getFinallyBlock() != null) {
return Description.NO_MATCH;
}
List<? extends CatchTree> catches = tryTree.getCatches();
for (CatchTree tree : catches) {
Type typeSym = ASTHelpers.getType(tree.getParameter().getType());
if (Objects.equals(interruptedType, typeSym) || Objects.equals(exceptionType, typeSym)) {
List<? extends StatementTree> statementTrees = tree.getBlock().getStatements();
// replaces the while loop with the try block or replaces just the try block
if (statementTrees.isEmpty() || (statementTrees.size() == 1 && statementTrees.get(0).toString().equals(";"))) {
SuggestedFix.Builder builder = SuggestedFix.builder();
builder.replace(hasWhileLoopOneStatement ? pathToLoop.getLeaf() : tryTree, "Uninterruptibles.joinUninterruptibly(" + threadString + ");");
builder.addImport("com.google.common.util.concurrent.Uninterruptibles");
return describeMatch(methodInvocationTree, builder.build());
}
}
}
}
return Description.NO_MATCH;
}
use of com.sun.source.tree.StatementTree in project error-prone by google.
the class TryFailThrowable method fixWithReturnOrBoolean.
private static Fix fixWithReturnOrBoolean(TryTree tryTree, StatementTree failStatement, VisitorState state) {
Tree parent = state.getPath().getParentPath().getLeaf();
Tree grandparent = state.getPath().getParentPath().getParentPath().getLeaf();
if (parent.getKind() == BLOCK && grandparent.getKind() == METHOD && tryTree == getLastStatement((BlockTree) parent)) {
return fixWithReturn(tryTree, failStatement, state);
} else {
return fixWithBoolean(tryTree, failStatement, state);
}
}
use of com.sun.source.tree.StatementTree in project error-prone by google.
the class UBlank method apply.
@Override
public Choice<UnifierWithUnconsumedStatements> apply(final UnifierWithUnconsumedStatements state) {
int goodIndex = 0;
while (goodIndex < state.unconsumedStatements().size()) {
StatementTree stmt = state.unconsumedStatements().get(goodIndex);
if (firstNonNull(FORBIDDEN_REFERENCE_SCANNER.scan(stmt, state.unifier()), false) && ControlFlowVisitor.INSTANCE.visitStatement(stmt) == ControlFlowVisitor.Result.NEVER_EXITS) {
break;
} else {
goodIndex++;
}
}
Collection<Integer> breakPoints = ContiguousSet.create(Range.closed(0, goodIndex), DiscreteDomain.integers());
return Choice.from(breakPoints).transform((Integer k) -> {
Unifier unifier = state.unifier().fork();
unifier.putBinding(key(), state.unconsumedStatements().subList(0, k));
List<? extends StatementTree> remaining = state.unconsumedStatements().subList(k, state.unconsumedStatements().size());
return UnifierWithUnconsumedStatements.create(unifier, remaining);
});
}
use of com.sun.source.tree.StatementTree in project error-prone by google.
the class CatchFail method rethrowFix.
private Optional<Fix> rethrowFix(ImmutableList<CatchTree> catchBlocks, VisitorState state) {
SuggestedFix.Builder fix = SuggestedFix.builder();
catchBlocks.forEach(c -> {
// e.g.
// fail("message") -> throw new AssertionError("message", cause);
// assertWithMessage("message format %s", 42) ->
// throw new AssertionError(String.format("message format %s", 42), cause);
StatementTree statementTree = getOnlyElement(c.getBlock().getStatements());
MethodInvocationTree methodInvocationTree = (MethodInvocationTree) ((ExpressionStatementTree) statementTree).getExpression();
String message = null;
if (message == null && !methodInvocationTree.getArguments().isEmpty()) {
message = getMessageOrFormat(methodInvocationTree, state);
}
if (message != null) {
// only catch and rethrow to add additional context, not for raw `fail()` calls
fix.replace(statementTree, String.format("throw new AssertionError(%s, %s);", message, c.getParameter().getName()));
}
});
return fix.isEmpty() ? Optional.empty() : Optional.of(fix.build());
}
Aggregations