/** Matches if this Tree is enclosed by either a synchronized block or a synchronized method. */ public static final <T extends Tree> Matcher<T> inSynchronized() { return new Matcher<T>() { @Override public boolean matches(T tree, VisitorState state) { SynchronizedTree synchronizedTree = ASTHelpers.findEnclosingNode(state.getPath(), SynchronizedTree.class); if (synchronizedTree != null) { return true; } MethodTree methodTree = ASTHelpers.findEnclosingNode(state.getPath(), MethodTree.class); return methodTree != null && methodTree.getModifiers().getFlags().contains(Modifier.SYNCHRONIZED); } }; }
@Override public Description matchSynchronized(SynchronizedTree tree, VisitorState state) { Symbol lock = ASTHelpers.getSymbol(stripParentheses(tree.getExpression())); if (!(lock instanceof VarSymbol)) { return Description.NO_MATCH; } if (lock.isStatic()) { return Description.NO_MATCH; } Multimap<VarSymbol, Tree> writes = WriteVisitor.scan(tree.getBlock()); for (Entry<VarSymbol, Tree> write : writes.entries()) { if (!write.getKey().isStatic()) { continue; } state.reportMatch( buildDescription(write.getValue()).setMessage(String.format(MESSAGE, lock)).build()); } return Description.NO_MATCH; }
@Override public Description matchSynchronized(SynchronizedTree tree, VisitorState state) { Symbol symbol = ASTHelpers.getSymbol(stripParentheses(tree.getExpression())); if (!(symbol instanceof VarSymbol)) { return NO_MATCH; } // TODO(cushon): check that the receiver doesn't contain mutable state. // Currently 'this.locks[i].mu' is accepted if 'mu' is final but 'locks' is non-final. VarSymbol varSymbol = (VarSymbol) symbol; if (varSymbol.isLocal() || varSymbol.isStatic() || (varSymbol.flags() & Flags.FINAL) != 0) { return NO_MATCH; } if (ASTHelpers.hasAnnotation(varSymbol, LazyInit.class, state)) { return NO_MATCH; } Name ownerName = varSymbol.owner.enclClass().getQualifiedName(); if (Stream.of("java.io.Writer", "java.io.Reader").anyMatch(ownerName::contentEquals)) { // These classes contain a non-final 'lock' variable available to subclasses, and we can't // make these locks final. return NO_MATCH; } return describeMatch(tree.getExpression()); }
/** * Matches if this Tree is enclosed by either a synchronized block or a synchronized method. */ public static final <T extends Tree> Matcher<T> inSynchronized() { return new Matcher<T>() { @Override public boolean matches(T tree, VisitorState state) { SynchronizedTree synchronizedTree = ASTHelpers.findEnclosingNode(state.getPath(), SynchronizedTree.class); if (synchronizedTree != null) { return true; } MethodTree methodTree = ASTHelpers.findEnclosingNode(state.getPath(), MethodTree.class); if (methodTree != null && methodTree.getModifiers().getFlags().contains(Modifier.SYNCHRONIZED)) { return true; } return false; } }; }
@Override public Tree visitSynchronized(SynchronizedTree tree, Void p) { SynchronizedTree n = make.Synchronized(tree.getExpression(), tree.getBlock()); model.setType(n, model.getType(tree)); comments.copyComments(tree, n); model.setPos(n, model.getPos(tree)); return n; }
public Boolean visitSynchronized(SynchronizedTree node, TreePath p) { if (p == null) { super.visitSynchronized(node, p); return false; } SynchronizedTree at = (SynchronizedTree) p.getLeaf(); if (!scan(node.getExpression(), at.getExpression(), p)) { return false; } return scan(node.getBlock(), at.getBlock(), p); }
@Override public Void visitSynchronized(SynchronizedTree tree, List<Node> d) { List<Node> below = new ArrayList<Node>(); addCorrespondingType(below); addCorrespondingComments(below); super.visitSynchronized(tree, below); d.add(new TreeNode(info, getCurrentPath(), below)); return null; }
@TriggerTreeKind(Kind.SYNCHRONIZED) public static ErrorDescription run(HintContext ctx) { ExpressionTree expression = ((SynchronizedTree) ctx.getPath().getLeaf()).getExpression(); Element e = ctx.getInfo().getTrees().getElement(new TreePath(ctx.getPath(), expression)); if (e == null || e.getKind() != ElementKind.FIELD || e.getModifiers().contains(Modifier.FINAL)) { return null; } String displayName = NbBundle.getMessage(SyncOnNonFinal.class, "ERR_SynchronizationOnNonFinalField"); return ErrorDescriptionFactory.forTree(ctx, expression, displayName); }
@Override public List<Tree> visitSynchronized(SynchronizedTree node, ExpressionScanner.ExpressionsInfo p) { List<Tree> result = null; if (acceptsTree(node)) { result = scan(node.getExpression(), p); } return reduce(result, scan(node.getBlock(), p)); }
@Override public Void visitSynchronized(SynchronizedTree node, Void unused) { sync(node); token("synchronized"); builder.space(); token("("); builder.open(plusFour); builder.breakOp(); scan(skipParen(node.getExpression()), null); builder.close(); token(")"); builder.space(); scan(node.getBlock(), null); return null; }
@Override public Void visitSynchronized(SynchronizedTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (SynchronizedTreeMatcher matcher : synchronizedMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchSynchronized(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitSynchronized(tree, state); }
@Override public Choice<State<JCSynchronized>> visitSynchronized( final SynchronizedTree node, State<?> state) { return chooseSubtrees( state, s -> unifyExpression(node.getExpression(), s), s -> unifyStatement(node.getBlock(), s), (expr, block) -> maker().Synchronized(expr, (JCBlock) block)); }
@Override public Void visitSynchronized(SynchronizedTree tree, HeldLockSet locks) { // The synchronized expression is held in the body of the synchronized statement: Optional<GuardedByExpression> lockExpression = GuardedByBinder.bindExpression((JCExpression) tree.getExpression(), visitorState); scan(tree.getBlock(), lockExpression.isPresent() ? locks.plus(lockExpression.get()) : locks); return null; }
/** * Matches an instance of DCL. The canonical pattern is: * * <pre>{@code * if ($X == null) { * synchronized (...) { * if ($X == null) { * ... * } * ... * } * } * }</pre> * * Gaps before the synchronized or inner 'if' statement are ignored, and the operands in the * null-checks are accepted in either order. */ @Nullable static DCLInfo findDCL(IfTree outerIf) { // TODO(cushon): Optional.ifPresent... ExpressionTree outerIfTest = getNullCheckedExpression(outerIf.getCondition()); if (outerIfTest == null) { return null; } SynchronizedTree synchTree = getChild(outerIf.getThenStatement(), SynchronizedTree.class); if (synchTree == null) { return null; } IfTree innerIf = getChild(synchTree.getBlock(), IfTree.class); if (innerIf == null) { return null; } ExpressionTree innerIfTest = getNullCheckedExpression(innerIf.getCondition()); if (innerIfTest == null) { return null; } Symbol outerSym = ASTHelpers.getSymbol(outerIfTest); if (!Objects.equals(outerSym, ASTHelpers.getSymbol(innerIfTest))) { return null; } if (!(outerSym instanceof VarSymbol)) { return null; } VarSymbol var = (VarSymbol) outerSym; return DCLInfo.create(outerIf, synchTree, innerIf, var); }
@Override public PurityResult visitSynchronized(SynchronizedTree node, PurityResult p) { PurityResult r = scan(node.getExpression(), p); r = scan(node.getBlock(), r); return r; }
@Override public Void visitSynchronized(SynchronizedTree node, Void p) { List<String> prevLocks = atypeFactory.getHeldLock(); try { List<String> locks = append(prevLocks, TreeUtils.skipParens(node.getExpression()).toString()); atypeFactory.setHeldLocks(locks); return super.visitSynchronized(node, p); } finally { atypeFactory.setHeldLocks(prevLocks); } }
@Override public Node visitSynchronized(SynchronizedTree tree, Void p) { // see JLS 14.19 Node synchronizedExpr = scan(tree.getExpression(), p); SynchronizedNode synchronizedStartNode = new SynchronizedNode(tree, synchronizedExpr, true, env.getTypeUtils()); extendWithNode(synchronizedStartNode); scan(tree.getBlock(), p); SynchronizedNode synchronizedEndNode = new SynchronizedNode(tree, synchronizedExpr, false, env.getTypeUtils()); extendWithNode(synchronizedEndNode); return null; }
@Override public Void visitSynchronized(SynchronizedTree expected, Tree actual) { Optional<SynchronizedTree> other = checkTypeAndCast(expected, actual); if (!other.isPresent()) { addTypeMismatch(expected, actual); return null; } scan(expected.getExpression(), other.get().getExpression()); scan(expected.getBlock(), other.get().getBlock()); return null; }
public Boolean visitSynchronized(SynchronizedTree node, ConstructorData p) { super.visitSynchronized(node, p); return null; }
@Override public List<? extends TypeMirror> visitSynchronized(SynchronizedTree node, Object p) { return null; }
@Override public Mirror visitSynchronized(SynchronizedTree arg0, EvaluationContext evaluationContext) { Assert.error(arg0, "unsupported"); return null; }
@Override public Void visitSynchronized(SynchronizedTree node, Map<ErrorDescription, Integer> p) { if (!isUnsafe) addError(node, ERR_NO_SYNCHRONIZATION, p); return super.visitSynchronized(node, p); }
@Override public R visitSynchronized(SynchronizedTree st, P p) { return null; }
@Override public List<T> visitSynchronized(SynchronizedTree node, T p) { return checkForCriteria(node); }
@Override public Object visitSynchronized(SynchronizedTree t, Trees p) { info("SynchronizedTree" + CL + t.getKind() + SP + t); return super.visitSynchronized(t, p); }
@Override public USynchronized visitSynchronized(SynchronizedTree tree, Void v) { return USynchronized.create( template(tree.getExpression()), visitBlock(tree.getBlock(), null)); }
@Override public Void visitSynchronized(SynchronizedTree node, Context context) { scan(SKIP_PARENS.visit(node.getExpression(), null), context); scan(node.getBlock(), context); return null; }
@Override @Nullable public Unifier visitSynchronized(SynchronizedTree synced, @Nullable Unifier unifier) { unifier = getExpression().unify(synced.getExpression(), unifier); return getBlock().unify(synced.getBlock(), unifier); }
@Override public Boolean visitSynchronized(SynchronizedTree tree, Void unused) { return scan(tree.getBlock()); }
@Override public USynchronized visitSynchronized(SynchronizedTree tree, Void v) { return USynchronized.create(template(tree.getExpression()), visitBlock(tree.getBlock(), null)); }
@Override public Result visitSynchronized(SynchronizedTree node, BreakContext cxt) { return node.getBlock().accept(this, cxt); }
@Override public Choice<Unifier> visitSynchronized(SynchronizedTree synced, Unifier unifier) { return getExpression() .unify(synced.getExpression(), unifier) .thenChoose(unifications(getBlock(), synced.getBlock())); }
@Override public Void visitSynchronized(SynchronizedTree node, Void aVoid) { // don't descend into nested synchronized blocks return null; }
/** The synchronized statement */ abstract SynchronizedTree synchTree();
static DCLInfo create( IfTree outerIf, SynchronizedTree synchTree, IfTree innerIf, VarSymbol sym) { return new AutoValue_DoubleCheckedLocking_DCLInfo(outerIf, synchTree, innerIf, sym); }
@Override public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { if (!waitMatcher.matches(tree, state)) { return Description.NO_MATCH; } if (!SUPPLY_FIX) { return describeMatch(tree, Fix.NO_FIX); } SuggestedFix fix = new SuggestedFix(); // if -> while case JCIf enclosingIf = ASTHelpers.findEnclosingNode(state.getPath().getParentPath(), JCIf.class); if (enclosingIf != null && enclosingIf.getElseStatement() == null) { // Assume first 2 characters of the IfTree are "if", replace with while. fix.replace(enclosingIf.getStartPosition(), enclosingIf.getStartPosition() + 2, "while"); return describeMatch(tree, fix); } // loop outside synchronized block -> move synchronized outside @SuppressWarnings("unchecked") List<Class<? extends StatementTree>> loopClasses = Arrays.asList(WhileLoopTree.class, ForLoopTree.class, EnhancedForLoopTree.class, DoWhileLoopTree.class); StatementTree enclosingLoop = null; for (Class<? extends StatementTree> loopClass : loopClasses) { enclosingLoop = ASTHelpers.findEnclosingNode(state.getPath().getParentPath(), loopClass); if (enclosingLoop != null) { break; } } if (enclosingLoop != null) { SynchronizedTree enclosingSynchronized = ASTHelpers.findEnclosingNode( state.getPath().getParentPath(), SynchronizedTree.class); if (enclosingSynchronized != null) { String blockStatements = enclosingSynchronized.getBlock().toString(); int openBracketIndex = blockStatements.indexOf('{'); int closeBracketIndex = blockStatements.lastIndexOf('}'); blockStatements = blockStatements.substring(openBracketIndex + 1, closeBracketIndex).trim(); fix.replace(enclosingSynchronized, blockStatements); fix.prefixWith(enclosingLoop, "synchronized " + enclosingSynchronized.getExpression() + " {\n"); fix.postfixWith(enclosingLoop, "\n}"); return describeMatch(tree, fix); } } // Intent is to wait forever -> wrap in while (true) // Heuristic: this is the last statement in a method called main, inside a synchronized block. /* if (enclosingIf == null && (ASTHelpers.findEnclosingNode(state.getPath().getParentPath(), WhileLoopTree.class) == null) && (ASTHelpers.findEnclosingNode(state.getPath().getParentPath(), ForLoopTree.class) == null) && (ASTHelpers.findEnclosingNode(state.getPath().getParentPath(), EnhancedForLoopTree.class) == null) && (ASTHelpers.findEnclosingNode(state.getPath().getParentPath(), DoWhileLoopTree.class) == null)) { TreeMaker treeMaker = TreeMaker.instance(state.context); JCLiteral trueLiteral = treeMaker.Literal(true); treeMaker.WhileLoop(trueLiteral, } */ return describeMatch(tree, fix); }
/** Case 5: Check for synchronizing locks */ @Override public Void visitSynchronized(SynchronizedTree node, Void p) { checkForNullability(node.getExpression(), LOCKING_NULLABLE); return super.visitSynchronized(node, p); }