@Override public boolean matches(VariableTree variableTree, VisitorState state) { ExpressionTree initializer = variableTree.getInitializer(); return initializer == null ? false : expressionTreeMatcher.matches(initializer, state); } };
@Override public Void visitVariable(VariableTree node, Void aVoid) { if (sym.equals(ASTHelpers.getSymbol(node)) && node.getInitializer() != null && node.getInitializer().getKind() == Kind.STRING_LITERAL) { String source = state.getSourceForNode(node.getInitializer()); String replacement = source.replace('Y', 'y'); if (!source.equals(replacement)) { fix[0] = SuggestedFix.replace(node.getInitializer(), replacement); } } return super.visitVariable(node, aVoid); } }.scan(state.getPath().getCompilationUnit(), null);
private static boolean isValidParameterTree(VariableTree variableTree) { // A valid parameter has no initializer. if (variableTree.getInitializer() != null) { return false; } // A valid parameter either has no modifiers or has only `final` keyword. Set<Modifier> flags = variableTree.getModifiers().getFlags(); return flags.isEmpty() || (flags.size() == 1 && flags.contains(Modifier.FINAL)); }
@Override public Void visitVariable(VariableTree node, Void unused) { if (node.getInitializer() != null) { generateConstraintsForWrite( TreeInfo.symbolFor((JCTree) node).type, node.getInitializer(), node); } return super.visitVariable(node, unused); }
@Override public Void visitVariable(VariableTree variable, Void unused) { Symbol symbol = ASTHelpers.getSymbol(variable); if (variable.getInitializer() != null && isEffectivelyFinal(symbol) && trackAssignments.matches(variable.getInitializer(), state)) { effectivelyFinalValues.put(symbol, variable.getInitializer()); } return isSuppressed(variable) ? null : super.visitVariable(variable, null); }
@Override public ValidationResult visitVariable(VariableTree node, Void unused) { if (ASTHelpers.getSymbol(node) == formatStringSymbol) { if (node.getInitializer() == null) { return ValidationResult.create( null, String.format( "Variables used as format strings must be initialized when they are" + " declared.\nInvalid declaration: %s", node)); } return validateStringFromAssignment(node, node.getInitializer(), args, state); } return super.visitVariable(node, unused); }
@Override public Void visitVariable(VariableTree node, Void aVoid) { recordInitialization(node, node.getInitializer()); return super.visitVariable(node, aVoid); }
@Override public Description matchVariable(VariableTree tree, VisitorState state) { return check(ASTHelpers.getType(tree), tree.getInitializer()); }
@Override public UVariableDecl visitVariable(VariableTree tree, Void v) { return UVariableDecl.create( tree.getName(), templateType(tree.getType()), (tree.getInitializer() == null) ? null : template(tree.getInitializer())); }
private void saveConstValue(VariableTree tree, Scope scope) { VarSymbol sym = ASTHelpers.getSymbol(tree); if (sym == null) { return; } if ((sym.flags() & (Flags.EFFECTIVELY_FINAL | Flags.FINAL)) == 0) { return; } // heuristic: long string constants are generally more interesting than short ones, or // than non-string constants (e.g. `""`, `0`, or `false`). String constValue = ASTHelpers.constValue(tree.getInitializer(), String.class); if (constValue == null || constValue.length() <= 1) { return; } scope.put(state.getSourceForNode(tree.getInitializer()), sym); } }.scan(tree, new Scope(null));
@Override public Void visitVariable(VariableTree tree, VisitorState state) { checkForInitializer(ASTHelpers.getSymbol(tree), tree.getInitializer(), state); return super.visitVariable(tree, state); }
private static ImmutableList<Tree> getNearbyTreesToScan(VisitorState state) { for (Tree parent : state.getPath()) { // if we get all the way up to the class tree, then _only_ scan the other class-level fields if (parent.getKind() == Tree.Kind.CLASS) { ImmutableList.Builder<Tree> treesToScan = ImmutableList.builder(); for (Tree member : ((ClassTree) parent).getMembers()) { if (member instanceof VariableTree) { ExpressionTree expressionTree = ((VariableTree) member).getInitializer(); if (expressionTree != null) { treesToScan.add(expressionTree); } } } return treesToScan.build(); } // if we reach a block tree, then _only_ scan that block if (parent.getKind() == Tree.Kind.BLOCK) { return ImmutableList.of(parent); } // if we reach a lambda tree, then don't scan anything since we don't know where/when that // lambda will actually be executed if (parent.getKind() == Tree.Kind.LAMBDA_EXPRESSION) { return ImmutableList.of(); } } return ImmutableList.of(); } }
@Override public Void visitVariable(VariableTree variableTree, Void unused) { // Track variables assigned from our parameter. Tree initializer = variableTree.getInitializer(); VarSymbol symbol = getSymbol(variableTree); if ((symbol.flags() & (Flags.FINAL | Flags.EFFECTIVELY_FINAL)) != 0 && initializer instanceof InstanceOfTree) { InstanceOfTree instanceOf = (InstanceOfTree) initializer; if (instanceOf.getExpression() instanceof IdentifierTree && incomingVariableSymbols.contains(getSymbol(instanceOf.getExpression()))) { impliesNonNull.add(getSymbol(variableTree)); } } if (incomingVariableSymbols.contains(findVariable(variableTree.getInitializer()))) { incomingVariableSymbols.add(getSymbol(variableTree)); } return super.visitVariable(variableTree, null); }
@Override public Void visitVariable(VariableTree tree, Scope scope) { // record that this variables hides previous declarations before entering its initializer scope.remove(ASTHelpers.getSymbol(tree)); scan(tree.getInitializer(), scope); saveConstValue(tree, scope); return null; }
@Nullable private static <T> TreePath findEnclosingMethodOrLambdaOrInitializer(TreePath path) { while (path != null) { if (path.getLeaf() instanceof MethodTree) { return path; } TreePath parent = path.getParentPath(); if (parent != null) { if (parent.getLeaf() instanceof ClassTree) { if (path.getLeaf() instanceof BlockTree) { // this is a class or instance initializer block return path; } if (path.getLeaf() instanceof VariableTree && ((VariableTree) path.getLeaf()).getInitializer() != null) { // this is a field with an inline initializer return path; } } if (parent.getLeaf() instanceof LambdaExpressionTree) { return parent; } } path = parent; } return null; }
private static Fix threadLocalFix( VariableTree tree, VisitorState state, final VarSymbol sym, SuggestedFix rename) { SuggestedFix.Builder fix = SuggestedFix.builder() .merge(rename) .replace( tree.getType(), String.format("ThreadLocal<%s>", state.getSourceForNode(tree.getType()))) .prefixWith(tree.getInitializer(), "ThreadLocal.withInitial(() -> ") .postfixWith(tree.getInitializer(), ")"); CompilationUnitTree unit = state.getPath().getCompilationUnit(); unit.accept( new TreeScanner<Void, Void>() { @Override public Void visitIdentifier(IdentifierTree tree, Void unused) { if (Objects.equals(ASTHelpers.getSymbol(tree), sym)) { fix.postfixWith(tree, ".get()"); } return null; } }, null); return fix.build(); } }
@Override public Choice<State<JCVariableDecl>> visitVariable(final VariableTree node, State<?> state) { return chooseSubtrees( state, s -> unifyExpression(node.getInitializer(), s), init -> maker() .VarDef( (JCModifiers) node.getModifiers(), (Name) node.getName(), (JCExpression) node.getType(), init)); }
@Override public Description matchVariable(VariableTree tree, VisitorState state) { ExpressionTree initializer = stripNullCheck(tree.getInitializer(), state); Tree parent = state.getPath().getParentPath().getLeaf(); // must be a static class variable with member select initializer if (initializer == null || initializer.getKind() != MEMBER_SELECT || parent.getKind() != CLASS || !tree.getModifiers().getFlags().contains(STATIC)) { return Description.NO_MATCH; } MemberSelectTree rhs = (MemberSelectTree) initializer; Symbol rhsClass = ASTHelpers.getSymbol(rhs.getExpression()); Symbol lhsClass = ASTHelpers.getSymbol(parent); if (rhsClass != null && lhsClass != null && rhsClass.equals(lhsClass) && rhs.getIdentifier().contentEquals(tree.getName())) { return describeForVarDecl(tree, state); } return Description.NO_MATCH; }
@Override public Choice<Unifier> visitVariable(final VariableTree decl, Unifier unifier) { return Choice.condition(unifier.getBinding(key()) == null, unifier) .thenChoose(unifications(getType(), decl.getType())) .thenChoose(unifications(getInitializer(), decl.getInitializer())) .transform( new Function<Unifier, Unifier>() { @Override public Unifier apply(Unifier unifier) { unifier.putBinding( key(), LocalVarBinding.create(ASTHelpers.getSymbol(decl), decl.getModifiers())); return unifier; } }); }
@Override public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) { if (!IS_LOGGABLE_CALL.matches(tree, state)) { return NO_MATCH; } ExpressionTree tagArg = tree.getArguments().get(0); // Check for constant value. String tagConstantValue = ASTHelpers.constValue(tagArg, String.class); if (tagConstantValue != null) { return isValidTag(tagConstantValue) ? NO_MATCH : describeMatch(tagArg); } // Check for class literal simple name (e.g. MyClass.class.getSimpleName(). ExpressionTree tagExpr = tagArg; // If the tag argument is a final field, retrieve the initializer. if (kindIs(IDENTIFIER).matches(tagArg, state)) { VariableTree declaredField = findEnclosingIdentifier((IdentifierTree) tagArg, state); if (declaredField == null || !hasModifier(FINAL).matches(declaredField, state)) { return NO_MATCH; } tagExpr = declaredField.getInitializer(); } if (GET_SIMPLE_NAME_CALL.matches(tagExpr, state) && RECEIVER_IS_CLASS_LITERAL.matches((MethodInvocationTree) tagExpr, state)) { String tagName = getSymbol(getReceiver(getReceiver(tagExpr))).getSimpleName().toString(); return isValidTag(tagName) ? NO_MATCH : describeMatch(tagArg); } return NO_MATCH; }