@Override public ExpressionTree visitExpressionStatement( ExpressionStatementTree tree, Void unused) { return tree.getExpression(); }
@Override public Description visitExpressionStatement(ExpressionStatementTree node, Void aVoid) { return node.getExpression().accept(this, null); } }
@Override public boolean matches(StatementTree statementTree, VisitorState state) { return statementTree instanceof ExpressionStatementTree && matcher.matches(((ExpressionStatementTree) statementTree).getExpression(), state); } };
@Override public MethodInvocationTree visitExpressionStatement( ExpressionStatementTree expressionStatement, Void unused) { return visit(expressionStatement.getExpression(), null); }
private static Optional<Symbol> returnUnarySym(StatementTree s) { if (s instanceof ExpressionStatementTree) { if (((ExpressionStatementTree) s).getExpression() instanceof UnaryTree) { UnaryTree unaryTree = (UnaryTree) ((ExpressionStatementTree) s).getExpression(); return Optional.ofNullable(ASTHelpers.getSymbol(unaryTree.getExpression())); } } return Optional.empty(); } }
@Override public Boolean visitExpressionStatement(ExpressionStatementTree node, VisitorState state) { return node.getExpression().accept(this, state); }
@Override public Boolean visitExpressionStatement(ExpressionStatementTree tree, Void unused) { if (isSystemExit(tree.getExpression())) { // The spec doesn't have any special handling for {@code System.exit}, but in practice it // cannot complete normally return false; } return true; }
@Override public Boolean visitExpressionStatement(ExpressionStatementTree tree, Void unused) { return scan(tree.getExpression(), null); }
@Override @Nullable public Choice<Unifier> visitExpressionStatement( ExpressionStatementTree expressionStatement, @Nullable Unifier unifier) { return getExpression().unify(expressionStatement.getExpression(), unifier); }
@Override public UStatement visitExpressionStatement(ExpressionStatementTree tree, Void v) { PlaceholderMethod placeholderMethod = placeholder(tree.getExpression()); if (placeholderMethod != null && placeholderMethod.returnType().equals(UPrimitiveType.VOID)) { MethodInvocationTree invocation = (MethodInvocationTree) tree.getExpression(); return UPlaceholderStatement.create( placeholderMethod, templateExpressions(invocation.getArguments()), ControlFlowVisitor.Result.NEVER_EXITS); } return UExpressionStatement.create(template(tree.getExpression())); }
protected static SuggestedFix buildFix( VisitorState state, SuggestedFix.Builder fix, JCExpression expectedException, List<? extends StatementTree> statements) { fix.addStaticImport("org.junit.Assert.assertThrows"); StringBuilder prefix = new StringBuilder(); prefix.append( String.format("assertThrows(%s, () -> ", state.getSourceForNode(expectedException))); if (statements.size() == 1 && getOnlyElement(statements) instanceof ExpressionStatementTree) { ExpressionTree expression = ((ExpressionStatementTree) getOnlyElement(statements)).getExpression(); fix.prefixWith(expression, prefix.toString()); fix.postfixWith(expression, ")"); } else if (!statements.isEmpty()) { prefix.append(" {"); fix.prefixWith(statements.iterator().next(), prefix.toString()); fix.postfixWith(getLast(statements), "});"); } return fix.build(); }
private static boolean invokedConstructorMustBeClosed(VisitorState state, MethodTree methodTree) { // The first statement in a constructor should be an invocation of the super/this constructor. List<? extends StatementTree> statements = methodTree.getBody().getStatements(); if (statements.isEmpty()) { // Not sure how the body would be empty, but just filter it out in case. return false; } ExpressionStatementTree est = (ExpressionStatementTree) statements.get(0); MethodInvocationTree mit = (MethodInvocationTree) est.getExpression(); MethodSymbol invokedConstructorSymbol = ASTHelpers.getSymbol(mit); return ASTHelpers.hasAnnotation(invokedConstructorSymbol, MustBeClosed.class, state); } }
public Fix build(List<? extends StatementTree> throwingStatements) { if (throwingStatements.isEmpty()) { return baseFix; } SuggestedFix.Builder fix = SuggestedFix.builder().merge(baseFix); fix.addStaticImport("org.junit.Assert.assertThrows"); StringBuilder fixPrefix = new StringBuilder(); if (!newAsserts.isEmpty()) { fixPrefix.append(String.format("%s thrown = ", exceptionClassName)); } fixPrefix.append("assertThrows"); fixPrefix.append(String.format("(%s, () -> ", exceptionClassExpr)); boolean useExpressionLambda = throwingStatements.size() == 1 && getOnlyElement(throwingStatements).getKind() == Kind.EXPRESSION_STATEMENT; if (!useExpressionLambda) { fixPrefix.append("{"); } fix.prefixWith(throwingStatements.get(0), fixPrefix.toString()); if (useExpressionLambda) { fix.postfixWith(((ExpressionStatementTree) throwingStatements.get(0)).getExpression(), ")"); fix.postfixWith(getLast(throwingStatements), '\n' + Joiner.on('\n').join(newAsserts)); } else { fix.postfixWith(getLast(throwingStatements), "});\n" + Joiner.on('\n').join(newAsserts)); } return fix.build(); } }
@Override public Choice<State<JCExpressionStatement>> visitExpressionStatement( ExpressionStatementTree node, State<?> state) { return chooseSubtrees(state, s -> unifyExpression(node.getExpression(), s), maker()::Exec); }
@Override public Description matchForLoop(ForLoopTree forLoopTree, VisitorState visitorState) { List<? extends ExpressionStatementTree> updates = forLoopTree.getUpdate(); // keep track of all the symbols that are updated in the for loop header final Set<Symbol> incrementedSymbols = updates.stream() .filter(expStateTree -> expStateTree.getExpression() instanceof UnaryTree) .map( expStateTree -> ASTHelpers.getSymbol( ((UnaryTree) expStateTree.getExpression()).getExpression())) .collect(Collectors.toCollection(HashSet::new)); // track if they are updated in the body without a conditional surrounding them StatementTree body = forLoopTree.getStatement(); List<? extends StatementTree> statementTrees = body instanceof BlockTree ? ((BlockTree) body).getStatements() : ImmutableList.of(body); for (StatementTree s : statementTrees) { if (!CONDITIONALS.contains(s.getKind())) { Optional<Symbol> opSymbol = returnUnarySym(s); if (opSymbol.isPresent() && incrementedSymbols.contains(opSymbol.get())) { // both ++ and -- return describeMatch(forLoopTree); } } } return Description.NO_MATCH; }
private static String getMessageSnippet( StatementTree failStatement, VisitorState state, HasOtherParameters hasOtherParameters) { ExpressionTree expression = ((ExpressionStatementTree) failStatement).getExpression(); MethodSymbol sym = (MethodSymbol) getSymbol(expression); String tail = hasOtherParameters == HasOtherParameters.TRUE ? ", " : ""; // The above casts were checked earlier by failOrAssert. return hasInitialStringParameter(sym, state) ? state.getSourceForNode(((MethodInvocationTree) expression).getArguments().get(0)) + tail : ""; }
private Symbol.MethodSymbol getSymbolOfSuperConstructor( Symbol.MethodSymbol anonClassConstructorSymbol, VisitorState state) { // get the statements in the body of the anonymous class constructor List<? extends StatementTree> statements = getTreesInstance(state).getTree(anonClassConstructorSymbol).getBody().getStatements(); // there should be exactly one statement, which is an invocation of the super constructor if (statements.size() == 1) { StatementTree stmt = statements.get(0); if (stmt instanceof ExpressionStatementTree) { ExpressionTree expression = ((ExpressionStatementTree) stmt).getExpression(); if (expression instanceof MethodInvocationTree) { return ASTHelpers.getSymbol((MethodInvocationTree) expression); } } } throw new IllegalStateException("unexpected anonymous class constructor body " + statements); }
private boolean isThisCall(StatementTree statementTree, VisitorState state) { if (statementTree.getKind().equals(EXPRESSION_STATEMENT)) { ExpressionTree expression = ((ExpressionStatementTree) statementTree).getExpression(); return Matchers.methodInvocation(THIS_MATCHER).matches(expression, state); } return false; }
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()); }
fix.replace(body, state.getSourceForNode(((ExpressionStatementTree) last).getExpression())); } else { fix.replace(startPosition, endPosition, "");