use of com.sun.source.tree.VariableTree in project error-prone by google.
the class StringSplitter method buildFix.
public Optional<Fix> buildFix(MethodInvocationTree tree, VisitorState state) {
Tree arg = getOnlyElement(tree.getArguments());
String value = ASTHelpers.constValue(arg, String.class);
boolean maybeRegex = false;
if (value != null) {
Optional<String> regexAsLiteral = convertRegexToLiteral(value);
if (regexAsLiteral.isPresent()) {
value = SourceCodeEscapers.javaCharEscaper().escape(regexAsLiteral.get());
if (value.length() == 1) {
value = String.format("'%s'", value.charAt(0));
} else {
value = String.format("\"%s\"", value);
}
} else {
maybeRegex = true;
value = state.getSourceForNode(arg);
}
} else {
value = state.getSourceForNode(arg);
}
Tree parent = state.getPath().getParentPath().getLeaf();
if (parent instanceof EnhancedForLoopTree && ((EnhancedForLoopTree) parent).getExpression().equals(tree)) {
// fix for `for (... : s.split(...)) {}` -> `for (... : Splitter.on(...).split(s)) {}`
return Optional.of(replaceWithSplitter(SuggestedFix.builder(), tree, value, state, "split", maybeRegex, /* mutableList= */
false).build());
}
if (parent instanceof ArrayAccessTree) {
ArrayAccessTree arrayAccessTree = (ArrayAccessTree) parent;
if (!arrayAccessTree.getExpression().equals(tree)) {
return Optional.empty();
}
SuggestedFix.Builder fix = SuggestedFix.builder().addImport("com.google.common.collect.Iterables").replace(((JCTree) arrayAccessTree).getStartPosition(), ((JCTree) arrayAccessTree).getStartPosition(), "Iterables.get(").replace(/* startPos= */
state.getEndPosition(arrayAccessTree.getExpression()), /* endPos= */
((JCTree) arrayAccessTree.getIndex()).getStartPosition(), String.format(", ")).replace(state.getEndPosition(arrayAccessTree.getIndex()), state.getEndPosition(arrayAccessTree), ")");
return Optional.of(replaceWithSplitter(fix, tree, value, state, "split", maybeRegex, /* mutableList= */
false).build());
}
// enclosing method. If we don't know how to fix any of them, bail out.
if (!(parent instanceof VariableTree)) {
return Optional.empty();
}
VariableTree varTree = (VariableTree) parent;
if (!varTree.getInitializer().equals(tree)) {
return Optional.empty();
}
VarSymbol sym = ASTHelpers.getSymbol(varTree);
TreePath enclosing = findEnclosing(state);
if (enclosing == null) {
return Optional.empty();
}
// find all uses of the variable in the enclosing method
List<TreePath> uses = new ArrayList<>();
new TreePathScanner<Void, Void>() {
@Override
public Void visitIdentifier(IdentifierTree tree, Void unused) {
if (Objects.equals(sym, ASTHelpers.getSymbol(tree))) {
uses.add(getCurrentPath());
}
return super.visitIdentifier(tree, null);
}
}.scan(enclosing, null);
SuggestedFix.Builder fix = SuggestedFix.builder();
// a mutable boolean to track whether we want split or splitToList
boolean[] needsList = { false };
boolean[] needsMutableList = { false };
// try to fix all uses of the variable
for (TreePath path : uses) {
class UseFixer extends TreePathScanner<Boolean, Void> {
@Override
public Boolean visitEnhancedForLoop(EnhancedForLoopTree tree, Void unused) {
// fix here.
return sym.equals(ASTHelpers.getSymbol(tree.getExpression()));
}
@Override
public Boolean visitArrayAccess(ArrayAccessTree tree, Void unused) {
// replace `pieces[N]` with `pieces.get(N)`
ExpressionTree expression = tree.getExpression();
ExpressionTree index = tree.getIndex();
if (!sym.equals(ASTHelpers.getSymbol(expression))) {
return false;
}
Tree parent = getCurrentPath().getParentPath().getLeaf();
if (parent instanceof AssignmentTree && ((AssignmentTree) parent).getVariable() == tree) {
AssignmentTree assignmentTree = (AssignmentTree) parent;
fix.replace(/* startPos= */
state.getEndPosition(expression), /* endPos= */
((JCTree) index).getStartPosition(), ".set(").replace(/* startPos= */
state.getEndPosition(index), /* endPos= */
((JCTree) assignmentTree.getExpression()).getStartPosition(), ", ").postfixWith(assignmentTree, ")");
needsMutableList[0] = true;
} else {
fix.replace(/* startPos= */
state.getEndPosition(expression), /* endPos= */
((JCTree) index).getStartPosition(), ".get(").replace(state.getEndPosition(index), state.getEndPosition(tree), ")");
}
// we want a list for indexing
needsList[0] = true;
return true;
}
@Override
public Boolean visitMemberSelect(MemberSelectTree tree, Void aVoid) {
// replace `pieces.length` with `pieces.size`
if (sym.equals(ASTHelpers.getSymbol(tree.getExpression())) && tree.getIdentifier().contentEquals("length")) {
fix.replace(state.getEndPosition(tree.getExpression()), state.getEndPosition(tree), ".size()");
needsList[0] = true;
return true;
}
return false;
}
}
if (!firstNonNull(new UseFixer().scan(path.getParentPath(), null), false)) {
return Optional.empty();
}
}
if (needsList[0]) {
fix.replace((varTree).getType(), "List<String>").addImport("java.util.List");
replaceWithSplitter(fix, tree, value, state, "splitToList", maybeRegex, needsMutableList[0]);
} else {
fix.replace((varTree).getType(), "Iterable<String>");
replaceWithSplitter(fix, tree, value, state, "split", maybeRegex, needsMutableList[0]);
}
return Optional.of(fix.build());
}
use of com.sun.source.tree.VariableTree in project error-prone by google.
the class MutableConstantField method matchVariable.
@Override
public Description matchVariable(VariableTree tree, VisitorState state) {
if (!isConstantField(ASTHelpers.getSymbol(tree))) {
return Description.NO_MATCH;
}
Tree rhsTree = tree.getInitializer();
Type rhsType = ASTHelpers.getType(rhsTree);
if (rhsType == null || !ImmutableCollections.isImmutableType(rhsType)) {
return Description.NO_MATCH;
}
Tree lhsTree = tree.getType();
Type lhsType = ASTHelpers.getType(lhsTree);
if (lhsType == null || ImmutableCollections.isImmutableType(lhsType)) {
return Description.NO_MATCH;
}
String lhsTypeQualifiedName = getTypeQualifiedName(lhsType);
String newLhsTypeQualifiedName = ImmutableCollections.mutableToImmutable(lhsTypeQualifiedName).orElse(getTypeQualifiedName(rhsType));
Type newLhsType = state.getTypeFromString(newLhsTypeQualifiedName);
SuggestedFix.Builder fixBuilder = SuggestedFix.builder();
fixBuilder.replace(getTypeTree(lhsTree), SuggestedFixes.qualifyType(state, fixBuilder, newLhsType.asElement()));
SuggestedFix fix = fixBuilder.build();
return describeMatch(lhsTree, fix);
}
use of com.sun.source.tree.VariableTree in project error-prone by google.
the class FindIdentifiers method findAllIdents.
/**
* Finds the set of all bare variable identifiers in scope at the current location. Identifiers
* are ordered by ascending distance/scope count from the current location to match shadowing
* rules. That is, if two variables with the same simple names appear in the set, the one that
* appears first in iteration order is the one you get if you use the bare name in the source
* code.
*
* <p>We do not report variables that would require a qualfied access. We also do not handle
* wildcard imports.
*/
public static LinkedHashSet<VarSymbol> findAllIdents(VisitorState state) {
ImmutableSet.Builder<VarSymbol> result = new ImmutableSet.Builder<>();
Tree prev = state.getPath().getLeaf();
for (Tree curr : state.getPath().getParentPath()) {
switch(curr.getKind()) {
case BLOCK:
for (StatementTree stmt : ((BlockTree) curr).getStatements()) {
if (stmt.equals(prev)) {
break;
}
addIfVariable(stmt, result);
}
break;
case METHOD:
for (VariableTree param : ((MethodTree) curr).getParameters()) {
result.add(ASTHelpers.getSymbol(param));
}
break;
case CATCH:
result.add(ASTHelpers.getSymbol(((CatchTree) curr).getParameter()));
break;
case CLASS:
case INTERFACE:
case ENUM:
case ANNOTATION_TYPE:
// field is referred to by qualified name, but we don't support that.
for (Tree member : ((ClassTree) curr).getMembers()) {
if (member.equals(prev)) {
break;
}
addIfVariable(member, result);
}
// Collect inherited fields.
Type classType = ASTHelpers.getType(curr);
List<Type> classTypeClosure = state.getTypes().closure(classType);
List<Type> superTypes = classTypeClosure.size() <= 1 ? Collections.emptyList() : classTypeClosure.subList(1, classTypeClosure.size());
for (Type type : superTypes) {
Scope scope = type.tsym.members();
ImmutableList.Builder<VarSymbol> varsList = ImmutableList.builder();
for (Symbol var : scope.getSymbols(VarSymbol.class::isInstance)) {
varsList.add((VarSymbol) var);
}
result.addAll(varsList.build().reverse());
}
break;
case FOR_LOOP:
addAllIfVariable(((ForLoopTree) curr).getInitializer(), result);
break;
case ENHANCED_FOR_LOOP:
result.add(ASTHelpers.getSymbol(((EnhancedForLoopTree) curr).getVariable()));
break;
case TRY:
TryTree tryTree = (TryTree) curr;
boolean inResources = false;
for (Tree resource : tryTree.getResources()) {
if (resource.equals(prev)) {
inResources = true;
break;
}
}
if (inResources) {
// Case 1: we're in one of the resource declarations
for (Tree resource : tryTree.getResources()) {
if (resource.equals(prev)) {
break;
}
addIfVariable(resource, result);
}
} else if (tryTree.getBlock().equals(prev)) {
// Case 2: We're in the block (not a catch or finally)
addAllIfVariable(tryTree.getResources(), result);
}
break;
case COMPILATION_UNIT:
for (ImportTree importTree : ((CompilationUnitTree) curr).getImports()) {
if (importTree.isStatic() && importTree.getQualifiedIdentifier().getKind() == Kind.MEMBER_SELECT) {
MemberSelectTree memberSelectTree = (MemberSelectTree) importTree.getQualifiedIdentifier();
Scope scope = state.getTypes().membersClosure(ASTHelpers.getType(memberSelectTree.getExpression()), /* skipInterface= */
false);
for (Symbol var : scope.getSymbols(sym -> sym instanceof VarSymbol && sym.getSimpleName().equals(memberSelectTree.getIdentifier()))) {
result.add((VarSymbol) var);
}
}
}
break;
default:
// other node types don't introduce variables
break;
}
prev = curr;
}
// TODO(eaftan): switch out collector for ImmutableSet.toImmutableSet()
return result.build().stream().filter(var -> isVisible(var, state.getPath())).collect(Collectors.toCollection(LinkedHashSet::new));
}
use of com.sun.source.tree.VariableTree in project error-prone by google.
the class RefasterRuleBuilderScanner method visitMethod.
@Override
public Void visitMethod(MethodTree tree, Void v) {
try {
VisitorState state = new VisitorState(context);
logger.log(FINE, "Discovered method with name {0}", tree.getName());
if (ASTHelpers.hasAnnotation(tree, Placeholder.class, state)) {
checkArgument(tree.getModifiers().getFlags().contains(Modifier.ABSTRACT), "@Placeholder methods are expected to be abstract");
UTemplater templater = new UTemplater(context);
ImmutableMap.Builder<UVariableDecl, ImmutableClassToInstanceMap<Annotation>> params = ImmutableMap.builder();
for (VariableTree param : tree.getParameters()) {
params.put(templater.visitVariable(param, null), UTemplater.annotationMap(ASTHelpers.getSymbol(param)));
}
MethodSymbol sym = ASTHelpers.getSymbol(tree);
placeholderMethods.put(sym, PlaceholderMethod.create(tree.getName(), templater.template(sym.getReturnType()), params.build(), UTemplater.annotationMap(sym)));
} else if (ASTHelpers.hasAnnotation(tree, BeforeTemplate.class, state)) {
checkState(afterTemplates.isEmpty(), "BeforeTemplate must come before AfterTemplate");
Template<?> template = UTemplater.createTemplate(context, tree);
beforeTemplates.add(template);
if (template instanceof BlockTemplate) {
context.put(UTemplater.REQUIRE_BLOCK_KEY, /* data= */
true);
}
} else if (ASTHelpers.hasAnnotation(tree, AfterTemplate.class, state)) {
afterTemplates.add(UTemplater.createTemplate(context, tree));
} else if (tree.getModifiers().getFlags().contains(Modifier.ABSTRACT)) {
throw new IllegalArgumentException("Placeholder methods must have @Placeholder, but abstract method does not: " + tree);
}
return null;
} catch (Throwable t) {
throw new RuntimeException("Error analysing: " + tree.getName(), t);
}
}
use of com.sun.source.tree.VariableTree in project error-prone by google.
the class ConstantOverflow method longFix.
/**
* If the left operand of an int binary expression is an int literal, suggest making it a long.
*/
private Fix longFix(ExpressionTree expr, VisitorState state) {
BinaryTree binExpr = null;
while (expr instanceof BinaryTree) {
binExpr = (BinaryTree) expr;
expr = binExpr.getLeftOperand();
}
if (!(expr instanceof LiteralTree) || expr.getKind() != Kind.INT_LITERAL) {
return null;
}
Type intType = state.getSymtab().intType;
if (!isSameType(getType(binExpr), intType, state)) {
return null;
}
SuggestedFix.Builder fix = SuggestedFix.builder().postfixWith(expr, "L");
Tree parent = state.getPath().getParentPath().getLeaf();
if (parent instanceof VariableTree && isSameType(getType(parent), intType, state)) {
fix.replace(((VariableTree) parent).getType(), "long");
}
return fix.build();
}
Aggregations