@Override public Boolean visitCatch(CatchTree tree, Stack<Tree> d) { TypeMirror type1 = info.getTrees().getTypeMirror(new TreePath(new TreePath(getCurrentPath(), tree.getParameter()), tree.getParameter().getType())); Types t = info.getTypes(); if (type1 != null) { Set<TypeMirror> toRemove = new HashSet<TypeMirror>(); Map<TypeMirror, List<Tree>> exceptions2Highlights = exceptions2HighlightsStack.peek(); if (exceptions2Highlights != null) { for (TypeMirror type2 : exceptions2Highlights.keySet()) { if (t.isAssignable(type2, type1)) { toRemove.add(type2); } } for (TypeMirror type : toRemove) { exceptions2Highlights.remove(type); } } } scan(tree.getParameter(), d); return scan(tree.getBlock(), d); }
@Override protected void performRewrite(TransformationContext ctx) { WorkingCopy wc = ctx.getWorkingCopy(); TreePath tp = ctx.getPath(); List<Tree> exceptions = new LinkedList<Tree>(); for (TypeMirrorHandle<TypeMirror> h : exceptionHandles) { TypeMirror tm = h.resolve(wc); if (tm == null) return ; //XXX: log exceptions.add(wc.getTreeMaker().Type(tm)); } VariableTree excVar = ((CatchTree) tp.getLeaf()).getParameter(); wc.rewrite(excVar.getType(), wc.getTreeMaker().UnionType(exceptions)); }
@Override public Void visitTry(TryTree node, Collection<TreePath> trees) { Set<TypeMirror> caught = new HashSet<TypeMirror>(); for (CatchTree ct : node.getCatches()) { TypeMirror t = info.getTrees().getTypeMirror(new TreePath(new TreePath(getCurrentPath(), ct), ct.getParameter())); if (t != null) { caught.add(t); } } caughtExceptions.push(caught); try { scan(node.getBlock(), trees); } finally { caughtExceptions.pop(); } scan(node.getFinallyBlock(), trees); return null; }
@Override protected void performRewrite(TransformationContext ctx) throws Exception { Tree t = ctx.getPath().getLeaf(); if (t.getKind() != Tree.Kind.CATCH) { // remove a clause from the multi-catch removeAlternativeFromMultiCatch(ctx); return; } CatchTree toRemove = (CatchTree)t; TryTree parent = (TryTree) ctx.getPath().getParentPath().getLeaf(); TreeMaker make = ctx.getWorkingCopy().getTreeMaker(); if (parent.getResources().isEmpty() && parent.getCatches().size() == 1) { List<StatementTree> repl = new ArrayList<>(); repl.addAll(parent.getBlock().getStatements()); if (parent.getFinallyBlock() != null) { repl.addAll(parent.getFinallyBlock().getStatements()); } Utilities.replaceStatement(ctx.getWorkingCopy(), ctx.getPath().getParentPath(), repl); } else { ctx.getWorkingCopy().rewrite(parent, make.removeTryCatch(parent, toRemove)); } }
private static CatchTree createCatch(WorkingCopy info, TreeMaker make, TreePath statement, String name, TypeMirror type) { StatementTree logStatement = createExceptionsStatement(info, make, name); if (logStatement == null) { logStatement = createLogStatement(info, make, statement, name); } if (logStatement == null) { logStatement = createRethrowAsRuntimeExceptionStatement(info, make, name); } if (logStatement == null) { logStatement = createRethrow(info, make, name); } if (logStatement == null) { logStatement = createPrintStackTraceStatement(info, make, name); } return make.Catch(make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), name, make.Type(type), null), make.Block(Collections.singletonList(logStatement), false)); }
@Override public Boolean visitTry(TryTree node, Void p) { Set<TypeMirror> caught = new HashSet<TypeMirror>(); for (CatchTree ct : node.getCatches()) { TypeMirror t = info.getTrees().getTypeMirror(new TreePath(new TreePath(getCurrentPath(), ct), ct.getParameter())); if (t != null) { caught.add(t); } } caughtExceptions.push(Pair.of(caught, node)); try { return scan(node.getBlock(), p) == Boolean.TRUE || scan(node.getFinallyBlock(), p) == Boolean.TRUE; } finally { caughtExceptions.pop(); } }
@Hint(displayName = "#DN_org.netbeans.modules.java.hints.AssignmentIssues.assignmentToCatchBlockParameter", description = "#DESC_org.netbeans.modules.java.hints.AssignmentIssues.assignmentToCatchBlockParameter", category = "assignment_issues", enabled = false, suppressWarnings = "AssignmentToCatchBlockParameter", options=Options.QUERY) //NOI18N @TriggerTreeKind(Kind.CATCH) public static List<ErrorDescription> assignmentToCatchBlockParameter(HintContext context) { final Trees trees = context.getInfo().getTrees(); final TreePath catchPath = context.getPath(); final Element param = trees.getElement(TreePath.getPath(catchPath, ((CatchTree) catchPath.getLeaf()).getParameter())); if (param == null || param.getKind() != ElementKind.EXCEPTION_PARAMETER) { return null; } final TreePath block = TreePath.getPath(catchPath, ((CatchTree) catchPath.getLeaf()).getBlock()); final List<TreePath> paths = new LinkedList<TreePath>(); new AssignmentFinder(trees, param).scan(block, paths); final List<ErrorDescription> ret = new ArrayList<ErrorDescription>(paths.size()); for (TreePath path : paths) { ret.add(ErrorDescriptionFactory.forTree(context, path, NbBundle.getMessage(AssignmentIssues.class, "MSG_AssignmentToCatchBlockParameter", param.getSimpleName()))); //NOI18N } return ret; }
/** * Helper method for {@link CatchTree}s. */ private void visitCatchClause(CatchTree node, AllowTrailingBlankLine allowTrailingBlankLine) { sync(node); builder.space(); token("catch"); builder.space(); token("("); builder.open(plusFour); VariableTree ex = node.getParameter(); if (ex.getType().getKind() == UNION_TYPE) { builder.open(ZERO); visitUnionType(ex); builder.close(); } else { // TODO(cushon): don't break after here for consistency with for, while, etc. builder.breakToFill(); builder.open(ZERO); scan(ex, null); builder.close(); } builder.close(); token(")"); builder.space(); visitBlock( node.getBlock(), CollapseEmptyOrNot.NO, AllowLeadingBlankLine.YES, allowTrailingBlankLine); }
@Override public Void visitCatch(CatchTree node, Void p) { TreePath param = new TreePath(getCurrentPath(), node.getParameter()); Element ex = trees.getElement(param); validateUnionTypeInfo(ex); if (ex.getSimpleName().contentEquals("ex")) { assertTrue(ex.getKind() == ElementKind.EXCEPTION_PARAMETER, "Expected EXCEPTION_PARAMETER - found " + ex.getKind()); for (Element e : types.asElement(trees.getLub(node)).getEnclosedElements()) { Member m = e.getAnnotation(Member.class); if (m != null) { assertTrue(e.getKind() == m.value(), "Expected " + m.value() + " - found " + e.getKind()); } } assertTrue(assertionCount == 9, "Expected 9 assertions - found " + assertionCount); } return super.visitCatch(node, p); }
@Override public Void visitTry(TryTree tryTree, List<ReformatOption> optionsToReformat) { addLeftBraceToList(optionsToReformat, tryTree.getBlock(), PreferencesFormatOptions.BRACES_IN_OTHER_DECLARATION); BlockTree finalBlock = tryTree.getFinallyBlock(); List<? extends CatchTree> catches = tryTree.getCatches(); if (finalBlock instanceof CompoundTree) { addLeftBraceToList(optionsToReformat, finalBlock, PreferencesFormatOptions.BRACES_IN_OTHER_DECLARATION); addRightBraceToList(optionsToReformat, (CompoundTree) finalBlock, PreferencesFormatOptions.AFTER_OTHER_DECLARATION); } else if (!catches.isEmpty()) { BlockTree catchBlock = catches.get(catches.size() - 1).getBlock(); addRightBraceToList(optionsToReformat, (CompoundTree) catchBlock, PreferencesFormatOptions.AFTER_OTHER_DECLARATION); } else { addRightBraceToList(optionsToReformat, (CompoundTree) tryTree.getBlock(), PreferencesFormatOptions.AFTER_OTHER_DECLARATION); } return null; }
@Test public void testVisitCatch() throws ParseException, BadLocationException, IOException { List<ReformatOption> optionsToReformat = new ArrayList<>(); CompilationUnitTree unit = getCompilationUnitTree(INPUT_FILE); MethodTree methodTree = TreeNavigationUtils.findMethodTreeByName("doSomething", unit).get(0); TryTree tryTree = (TryTree) getStatementTreeByClassName(TryTree.class, methodTree); if (tryTree == null) { fail(ERROR_MESSAGE); } CatchTree catchTree = tryTree.getCatches().get(0); ReformatTreeVisitor reformatTreeVisitor = getReformatTreeVisitor(INPUT_FILE); reformatTreeVisitor.visitCatch(catchTree, optionsToReformat); assertFalse(optionsToReformat.isEmpty()); }
@Test public void testVisitCatchNotReformat() throws ParseException, BadLocationException, IOException { List<ReformatOption> optionsToReformat = new ArrayList<>(); CompilationUnitTree unit = getCompilationUnitTree(INPUT_FILE); MethodTree methodTree = TreeNavigationUtils.findMethodTreeByName("doSomething", unit).get(0); TryTree tryTree = (TryTree) getStatementTreeByClassName(TryTree.class, methodTree); if (tryTree == null) { fail(ERROR_MESSAGE); } CatchTree catchTree = tryTree.getCatches().get(0); ReformatTreeVisitor reformatTreeVisitor = getReformatTreeVisitor(INPUT_FILE, 10, 20); reformatTreeVisitor.visitCatch(catchTree, optionsToReformat); assertTrue(optionsToReformat.isEmpty()); }
@Override public Description matchTry(TryTree tree, VisitorState state) { if (tree.getCatches().isEmpty()) { return NO_MATCH; } // Find catch blocks that contain only a call to fail, and that ignore the caught exception. ImmutableList<CatchTree> catchBlocks = tree.getCatches() .stream() .filter( c -> c.getBlock().getStatements().size() == 1 && FAIL_METHOD.matches(getOnlyElement(c.getBlock().getStatements()), state)) .filter(c -> !catchVariableIsUsed(c)) .collect(toImmutableList()); if (catchBlocks.isEmpty()) { return NO_MATCH; } Description.Builder description = buildDescription(tree); rethrowFix(catchBlocks, state).ifPresent(description::addFix); deleteFix(tree, catchBlocks, state).ifPresent(description::addFix); return description.build(); }
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()); }
private boolean catchVariableIsUsed(CatchTree c) { VarSymbol sym = ASTHelpers.getSymbol(c.getParameter()); boolean[] found = {false}; c.getBlock() .accept( new TreeScanner<Void, Void>() { @Override public Void visitIdentifier(IdentifierTree node, Void aVoid) { if (Objects.equals(sym, ASTHelpers.getSymbol(node))) { found[0] = true; } return super.visitIdentifier(node, aVoid); } }, null); return found[0]; }
/** Return whether the given try-tree will catch the given exception type. */ private boolean tryCatchesException(TryTree tryTree, Type exceptionToCatch, VisitorState state) { Types types = state.getTypes(); return tryTree .getCatches() .stream() .anyMatch( (CatchTree catchClause) -> { Type catchesException = getType(catchClause.getParameter().getType()); // Examine all alternative types of a union type. if (catchesException != null && catchesException.isUnion()) { return Streams.stream(((UnionClassType) catchesException).getAlternativeTypes()) .anyMatch(caught -> types.isSuperType(caught, exceptionToCatch)); } // Simple type, just check superclass. return types.isSuperType(catchesException, exceptionToCatch); }); }
@Override public Description matchTry (TryTree tree, VisitorState state) { List<? extends CatchTree> catchList = tree.getCatches(); if (catchList == null || catchList.size() == 0) { // TODO: this try block does not have a catch, we should further check the // finally block! return Description.NO_MATCH; } CatchTree lastCatch = catchList.get(tree.getCatches().size() - 1); if (overcatch(lastCatch, state)) { if (abortInCatch(lastCatch, state)) { LineMap lineMap = state.getPath().getCompilationUnit().getLineMap(); /* System.out.println("****** warning starts **************"); System.out.println("WARNING: abort in overcatch: " + state.getPath().getCompilationUnit().getSourceFile().getName() + ":" + lineMap.getLineNumber(TreeInfo.getStartPos((JCTree) lastCatch))); System.out.println(state.getPath().getLeaf()); System.out.println("****** warning ends **************"); System.out.println(); */ return describeMatch(lastCatch, NO_FIX); } } return Description.NO_MATCH; }
private boolean abortInCatch(CatchTree catchTree, VisitorState state) { List<? extends StatementTree> statements = catchTree.getBlock().getStatements(); if (statements.isEmpty()) { return false; } StatementTree lastStmt = statements.get(statements.size() - 1); if (lastStmt.getKind() == EXPRESSION_STATEMENT) { ExpressionTree et = ((ExpressionStatementTree) lastStmt).getExpression(); Symbol sym = ASTHelpers.getSymbol(et); if (sym == null || !(sym instanceof MethodSymbol)) { return false; } String methodName = sym.getQualifiedName().toString(); String className = sym.owner.getQualifiedName().toString(); // System.out.println("DEBUG: method: " + methodName + ", className: " + className); if (methodName.contains("abort") || methodName.contains("shutdown") || (methodName.equals("exit") && className.equals("java.lang.System"))) { return true; } } return false; }
@Override public Description matchTry (TryTree tree, VisitorState state) { if (badEmptyCatchBlock(tree, state)) { // If it has finally block, assume it's OK BlockTree bt = tree.getFinallyBlock(); if (bt == null || bt.getStatements().size() == 0) { CatchTree lastCatch = tree.getCatches().get(tree.getCatches().size() - 1); LineMap lineMap = state.getPath().getCompilationUnit().getLineMap(); /* System.out.println("****** warning starts **************"); System.out.println("WARNING: empty catch: " + state.getPath().getCompilationUnit().getSourceFile().getName() // + ":" + state.getEndPosition((JCTree) tree) + ":" + lineMap.getLineNumber(TreeInfo.getStartPos((JCTree) lastCatch))); System.out.println(state.getPath().getLeaf()); System.out.println(); System.out.println("****** warning ends **************"); */ return describeMatch(lastCatch, NO_FIX); } } return Description.NO_MATCH; }
private boolean exceptionWhitelisted (CatchTree catchTree, VisitorState state) { /* We further check the exception type, and ignore these exceptions. */ String caughtException = catchTree.getParameter().toString(); boolean canBeIgnored = false; for (String harmlessExp : harmlessExceptions) { if (caughtException.contains(harmlessExp)) { canBeIgnored = true; break; } } if (canBeIgnored) { // System.out.println("DEBUG: found empty handler for an harmless exception: " + caughtException); return true; } // System.out.println("DEBUG: catchType = " + caughtException); return false; }
private boolean isCatchEmpty(CatchTree catchTree, VisitorState state) { List<? extends StatementTree> statements = catchTree.getBlock().getStatements(); if (statements.isEmpty()) { // System.out.println("DEBUG: found an purely empty catch block " + catchTree); return true; } for (StatementTree stmt : statements) { // System.out.println("DEBUG: statement in catch: " + stmt + ", kind: " + stmt.getKind()); if (isLoggingStmt(stmt, state)) { // System.out.println("DEBUG: logging statement: " + stmt); continue; } else if (stmt.getKind() == EMPTY_STATEMENT) { continue; } // if we falls to here, it means that this statement is neither a logging // stmt or an empty one, therefore, it's a meaningful stmt! // System.out.println("DEBUG: statement: " + stmt + " is a meaningful stmt!"); return false; } // We didn't return from the loop body above, so this is an empty // catch block or only contains logging stmt! return true; }
@Override public Tree visitCatch(CatchTree tree, Void p) { CatchTree n = make.Catch(tree.getParameter(), tree.getBlock()); model.setType(n, model.getType(tree)); comments.copyComments(tree, n); model.setPos(n, model.getPos(tree)); return n; }
public Boolean visitCatch(CatchTree node, TreePath p) { if (p == null) { super.visitCatch(node, p); return false; } CatchTree ef = (CatchTree) p.getLeaf(); if (!scan(node.getParameter(), ef.getParameter(), p)) return false; return scan(node.getBlock(), ef.getBlock(), p); }
@Override public Number visitTry(TryTree node, Void p) { List<? extends Tree> resources = (List<? extends Tree>) resolveMultiParameters(node.getResources()); List<? extends CatchTree> catches = (List<? extends CatchTree>) resolveMultiParameters(node.getCatches()); TryTree nue = make.Try(resources, node.getBlock(), catches, node.getFinallyBlock()); rewrite(node, nue); return super.visitTry(node, p); }
@Override public Void visitCatch(CatchTree tree, List<Node> d) { List<Node> below = new ArrayList<Node>(); addCorrespondingType(below); addCorrespondingComments(below); super.visitCatch(tree, below); d.add(new TreeNode(info, getCurrentPath(), below)); return null; }
@Override protected void performRewrite(TransformationContext ctx) { WorkingCopy wc = ctx.getWorkingCopy(); TreePath tp = ctx.getPath(); List<Tree> disjointTypes = new LinkedList<Tree>(); TryTree tt = (TryTree) tp.getLeaf(); int first = duplicates.get(0); List<Integer> remainingDuplicates = duplicates.subList(1, duplicates.size()); addDisjointType(disjointTypes, tt.getCatches().get(first).getParameter().getType()); for (Integer d : remainingDuplicates) { addDisjointType(disjointTypes, tt.getCatches().get((int) d).getParameter().getType()); } List<CatchTree> newCatches = new LinkedList<CatchTree>(); int c = 0; for (CatchTree ct : tt.getCatches()) { if (c == first) { wc.rewrite(ct.getParameter().getType(), wc.getTreeMaker().UnionType(disjointTypes)); } if (remainingDuplicates.contains(c++)) continue; newCatches.add(ct); } TryTree nue = wc.getTreeMaker().Try(tt.getResources(), tt.getBlock(), newCatches, tt.getFinallyBlock()); wc.rewrite(tt, nue); }
@Override protected void performRewrite(JavaFix.TransformationContext ctx) throws Exception { CatchTree oldTree = (CatchTree)ctx.getPath().getLeaf(); TryTree oldTry = (TryTree)ctx.getPath().getParentPath().getLeaf(); WorkingCopy wcopy = ctx.getWorkingCopy(); GeneratorUtilities gen = GeneratorUtilities.get(wcopy); TreeMaker mk = wcopy.getTreeMaker(); int index = oldTry.getCatches().indexOf(oldTree); TryTree result = mk.removeTryCatch(oldTry, index); for (TypeMirrorHandle h : newTypes) { TypeMirror m = h.resolve(wcopy); if (m == null || m.getKind() != TypeKind.DECLARED) { continue; } CatchTree branch = mk.Catch( mk.Variable( oldTree.getParameter().getModifiers(), oldTree.getParameter().getName(), mk.Type(m), oldTree.getParameter().getInitializer()), oldTree.getBlock()); gen.copyComments(oldTree, branch, true); result = mk.insertTryCatch(result, index++, branch); } wcopy.rewrite(oldTry, result); }
@Override protected void performRewrite(TransformationContext ctx) throws Exception { CatchTree oldTree = (CatchTree)ctx.getPath().getLeaf(); WorkingCopy wcopy = ctx.getWorkingCopy(); Tree varType = oldTree.getParameter().getType(); Tree newVarType = wcopy.getTreeMaker().Type(newCatchType.resolve(wcopy)); wcopy.rewrite(varType, newVarType); }
@Override protected void performRewrite(TransformationContext ctx) { WorkingCopy wc = ctx.getWorkingCopy(); final TreeMaker tm = wc.getTreeMaker(); TreePath tp = ctx.getPath(); final BlockTree oldBody = ((MethodTree)tp.getLeaf()).getBody(); if (oldBody == null) { return; } final List<StatementTree> newStatements = new ArrayList<StatementTree>(2); BlockTree superFinalize = tm.Block( Collections.singletonList( tm.ExpressionStatement( tm.MethodInvocation(Collections.<ExpressionTree>emptyList(), tm.MemberSelect( tm.Identifier(SUPER), FINALIZE), Collections.<ExpressionTree>emptyList()))), false); if (oldBody.getStatements().isEmpty()) { wc.rewrite(oldBody, superFinalize); } else { TryTree soleTry = soleTryWithoutFinally(oldBody); if (soleTry != null) { wc.rewrite(soleTry, tm.Try(soleTry.getBlock(), soleTry.getCatches(), superFinalize)); } else { wc.rewrite(oldBody, tm.Block(Collections.singletonList(tm.Try(oldBody, Collections.<CatchTree>emptyList(), superFinalize)), false)); } } }
public Boolean visitCatch(CatchTree node, ConstructorData p) { inParameters = true; scan(node.getParameter(), p); inParameters = false; scan(node.getBlock(), p); return null; }