use of com.sun.source.tree.IdentifierTree in project checker-framework by typetools.
the class TreeParserTest method parsesIndex.
@Test
public void parsesIndex() {
String value = "array[2]";
ExpressionTree parsed = parser.parseTree(value);
Assert.assertTrue(parsed instanceof ArrayAccessTree);
ArrayAccessTree access = (ArrayAccessTree) parsed;
Assert.assertEquals(2, ((LiteralTree) access.getIndex()).getValue());
Assert.assertEquals("array", ((IdentifierTree) access.getExpression()).getName().toString());
}
use of com.sun.source.tree.IdentifierTree in project checker-framework by typetools.
the class BaseTypeValidator method extractParameterizedTypeTree.
/**
* If {@code tree} has a {@link ParameterizedTypeTree}, then the tree and its type is returned.
* Otherwise null and {@code type} are returned.
*
* @param tree tree to search
* @param type type to return if no {@code ParameterizedTypeTree} is found
* @return if {@code tree} has a {@code ParameterizedTypeTree}, then returns the tree and its
* type. Otherwise, returns null and {@code type}.
*/
private Pair<@Nullable ParameterizedTypeTree, AnnotatedDeclaredType> extractParameterizedTypeTree(Tree tree, AnnotatedDeclaredType type) {
ParameterizedTypeTree typeargtree = null;
switch(tree.getKind()) {
case VARIABLE:
Tree lt = ((VariableTree) tree).getType();
if (lt instanceof ParameterizedTypeTree) {
typeargtree = (ParameterizedTypeTree) lt;
} else {
// System.out.println("Found a: " + lt);
}
break;
case PARAMETERIZED_TYPE:
typeargtree = (ParameterizedTypeTree) tree;
break;
case NEW_CLASS:
NewClassTree nct = (NewClassTree) tree;
ExpressionTree nctid = nct.getIdentifier();
if (nctid.getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
typeargtree = (ParameterizedTypeTree) nctid;
/*
* This is quite tricky... for anonymous class instantiations,
* the type at this point has no type arguments. By doing the
* following, we get the type arguments again.
*/
type = (AnnotatedDeclaredType) atypeFactory.getAnnotatedType(typeargtree);
}
break;
case ANNOTATED_TYPE:
AnnotatedTypeTree tr = (AnnotatedTypeTree) tree;
ExpressionTree undtr = tr.getUnderlyingType();
if (undtr instanceof ParameterizedTypeTree) {
typeargtree = (ParameterizedTypeTree) undtr;
} else if (undtr instanceof IdentifierTree) {
// @Something D -> Nothing to do
} else {
// TODO: add more test cases to ensure that nested types are
// handled correctly,
// e.g. @Nullable() List<@Nullable Object>[][]
Pair<ParameterizedTypeTree, AnnotatedDeclaredType> p = extractParameterizedTypeTree(undtr, type);
typeargtree = p.first;
type = p.second;
}
break;
case IDENTIFIER:
case ARRAY_TYPE:
case NEW_ARRAY:
case MEMBER_SELECT:
case UNBOUNDED_WILDCARD:
case EXTENDS_WILDCARD:
case SUPER_WILDCARD:
case TYPE_PARAMETER:
// Nothing to do.
break;
case METHOD:
// If a MethodTree is passed, it's just the return type that is validated.
// See BaseTypeVisitor#validateTypeOf.
MethodTree methodTree = (MethodTree) tree;
if (methodTree.getReturnType() instanceof ParameterizedTypeTree) {
typeargtree = (ParameterizedTypeTree) methodTree.getReturnType();
}
break;
default:
// No need to do anything further.
break;
}
return Pair.of(typeargtree, type);
}
use of com.sun.source.tree.IdentifierTree in project checker-framework by typetools.
the class ExpectedTreesVisitor method visitExpressionStatement.
@Override
public Void visitExpressionStatement(ExpressionStatementTree tree, Void p) {
// These don't have matching JavaParser nodes.
if (JointJavacJavaParserVisitor.isDefaultSuperConstructorCall(tree)) {
return null;
}
// Whereas synthetic constructors should be skipped, regular super() and this() should still
// be added. JavaParser has no expression statement surrounding these, so remove the
// expression statement itself.
Void result = super.visitExpressionStatement(tree, p);
if (tree.getExpression().getKind() == Tree.Kind.METHOD_INVOCATION) {
MethodInvocationTree invocation = (MethodInvocationTree) tree.getExpression();
if (invocation.getMethodSelect().getKind() == Tree.Kind.IDENTIFIER) {
IdentifierTree identifier = (IdentifierTree) invocation.getMethodSelect();
if (identifier.getName().contentEquals("this") || identifier.getName().contentEquals("super")) {
trees.remove(tree);
trees.remove(identifier);
}
}
}
return result;
}
use of com.sun.source.tree.IdentifierTree in project error-prone by google.
the class StreamResourceLeak method addFix.
@Override
protected void addFix(Description.Builder description, ExpressionTree tree, VisitorState state) {
TreePath parentPath = state.getPath().getParentPath();
Tree parent = parentPath.getLeaf();
SuggestedFix.Builder fix = SuggestedFix.builder();
String streamType = SuggestedFixes.prettyType(state, fix, ASTHelpers.getReturnType(tree));
if (parent instanceof MemberSelectTree) {
StatementTree statement = state.findEnclosing(StatementTree.class);
if (statement instanceof VariableTree) {
// Variables need to be declared outside the try-with-resources:
// e.g. `int count = Files.lines(p).count();`
// -> `int count; try (Stream<String> stream = Files.lines(p)) { count = stream.count(); }`
VariableTree var = (VariableTree) statement;
int pos = ((JCTree) var).getStartPosition();
int initPos = ((JCTree) var.getInitializer()).getStartPosition();
int eqPos = pos + state.getSourceForNode(var).substring(0, initPos - pos).lastIndexOf('=');
fix.replace(eqPos, initPos, String.format(";\ntry (%s stream = %s) {\n%s =", streamType, state.getSourceForNode(tree), var.getName().toString()));
} else {
// the non-variable case, e.g. `return Files.lines(p).count()`
// -> try (Stream<Stream> stream = Files.lines(p)) { return stream.count(); }`
fix.prefixWith(statement, String.format("try (%s stream = %s) {\n", streamType, state.getSourceForNode(tree)));
}
fix.replace(tree, "stream");
fix.postfixWith(statement, "}");
description.addFix(fix.build());
} else if (parent instanceof VariableTree) {
// If the stream is assigned to a variable, wrap the variable in a try-with-resources
// that includes all statements in the same block that reference the variable.
Tree grandParent = parentPath.getParentPath().getLeaf();
if (!(grandParent instanceof BlockTree)) {
return;
}
List<? extends StatementTree> statements = ((BlockTree) grandParent).getStatements();
int idx = statements.indexOf(parent);
int lastUse = idx;
for (int i = idx + 1; i < statements.size(); i++) {
boolean[] found = { false };
statements.get(i).accept(new TreeScanner<Void, Void>() {
@Override
public Void visitIdentifier(IdentifierTree tree, Void unused) {
if (Objects.equals(ASTHelpers.getSymbol(tree), ASTHelpers.getSymbol(parent))) {
found[0] = true;
}
return null;
}
}, null);
if (found[0]) {
lastUse = i;
}
}
fix.prefixWith(parent, "try (");
fix.replace(state.getEndPosition(((VariableTree) parent).getInitializer()), state.getEndPosition(parent), ") {");
fix.postfixWith(statements.get(lastUse), "}");
description.addFix(fix.build());
} else if (parent instanceof EnhancedForLoopTree) {
// If the stream is used in a loop (e.g. directory streams), wrap the loop in
// try-with-resources.
fix.prefixWith(parent, String.format("try (%s stream = %s) {\n", streamType, state.getSourceForNode(tree)));
fix.replace(tree, "stream");
fix.postfixWith(parent, "}");
description.addFix(fix.build());
} else if (parent instanceof MethodInvocationTree) {
// If the stream is used in a method that is called in an expression statement, wrap it in
// try-with-resources.
Tree grandParent = parentPath.getParentPath().getLeaf();
if (!(grandParent instanceof ExpressionStatementTree)) {
return;
}
fix.prefixWith(parent, String.format("try (%s stream = %s) {\n", streamType, state.getSourceForNode(tree)));
fix.replace(tree, "stream");
fix.postfixWith(grandParent, "}");
description.addFix(fix.build());
}
}
use of com.sun.source.tree.IdentifierTree 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());
}
Aggregations