下面列出了com.sun.source.tree.TryTree#getFinallyBlock ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@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));
}
}
static TreePath enclosingTry(TreePath from) {
TreePath tryPath = from;
while (tryPath != null
&& tryPath.getLeaf().getKind() != Kind.TRY
&& !TreeUtilities.CLASS_TREE_KINDS.contains(tryPath.getLeaf().getKind())
&& tryPath.getLeaf().getKind() != Kind.CATCH
&& tryPath.getLeaf().getKind() != Kind.LAMBDA_EXPRESSION)
tryPath = tryPath.getParentPath();
if (tryPath.getLeaf().getKind() == Kind.TRY) {
TryTree tt = (TryTree) tryPath.getLeaf();
//#104085: if the statement to be wrapped is inside a finally block of the try-catch,
//do not attempt to extend existing catches...:
for (Tree t : from) {
if (tt.getFinallyBlock() == t) {
return null;
}
}
return tryPath;
}
return null;
}
private TryTree soleTryWithoutFinally(BlockTree block) {
if (block.getStatements().size() != 1) return null;
StatementTree first = block.getStatements().get(0);
if (first.getKind() != Kind.TRY) return null;
TryTree tt = (TryTree) first;
if (tt.getFinallyBlock() != null) return null;
return tt;
}
/**
* @param blockTree block of statements
* @param state visitor state
* @return Elements of safe init methods that are invoked as top-level statements in the method
*/
private Set<Element> getSafeInitMethods(
BlockTree blockTree, Symbol.ClassSymbol classSymbol, VisitorState state) {
Set<Element> result = new LinkedHashSet<>();
List<? extends StatementTree> statements = blockTree.getStatements();
for (StatementTree stmt : statements) {
Element privMethodElem = getInvokeOfSafeInitMethod(stmt, classSymbol, state);
if (privMethodElem != null) {
result.add(privMethodElem);
}
// Hack: If we see a try{...}finally{...} statement, without a catch, we consider the methods
// inside both blocks
// as "top level" for the purposes of finding initialization methods. Any exception happening
// there is also an
// exception of the full method.
if (stmt.getKind().equals(Tree.Kind.TRY)) {
TryTree tryTree = (TryTree) stmt;
if (tryTree.getCatches().size() == 0) {
if (tryTree.getBlock() != null) {
result.addAll(getSafeInitMethods(tryTree.getBlock(), classSymbol, state));
}
if (tryTree.getFinallyBlock() != null) {
result.addAll(getSafeInitMethods(tryTree.getFinallyBlock(), classSymbol, state));
}
}
}
}
return result;
}
@Override
public Void visitTry(TryTree node, Void unused) {
sync(node);
builder.open(ZERO);
token("try");
builder.space();
if (!node.getResources().isEmpty()) {
token("(");
builder.open(node.getResources().size() > 1 ? plusFour : ZERO);
boolean first = true;
for (Tree resource : node.getResources()) {
if (!first) {
builder.forcedBreak();
}
VariableTree variableTree = (VariableTree) resource;
declareOne(
DeclarationKind.PARAMETER,
fieldAnnotationDirection(variableTree.getModifiers()),
Optional.of(variableTree.getModifiers()),
variableTree.getType(),
VarArgsOrNot.NO,
ImmutableList.<AnnotationTree>of(),
variableTree.getName(),
"",
"=",
Optional.fromNullable(variableTree.getInitializer()),
Optional.<String>absent(),
Optional.<ExpressionTree>absent(),
Optional.<TypeWithDims>absent());
if (builder.peekToken().equals(Optional.of(";"))) {
token(";");
builder.space();
}
first = false;
}
if (builder.peekToken().equals(Optional.of(";"))) {
token(";");
builder.space();
}
token(")");
builder.close();
builder.space();
}
// An empty try-with-resources body can collapse to "{}" if there are no trailing catch or
// finally blocks.
boolean trailingClauses = !node.getCatches().isEmpty() || node.getFinallyBlock() != null;
visitBlock(
node.getBlock(),
CollapseEmptyOrNot.valueOf(!trailingClauses),
AllowLeadingBlankLine.YES,
AllowTrailingBlankLine.valueOf(trailingClauses));
for (int i = 0; i < node.getCatches().size(); i++) {
CatchTree catchClause = node.getCatches().get(i);
trailingClauses = i < node.getCatches().size() - 1 || node.getFinallyBlock() != null;
visitCatchClause(catchClause, AllowTrailingBlankLine.valueOf(trailingClauses));
}
if (node.getFinallyBlock() != null) {
builder.space();
token("finally");
builder.space();
visitBlock(
node.getFinallyBlock(),
CollapseEmptyOrNot.NO,
AllowLeadingBlankLine.YES,
AllowTrailingBlankLine.NO);
}
builder.close();
return null;
}
public @Override Void visitTry(TryTree tt, Void p) {
List<CatchTree> catches = new ArrayList<CatchTree>();
catches.addAll(tt.getCatches());
catches.addAll(createCatches(info, make, thandles, statement));
if (!streamAlike) {
info.rewrite(tt, make.Try(tt.getResources(), tt.getBlock(), catches, tt.getFinallyBlock()));
} else {
VariableTree originalDeclaration = (VariableTree) statement.getLeaf();
VariableTree declaration = make.Variable(make.Modifiers(EnumSet.noneOf(Modifier.class)), originalDeclaration.getName(), originalDeclaration.getType(), make.Literal(null));
StatementTree assignment = make.ExpressionStatement(make.Assignment(make.Identifier(originalDeclaration.getName()), originalDeclaration.getInitializer()));
List<StatementTree> finallyStatements = new ArrayList<StatementTree>(tt.getFinallyBlock() != null ? tt.getFinallyBlock().getStatements() : Collections.<StatementTree>emptyList());
finallyStatements.add(createFinallyCloseBlockStatement(originalDeclaration));
BlockTree finallyTree = make.Block(finallyStatements, false);
info.rewrite(originalDeclaration, assignment);
TryTree nueTry = make.Try(tt.getResources(), tt.getBlock(), catches, finallyTree);
TreePath currentBlockCandidate = statement;
while (currentBlockCandidate.getLeaf() != tt) {
currentBlockCandidate = currentBlockCandidate.getParentPath();
}
currentBlockCandidate = currentBlockCandidate.getParentPath();
if (currentBlockCandidate.getLeaf().getKind() == Kind.BLOCK) {
BlockTree originalTree = (BlockTree) currentBlockCandidate.getLeaf();
List<StatementTree> statements = new ArrayList<StatementTree>(originalTree.getStatements());
int index = statements.indexOf(tt);
statements.remove(index);
statements.add(index, nueTry);
statements.add(index, declaration);
info.rewrite(originalTree, make.Block(statements, originalTree.isStatic()));
} else {
BlockTree nueBlock = make.Block(Arrays.asList(declaration, nueTry), false);
info.rewrite(tt, nueBlock);
}
}
return null;
}
@TriggerPatterns({
@TriggerPattern(value="$lock.lock(); $otherStats$; try { $statements$; $lock.unlock(); $rest$; } catch $catches$ finally { $finstats$; } ",
[email protected](variable="$lock", type="java.util.concurrent.locks.Lock")),
@TriggerPattern(value="$lock.lock(); $otherStats$; try { $statements$; $lock.unlock(); $rest$; } catch $catches$",
[email protected](variable="$lock", type="java.util.concurrent.locks.Lock")),
@TriggerPattern(value="$lock.lock(); $otherStats$; try { $statements$; } catch $catches$ catch($excType $var) { $catchStats1$; $lock.unlock(); $catchStats2$; } catch $catches2$ finally { $finstmts$; }",
[email protected](variable="$lock", type="java.util.concurrent.locks.Lock")),
})
@NbBundle.Messages({
"ERR_UnlockOutsideTryFinally=Lock.lock() not unlocked in finally",
"FIX_UnlockOutsideTryFinally=Wrap by try-finally",
"MSG_ExtraUnlock=Extra unlock() call; lock is already released in finally"
})
public static ErrorDescription unlockInsideTry(HintContext ctx) {
TreePath fin = ctx.getVariables().get("$lock$1");
if (fin == null) {
return null;
}
TreePath parent = fin.getParentPath();
if (parent.getLeaf().getKind() != Tree.Kind.MEMBER_SELECT) {
return null;
}
parent = parent.getParentPath();
if (parent == null || parent.getLeaf().getKind() != Tree.Kind.METHOD_INVOCATION) {
return null;
}
TreePath tPath = parent.getParentPath();
while (tPath != null && tPath.getLeaf().getKind() != Tree.Kind.TRY) {
if (tPath.getLeaf().getKind() == Tree.Kind.METHOD ||
tPath.getLeaf().getKind() == Tree.Kind.CLASS) {
return null;
}
tPath = tPath.getParentPath();
}
if (tPath == null) {
return null;
}
TryTree tt = (TryTree)tPath.getLeaf();
Fix f = null;
String displayName = null;
if (tt.getFinallyBlock() != null) {
TreePath finBlockPath = new TreePath(tPath, tt.getFinallyBlock());
Collection<? extends Occurrence> occ = Matcher.create(ctx.getInfo()).
setSearchRoot(finBlockPath).
match(
Pattern.createSimplePattern(parent)
);
if (!occ.isEmpty()) {
f = new MoveUnlockFix(
TreePathHandle.create(parent, ctx.getInfo()),
null).toEditorFix();
displayName = Bundle.MSG_ExtraUnlock();
}
}
if (f == null) {
displayName = Bundle.ERR_UnlockOutsideTryFinally();
f = new MoveUnlockFix(
TreePathHandle.create(parent, ctx.getInfo()),
TreePathHandle.create(tPath, ctx.getInfo())).toEditorFix();
}
return ErrorDescriptionFactory.forName(ctx, parent, displayName, f);
}
/**
* computes those fields always initialized by callee safe init methods before a read operation
* (pathToRead) is invoked. See <a
* href="https://github.com/uber/NullAway/wiki/Error-Messages#initializer-method-does-not-guarantee-nonnull-field-is-initialized--nonnull-field--not-initialized">the
* docs</a> for what is considered a safe initializer method.
*/
private ImmutableSet<Element> safeInitByCalleeBefore(
TreePath pathToRead, VisitorState state, TreePath enclosingBlockPath) {
Set<Element> safeInitMethods = new LinkedHashSet<>();
Tree enclosingBlockOrMethod = enclosingBlockPath.getLeaf();
if (enclosingBlockOrMethod instanceof VariableTree) {
return ImmutableSet.of();
}
ImmutableSet.Builder<Element> resultBuilder = ImmutableSet.builder();
BlockTree blockTree =
enclosingBlockOrMethod instanceof BlockTree
? (BlockTree) enclosingBlockOrMethod
: ((MethodTree) enclosingBlockOrMethod).getBody();
List<? extends StatementTree> statements = blockTree.getStatements();
Tree readExprTree = pathToRead.getLeaf();
int readStartPos = getStartPos((JCTree) readExprTree);
TreePath classTreePath = enclosingBlockPath;
// look for the parent ClassTree node, which represents the enclosing class / enum / interface
while (!(classTreePath.getLeaf() instanceof ClassTree)) {
classTreePath = classTreePath.getParentPath();
if (classTreePath == null) {
throw new IllegalStateException(
"could not find enclosing class / enum / interface for "
+ state.getSourceForNode(enclosingBlockPath.getLeaf()));
}
}
Symbol.ClassSymbol classSymbol = ASTHelpers.getSymbol((ClassTree) classTreePath.getLeaf());
for (int i = 0; i < statements.size(); i++) {
StatementTree curStmt = statements.get(i);
if (getStartPos((JCTree) curStmt) <= readStartPos) {
Element privMethodElem = getInvokeOfSafeInitMethod(curStmt, classSymbol, state);
if (privMethodElem != null) {
safeInitMethods.add(privMethodElem);
}
// Hack: Handling try{...}finally{...} statement, see getSafeInitMethods
if (curStmt.getKind().equals(Tree.Kind.TRY)) {
TryTree tryTree = (TryTree) curStmt;
// ToDo: Should we check initialization inside tryTree.getResources ? What is the scope of
// that initialization?
if (tryTree.getCatches().size() == 0) {
if (tryTree.getBlock() != null) {
resultBuilder.addAll(
safeInitByCalleeBefore(
pathToRead, state, new TreePath(enclosingBlockPath, tryTree.getBlock())));
}
if (tryTree.getFinallyBlock() != null) {
resultBuilder.addAll(
safeInitByCalleeBefore(
pathToRead,
state,
new TreePath(enclosingBlockPath, tryTree.getFinallyBlock())));
}
}
}
}
}
addGuaranteedNonNullFromInvokes(
state, getTreesInstance(state), safeInitMethods, getNullnessAnalysis(state), resultBuilder);
return resultBuilder.build();
}
@Override
public Void visitTry(TryTree node, Void unused) {
sync(node);
builder.open(ZERO);
token("try");
builder.space();
if (!node.getResources().isEmpty()) {
token("(");
builder.open(node.getResources().size() > 1 ? plusFour : ZERO);
boolean first = true;
for (Tree resource : node.getResources()) {
if (!first) {
builder.forcedBreak();
}
VariableTree variableTree = (VariableTree) resource;
declareOne(
DeclarationKind.PARAMETER,
fieldAnnotationDirection(variableTree.getModifiers()),
Optional.of(variableTree.getModifiers()),
variableTree.getType(),
VarArgsOrNot.NO,
ImmutableList.<AnnotationTree>of(),
variableTree.getName(),
"",
"=",
Optional.fromNullable(variableTree.getInitializer()),
Optional.<String>absent(),
Optional.<ExpressionTree>absent(),
Optional.<TypeWithDims>absent());
if (builder.peekToken().equals(Optional.of(";"))) {
token(";");
builder.space();
}
first = false;
}
if (builder.peekToken().equals(Optional.of(";"))) {
token(";");
builder.space();
}
token(")");
builder.close();
builder.space();
}
// An empty try-with-resources body can collapse to "{}" if there are no trailing catch or
// finally blocks.
boolean trailingClauses = !node.getCatches().isEmpty() || node.getFinallyBlock() != null;
visitBlock(
node.getBlock(),
CollapseEmptyOrNot.valueOf(!trailingClauses),
AllowLeadingBlankLine.YES,
AllowTrailingBlankLine.valueOf(trailingClauses));
for (int i = 0; i < node.getCatches().size(); i++) {
CatchTree catchClause = node.getCatches().get(i);
trailingClauses = i < node.getCatches().size() - 1 || node.getFinallyBlock() != null;
visitCatchClause(catchClause, AllowTrailingBlankLine.valueOf(trailingClauses));
}
if (node.getFinallyBlock() != null) {
builder.space();
token("finally");
builder.space();
visitBlock(
node.getFinallyBlock(),
CollapseEmptyOrNot.NO,
AllowLeadingBlankLine.YES,
AllowTrailingBlankLine.NO);
}
builder.close();
return null;
}
@Override
public Void visitTry(TryTree node, Void unused) {
sync(node);
builder.open(ZERO);
token("try");
builder.space();
if (!node.getResources().isEmpty()) {
token("(");
builder.open(node.getResources().size() > 1 ? plusFour : ZERO);
boolean first = true;
for (Tree resource : node.getResources()) {
if (!first) {
builder.forcedBreak();
}
if (resource instanceof VariableTree) {
VariableTree variableTree = (VariableTree) resource;
declareOne(
DeclarationKind.PARAMETER,
fieldAnnotationDirection(variableTree.getModifiers()),
Optional.of(variableTree.getModifiers()),
variableTree.getType(),
/* name= */ variableTree.getName(),
"",
"=",
Optional.ofNullable(variableTree.getInitializer()),
/* trailing= */ Optional.empty(),
/* receiverExpression= */ Optional.empty(),
/* typeWithDims= */ Optional.empty());
} else {
// TODO(cushon): think harder about what to do with `try (resource1; resource2) {}`
scan(resource, null);
}
if (builder.peekToken().equals(Optional.of(";"))) {
token(";");
builder.space();
}
first = false;
}
if (builder.peekToken().equals(Optional.of(";"))) {
token(";");
builder.space();
}
token(")");
builder.close();
builder.space();
}
// An empty try-with-resources body can collapse to "{}" if there are no trailing catch or
// finally blocks.
boolean trailingClauses = !node.getCatches().isEmpty() || node.getFinallyBlock() != null;
visitBlock(
node.getBlock(),
CollapseEmptyOrNot.valueOf(!trailingClauses),
AllowLeadingBlankLine.YES,
AllowTrailingBlankLine.valueOf(trailingClauses));
for (int i = 0; i < node.getCatches().size(); i++) {
CatchTree catchClause = node.getCatches().get(i);
trailingClauses = i < node.getCatches().size() - 1 || node.getFinallyBlock() != null;
visitCatchClause(catchClause, AllowTrailingBlankLine.valueOf(trailingClauses));
}
if (node.getFinallyBlock() != null) {
builder.space();
token("finally");
builder.space();
visitBlock(
node.getFinallyBlock(),
CollapseEmptyOrNot.NO,
AllowLeadingBlankLine.YES,
AllowTrailingBlankLine.NO);
}
builder.close();
return null;
}