@Override public List<Fix> run(CompilationInfo info, String diagnosticKey, int offset, TreePath treePath, Data<Void> data) { if (treePath.getLeaf().getKind() != Kind.ARRAY_ACCESS) { return Collections.emptyList(); } ArrayAccessTree aa = (ArrayAccessTree) treePath.getLeaf(); TypeMirror onType = info.getTrees().getTypeMirror(new TreePath(treePath, aa.getExpression())); boolean list = isSubType(info, onType, "java.util.List"); boolean map = isSubType(info, onType, "java.util.Map"); if (list || map) { Kind parentKind = treePath.getParentPath().getLeaf().getKind(); if (CANNOT_HANDLE_PARENTS.contains(parentKind)) return null; return Collections.singletonList(new ConvertFromArrayAccess(info, treePath, map, parentKind == Kind.ASSIGNMENT).toEditorFix()); } return Collections.emptyList(); }
@Override public Mirror visitArrayAccess(ArrayAccessTree arg0, EvaluationContext evaluationContext) { Mirror array = arg0.getExpression().accept(this, evaluationContext); if (array == null) { Assert.error(arg0, "arrayIsNull", arg0.getExpression()); } Mirror index = arg0.getIndex().accept(this, evaluationContext); if (!(array instanceof ArrayReference)) { Assert.error(arg0, "notArrayType", arg0.getExpression()); } if (!(index instanceof PrimitiveValue)) { Assert.error(arg0, "arraySizeBadType", index); } int i = ((PrimitiveValue) index).intValue(); if (i < 0 || i >= ((ArrayReference) array).length()) { Assert.error(arg0, "arrayIndexOutOfBounds", array, i); } evaluationContext.putArrayAccess(arg0, (ArrayReference)array, i); return ((ArrayReference) array).getValue(i); }
@Override public Description matchTypeCast(TypeCastTree typeCastTree, VisitorState visitorState) { CastingMatcher castingMatcher = new CastingMatcher(); if (!(typeCastTree.getExpression() instanceof IdentifierTree || typeCastTree.getExpression() instanceof ArrayAccessTree)) { return Description.NO_MATCH; } if (castingMatcher.matches(typeCastTree, visitorState)) { return buildDescription(typeCastTree) .addFix( SuggestedFix.replace(castingMatcher.nodeToReplace, typeCastTree.getType().toString())) .build(); } return Description.NO_MATCH; }
@Override public AnnotatedTypeMirror visitArrayAccess(ArrayAccessTree node, AnnotatedTypeFactory f) { Pair<Tree, AnnotatedTypeMirror> preAssCtxt = f.visitorState.getAssignmentContext(); try { // TODO: what other trees shouldn't maintain the context? f.visitorState.setAssignmentContext(null); AnnotatedTypeMirror type = f.getAnnotatedType(node.getExpression()); assert type instanceof AnnotatedArrayType; return ((AnnotatedArrayType)type).getComponentType(); } finally { f.visitorState.setAssignmentContext(preAssCtxt); } }
@Override public Tree visitArrayAccess(ArrayAccessTree tree, Void p) { ArrayAccessTree n = make.ArrayAccess(tree.getExpression(), tree.getIndex()); model.setType(n, model.getType(tree)); comments.copyComments(tree, n); model.setPos(n, model.getPos(tree)); return n; }
public Boolean visitArrayAccess(ArrayAccessTree node, TreePath p) { if (p == null) return super.visitArrayAccess(node, p); ArrayAccessTree t = (ArrayAccessTree) p.getLeaf(); if (!scan(node.getExpression(), t.getExpression(), p)) return false; return scan(node.getIndex(), t.getIndex(), p); }
@Override public Void visitArrayAccess(ArrayAccessTree tree, EnumSet<UseTypes> d) { scan(tree.getExpression(), EnumSet.of(UseTypes.READ)); scan(tree.getIndex(), EnumSet.of(UseTypes.READ)); return null; }
@Override public Void visitArrayAccess(ArrayAccessTree tree, List<Node> d) { List<Node> below = new ArrayList<Node>(); addCorrespondingType(below); addCorrespondingComments(below); super.visitArrayAccess(tree, below); d.add(new TreeNode(info, getCurrentPath(), below)); return null; }
public Boolean visitArrayAccess(ArrayAccessTree node, ConstructorData p) { boolean lv = lValueDereference; // even the array reference is just read from. There's no support to track array-item lvalues. this.lValueDereference = false; scan(node.getExpression(), p); scan(node.getIndex(), p); this.lValueDereference = lv; return null; }
@Override protected void performRewrite(TransformationContext ctx) throws Exception { ArrayAccessTree aa = (ArrayAccessTree) ctx.getPath().getLeaf(); TreeMaker make = ctx.getWorkingCopy().getTreeMaker(); if (assignment) { AssignmentTree at = (AssignmentTree) ctx.getPath().getParentPath().getLeaf(); ctx.getWorkingCopy().rewrite(at, make.MethodInvocation(Collections.<ExpressionTree>emptyList(), make.MemberSelect(aa.getExpression(), map ? " put" : "set"), Arrays.asList(aa.getIndex(), at.getExpression()))); } else { ctx.getWorkingCopy().rewrite(aa, make.MethodInvocation(Collections.<ExpressionTree>emptyList(), make.MemberSelect(aa.getExpression(), "get"), Collections.singletonList(aa.getIndex()))); } }
/** * Index in array access must be int */ @Override public List<? extends TypeMirror> visitArrayAccess(ArrayAccessTree node, Object p) { if (theExpression == null) { return null; } // for now we do not guess array type, just the indexes. if (theExpression == node.getExpression()) { return null; } return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.INT)); }
private Element getElement(Tree tree) { TreePath expPath = TreePath.getPath(cut, tree); Element e = trees.getElement(expPath); if (e == null) { if (tree instanceof ParenthesizedTree) { e = getElement(((ParenthesizedTree) tree).getExpression()); //if (e == null) { // System.err.println("Have null element for "+tree); //} //System.err.println("\nHAVE "+e.asType().toString()+" for ParenthesizedTree "+tree); } else if (tree instanceof TypeCastTree) { e = getElement(((TypeCastTree) tree).getType()); //if (e == null) { // System.err.println("Have null element for "+tree); //} //System.err.println("\nHAVE "+e.asType().toString()+" for TypeCastTree "+tree); } else if (tree instanceof AssignmentTree) { e = getElement(((AssignmentTree) tree).getVariable()); } else if (tree instanceof ArrayAccessTree) { e = getElement(((ArrayAccessTree) tree).getExpression()); if (e != null) { TypeMirror tm = e.asType(); if (tm.getKind() == TypeKind.ARRAY) { tm = ((ArrayType) tm).getComponentType(); e = types.asElement(tm); } } //System.err.println("ArrayAccessTree = "+((ArrayAccessTree) tree).getExpression()+", element = "+getElement(((ArrayAccessTree) tree).getExpression())+", type = "+getElement(((ArrayAccessTree) tree).getExpression()).asType()); } } return e; }
@Override public Description matchArrayAccess(ArrayAccessTree tree, VisitorState state) { if (!matchWithinClass) { return Description.NO_MATCH; } return matchDereference(tree.getExpression(), tree, state); }
/** * Returns the base expression of an erray access, e.g. given {@code foo[0][0]} returns {@code * foo}. */ private ExpressionTree getArrayBase(ExpressionTree node) { while (node instanceof ArrayAccessTree) { node = ((ArrayAccessTree) node).getExpression(); } return node; }
/** * Returns all array indices for the given expression, e.g. given {@code foo[0][0]} returns the * expressions for {@code [0][0]}. */ private Deque<ExpressionTree> getArrayIndices(ExpressionTree expression) { Deque<ExpressionTree> indices = new ArrayDeque<>(); while (expression instanceof ArrayAccessTree) { ArrayAccessTree array = (ArrayAccessTree) expression; indices.addLast(array.getIndex()); expression = array.getExpression(); } return indices; }
@Override public Void visitArrayAccess(ArrayAccessTree tree, VisitorState visitorState) { VisitorState state = visitorState.withPath(getCurrentPath()); for (ArrayAccessTreeMatcher matcher : arrayAccessMatchers) { if (!isSuppressed(matcher, state)) { try { reportMatch(matcher.matchArrayAccess(tree, state), tree, state); } catch (Throwable t) { handleError(matcher, t); } } } return super.visitArrayAccess(tree, state); }
@Override public Choice<State<JCArrayAccess>> visitArrayAccess(final ArrayAccessTree node, State<?> state) { return chooseSubtrees( state, s -> unifyExpression(node.getExpression(), s), s -> unifyExpression(node.getIndex(), s), maker()::Indexed); }
/** * Determines whether two {@link ExpressionTree} instances are equal. Only handles the cases * relevant to this checker: array accesses, identifiers, and literals. Returns false for all * other cases. */ private static boolean expressionsEqual(ExpressionTree expr1, ExpressionTree expr2) { if (!expr1.getKind().equals(expr2.getKind())) { return false; } if (!expr1.getKind().equals(Kind.ARRAY_ACCESS) && !expr1.getKind().equals(Kind.IDENTIFIER) && !(expr1 instanceof LiteralTree)) { return false; } if (expr1.getKind() == Kind.ARRAY_ACCESS) { ArrayAccessTree arrayAccessTree1 = (ArrayAccessTree) expr1; ArrayAccessTree arrayAccessTree2 = (ArrayAccessTree) expr2; return expressionsEqual(arrayAccessTree1.getExpression(), arrayAccessTree2.getExpression()) && expressionsEqual(arrayAccessTree1.getIndex(), arrayAccessTree2.getIndex()); } if (expr1 instanceof LiteralTree) { LiteralTree literalTree1 = (LiteralTree) expr1; LiteralTree literalTree2 = (LiteralTree) expr2; return literalTree1.getValue().equals(literalTree2.getValue()); } return Objects.equal(ASTHelpers.getSymbol(expr1), ASTHelpers.getSymbol(expr2)); }
/** * Builds an AST Tree to dereference an array. * * @param array the array to dereference * @param index the index at which to dereference * @return a Tree representing the dereference */ public ArrayAccessTree buildArrayAccess(ExpressionTree array, ExpressionTree index) { ArrayType arrayType = (ArrayType)InternalUtils.typeOf(array); JCTree.JCArrayAccess access = maker.Indexed((JCTree.JCExpression)array, (JCTree.JCExpression)index); access.setType((Type)arrayType.getComponentType()); return access; }
@Override public PurityResult visitArrayAccess(ArrayAccessTree node, PurityResult p) { PurityResult r = scan(node.getExpression(), p); r = scan(node.getIndex(), r); return r; }
@Override public Void visitArrayAccess(ArrayAccessTree node, Void p) { Pair<Tree, AnnotatedTypeMirror> preAssCtxt = visitorState.getAssignmentContext(); try { visitorState.setAssignmentContext(null); scan(node.getExpression(), p); scan(node.getIndex(), p); } finally { visitorState.setAssignmentContext(preAssCtxt); } return null; }
@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()); }
@Test public void randomParses() { ExpressionTree parsed = parser.parseTree("Class.method()[4].field[3]"); Assert.assertTrue(parsed instanceof ArrayAccessTree); MemberSelectTree array = (MemberSelectTree)((ArrayAccessTree)parsed).getExpression(); Assert.assertEquals("field", array.getIdentifier().toString()); Assert.assertTrue(array.getExpression() instanceof ArrayAccessTree); }
/** * Builds an AST Tree to dereference an array. * * @param array the array to dereference * @param index the index at which to dereference * @return a Tree representing the dereference */ public ArrayAccessTree buildArrayAccess(ExpressionTree array, ExpressionTree index) { ArrayType arrayType = (ArrayType) InternalUtils.typeOf(array); JCTree.JCArrayAccess access = maker.Indexed((JCTree.JCExpression) array, (JCTree.JCExpression) index); access.setType((Type) arrayType.getComponentType()); return access; }
@Override public Void visitArrayAccess(ArrayAccessTree expected, Tree actual) { Optional<ArrayAccessTree> other = checkTypeAndCast(expected, actual); if (!other.isPresent()) { addTypeMismatch(expected, actual); return null; } scan(expected.getExpression(), other.get().getExpression()); scan(expected.getIndex(), other.get().getIndex()); return null; }
private static List<? extends TypeMirror> computeArrayAccess(Set<ElementKind> types, CompilationInfo info, TreePath parent, Tree error, int offset) { ArrayAccessTree aat = (ArrayAccessTree) parent.getLeaf(); if (aat.getExpression() == error) { TreePath parentParent = parent.getParentPath(); List<? extends TypeMirror> upperTypes = resolveType(types, info, parentParent, aat, offset, null, null); if (upperTypes == null) { return null; } List<TypeMirror> arrayTypes = new ArrayList<TypeMirror>(); for (TypeMirror tm : upperTypes) { if (tm == null) continue; switch (tm.getKind()) { case VOID: case EXECUTABLE: case WILDCARD: case PACKAGE: continue; } arrayTypes.add(info.getTypes().getArrayType(tm)); } if (arrayTypes.isEmpty()) return null; return arrayTypes; } if (aat.getIndex() == error) { types.add(ElementKind.PARAMETER); types.add(ElementKind.LOCAL_VARIABLE); types.add(ElementKind.FIELD); return Collections.singletonList(info.getTypes().getPrimitiveType(TypeKind.INT)); } return null; }
public @Override String visitArrayAccess(ArrayAccessTree node, Void p) { return "..." + simpleName(node.getExpression()) + "[]"; // NOI18N }
private String simpleName(Tree t) { if (t == null) { return Bundle.DisplayName_Unknown(); } if (t.getKind() == Kind.IDENTIFIER) { return ((IdentifierTree) t).getName().toString(); } if (t.getKind() == Kind.MEMBER_SELECT) { return ((MemberSelectTree) t).getIdentifier().toString(); } if (t.getKind() == Kind.METHOD_INVOCATION) { return scan(t, null); } if (t.getKind() == Kind.PARAMETERIZED_TYPE) { return simpleName(((ParameterizedTypeTree) t).getType()) + "<...>"; // NOI18N } if (t.getKind() == Kind.ARRAY_ACCESS) { return simpleName(((ArrayAccessTree) t).getExpression()) + "[]"; //NOI18N } if (t.getKind() == Kind.PARENTHESIZED) { return "(" + simpleName(((ParenthesizedTree)t).getExpression()) + ")"; //NOI18N } if (t.getKind() == Kind.TYPE_CAST) { return simpleName(((TypeCastTree)t).getType()); } if (t.getKind() == Kind.ARRAY_TYPE) { return simpleName(((ArrayTypeTree)t).getType()); } if (t.getKind() == Kind.PRIMITIVE_TYPE) { return ((PrimitiveTypeTree) t).getPrimitiveTypeKind().name().toLowerCase(); } throw new IllegalStateException("Currently unsupported kind of tree: " + t.getKind()); // NOI18N }
private static String varNameForTree(Tree et) { if (et == null) return null; switch (et.getKind()) { case IDENTIFIER: return ((IdentifierTree) et).getName().toString(); case MEMBER_SELECT: return ((MemberSelectTree) et).getIdentifier().toString(); case METHOD_INVOCATION: return varNameForTree(((MethodInvocationTree) et).getMethodSelect()); case NEW_CLASS: return firstToLower(varNameForTree(((NewClassTree) et).getIdentifier())); case PARAMETERIZED_TYPE: return firstToLower(varNameForTree(((ParameterizedTypeTree) et).getType())); case STRING_LITERAL: String name = guessLiteralName((String) ((LiteralTree) et).getValue()); if (name == null) { return firstToLower(String.class.getSimpleName()); } else { return firstToLower(name); } case VARIABLE: return ((VariableTree) et).getName().toString(); case ARRAY_ACCESS: name = varNameForTree(((ArrayAccessTree)et).getExpression()); if (name != null) { String singular = getSingular(name); if (singular != null) { return singular; } } return null; case ASSIGNMENT: if (((AssignmentTree)et).getExpression() != null) { return varNameForTree(((AssignmentTree)et).getExpression()); } return null; default: return null; } }
@Override public List<Tree> visitArrayAccess(ArrayAccessTree node, ExpressionScanner.ExpressionsInfo p) { return scan(node.getExpression(), node.getIndex(), p); }
@Override public Void visitArrayAccess(ArrayAccessTree node, Void unused) { sync(node); visitDot(node); return null; }
@Override public R visitArrayAccess(ArrayAccessTree aat, P p) { return null; }
@Override public List<T> visitArrayAccess(ArrayAccessTree node, T p) { return checkForCriteria(node); }
@Override public ArrayAccessTree createArrayAccess(ExpressionTree expression, ExpressionTree index) { return new ArrayAccessTreeImpl(expression, index); }
@Override public Object visitArrayAccess(ArrayAccessTree t, Trees p) { info("ArrayAccessTree" + CL + t.getKind() + SP + t); return super.visitArrayAccess(t, p); }
@Override public UArrayAccess visitArrayAccess(ArrayAccessTree tree, Void v) { return UArrayAccess.create(template(tree.getExpression()), template(tree.getIndex())); }
@Override @Nullable public Unifier visitArrayAccess(ArrayAccessTree arrayAccess, @Nullable Unifier unifier) { unifier = getExpression().unify(arrayAccess.getExpression(), unifier); return getIndex().unify(arrayAccess.getIndex(), unifier); }