Search in sources :

Example 6 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project groovy-cps by cloudbees.

the class Translator method translateMethod.

/**
 * @param e
 *      Method in {@code fqcn} to translate.
 */
private void translateMethod(final CompilationUnitTree cut, ExecutableElement e, JDefinedClass $output, String fqcn, String overloadResolved) {
    String methodName = n(e);
    boolean isPublic = e.getModifiers().contains(Modifier.PUBLIC);
    JMethod delegating = $output.method(isPublic ? JMod.PUBLIC | JMod.STATIC : JMod.STATIC, (JType) null, methodName);
    JMethod m = $output.method(JMod.PRIVATE | JMod.STATIC, (JType) null, overloadResolved);
    Map<String, JTypeVar> typeVars = new HashMap<>();
    e.getTypeParameters().forEach(p -> {
        String name = n(p);
        JTypeVar typeVar = delegating.generify(name);
        JTypeVar typeVar2 = m.generify(name);
        p.getBounds().forEach(b -> {
            JClass binding = (JClass) t(b, typeVars);
            typeVar.bound(binding);
            typeVar2.bound(binding);
        });
        typeVars.put(name, typeVar);
    });
    JType type = t(e.getReturnType(), typeVars);
    delegating.type(type);
    m.type(type);
    List<JVar> delegatingParams = new ArrayList<>();
    List<JVar> params = new ArrayList<>();
    e.getParameters().forEach(p -> {
        JType paramType = t(p.asType(), typeVars);
        delegatingParams.add(e.isVarArgs() && p == e.getParameters().get(e.getParameters().size() - 1) ? delegating.varParam(paramType.elementType(), n(p)) : delegating.param(paramType, n(p)));
        params.add(m.param(paramType, n(p)));
    });
    e.getThrownTypes().forEach(ex -> {
        delegating._throws((JClass) t(ex));
        m._throws((JClass) t(ex));
    });
    boolean returnsVoid = e.getReturnType().getKind() == TypeKind.VOID;
    if (isPublic) {
        // preamble
        /*
                If the call to this method happen outside CPS code, execute normally via DefaultGroovyMethods
             */
        delegating.body()._if(JOp.cand(JOp.not($Caller.staticInvoke("isAsynchronous").tap(inv -> {
            inv.arg(delegatingParams.get(0));
            inv.arg(methodName);
            for (int i = 1; i < delegatingParams.size(); i++) inv.arg(delegatingParams.get(i));
        })), JOp.not($Caller.staticInvoke("isAsynchronous").arg($output.dotclass()).arg(methodName).args(params))))._then().tap(blk -> {
            JClass $WhateverGroovyMethods = codeModel.ref(fqcn);
            JInvocation forward = $WhateverGroovyMethods.staticInvoke(methodName).args(delegatingParams);
            if (returnsVoid) {
                blk.add(forward);
                blk._return();
            } else {
                blk._return(forward);
            }
        });
    }
    JInvocation delegateCall = $output.staticInvoke(overloadResolved);
    if (returnsVoid) {
        delegating.body().add(delegateCall);
    } else {
        delegating.body()._return(delegateCall);
    }
    delegatingParams.forEach(p -> delegateCall.arg(p));
    JVar $b = m.body().decl($Builder, "b", JExpr._new($Builder).arg(JExpr.invoke("loc").arg(methodName)).invoke("contextualize").arg(codeModel.ref("com.cloudbees.groovy.cps.sandbox.Trusted").staticRef("INSTANCE")));
    JInvocation f = JExpr._new($CpsFunction);
    // parameter names
    f.arg(codeModel.ref(Arrays.class).staticInvoke("asList").tap(inv -> {
        e.getParameters().forEach(p -> inv.arg(n(p)));
    }));
    // translate the method body into an expression that invokes Builder
    f.arg(trees.getTree(e).getBody().accept(new SimpleTreeVisitor<JExpression, Void>() {

        private JExpression visit(Tree t) {
            if (t == null)
                return JExpr._null();
            return visit(t, null);
        }

        /**
         * Maps a symbol to its source location.
         */
        private JExpression loc(Tree t) {
            long pos = trees.getSourcePositions().getStartPosition(cut, t);
            return JExpr.lit((int) cut.getLineMap().getLineNumber(pos));
        }

        @Override
        public JExpression visitWhileLoop(WhileLoopTree wt, Void __) {
            return $b.invoke("while_").arg(// TODO: label
            JExpr._null()).arg(visit(wt.getCondition())).arg(visit(wt.getStatement()));
        }

        @Override
        public JExpression visitMethodInvocation(MethodInvocationTree mt, Void __) {
            ExpressionTree ms = mt.getMethodSelect();
            JInvocation inv;
            if (ms instanceof MemberSelectTree) {
                MemberSelectTree mst = (MemberSelectTree) ms;
                // of the other known translated classes.
                if (mst.getExpression() instanceof JCIdent && !((JCIdent) mst.getExpression()).sym.toString().equals(fqcn) && otherTranslated.containsKey(((JCIdent) mst.getExpression()).sym.toString())) {
                    inv = $b.invoke("functionCall").arg(loc(mt)).arg($b.invoke("constant").arg(otherTranslated.get(((JCIdent) mst.getExpression()).sym.toString()).dotclass())).arg(n(mst.getIdentifier()));
                } else {
                    inv = $b.invoke("functionCall").arg(loc(mt)).arg(visit(mst.getExpression())).arg(n(mst.getIdentifier()));
                }
            } else if (ms instanceof JCIdent) {
                // invocation without object selection, like  foo(bar,zot)
                JCIdent it = (JCIdent) ms;
                if (!it.sym.owner.toString().equals(fqcn)) {
                    if (otherTranslated.containsKey(it.sym.owner.toString())) {
                        // static import from transformed class
                        inv = $b.invoke("functionCall").arg(loc(mt)).arg($b.invoke("constant").arg(otherTranslated.get(it.sym.owner.toString()).dotclass())).arg(n(it));
                    } else {
                        // static import from non-transformed class
                        inv = $b.invoke("functionCall").arg(loc(mt)).arg($b.invoke("constant").arg(t(it.sym.owner.type).dotclass())).arg(n(it));
                    }
                } else {
                    // invocation on this class
                    String overloadResolved = mangledName((Symbol.MethodSymbol) it.sym);
                    Optional<? extends Element> callSite = elements.getTypeElement(fqcn).getEnclosedElements().stream().filter(e -> e.getKind() == ElementKind.METHOD && mangledName((ExecutableElement) e).equals(overloadResolved)).findAny();
                    if (callSite.isPresent()) {
                        ExecutableElement e = (ExecutableElement) callSite.get();
                        if (e.getModifiers().contains(Modifier.PUBLIC) && !e.isVarArgs() && !e.getParameters().stream().anyMatch(p -> types.isAssignable(p.asType(), closureType))) {
                            // Delegate to the standard version.
                            inv = $b.invoke("staticCall").arg(loc(mt)).arg(t(it.sym.owner.type).dotclass()).arg(n(e));
                        } else if (overloadsResolved.containsKey(overloadResolved)) {
                            // Private, so delegate to our mangled version.
                            // TODO add a String parameter to each internal helper method for the expected methodName to pass to CpsCallableInvocation.<init>
                            // (It could be improved to take a parameter for the name under which we expect methodCall to be invoking it.
                            // Usually just `each`, but might be `$each__java_util_Iterable__groovy_lang_Closure` for the case that one DGM method is delegating to another.
                            // See comment in ContinuationGroup, where we are unable to enforce continuation name mismatches in this case.)
                            inv = $b.invoke("staticCall").arg(loc(mt)).arg($output.dotclass()).arg(overloadResolved);
                        } else {
                            throw new IllegalStateException("Not yet translating a " + e.getModifiers() + " method; translatable.txt might need to include: " + fqcn + "." + e);
                        }
                    } else {
                        throw new IllegalStateException("Could not find self-call site " + overloadResolved + " for " + mt);
                    }
                }
            } else {
                // TODO: figure out what can come here
                throw new UnsupportedOperationException(ms.toString());
            }
            mt.getArguments().forEach(a -> inv.arg(visit(a)));
            return inv;
        }

        @Override
        public JExpression visitVariable(VariableTree vt, Void __) {
            return $b.invoke("declareVariable").arg(loc(vt)).arg(cpsTypeTranslation(erasure(vt))).arg(n(vt)).arg(visit(vt.getInitializer()));
        }

        @Override
        public JExpression visitIdentifier(IdentifierTree it, Void __) {
            JCIdent idt = (JCIdent) it;
            return idt.sym.accept(new DefaultSymbolVisitor<JExpression, Void>() {

                @Override
                public JExpression visitClassSymbol(ClassSymbol cs, Void __) {
                    return $b.invoke("constant").arg(t(cs.asType()).dotclass());
                }

                @Override
                public JExpression visitVarSymbol(VarSymbol s, Void __) {
                    return $b.invoke("localVariable").arg(n(s.name));
                }

                @Override
                public JExpression visitSymbol(Symbol s, Void __) {
                    throw new UnsupportedOperationException(s.toString());
                }
            }, __);
        }

        @Override
        public JExpression visitBlock(BlockTree bt, Void __) {
            JInvocation inv = $b.invoke("block");
            bt.getStatements().forEach(s -> inv.arg(visit(s)));
            return inv;
        }

        @Override
        public JExpression visitReturn(ReturnTree rt, Void __) {
            return $b.invoke("return_").arg(visit(rt.getExpression()));
        }

        /**
         * When used outside {@link MethodInvocationTree}, this is property access.
         */
        @Override
        public JExpression visitMemberSelect(MemberSelectTree mt, Void __) {
            return $b.invoke("property").arg(loc(mt)).arg(visit(mt.getExpression())).arg(n(mt.getIdentifier()));
        }

        @Override
        public JExpression visitTypeCast(TypeCastTree tt, Void __) {
            return $b.invoke("cast").arg(loc(tt)).arg(visit(tt.getExpression())).arg(erasure(tt.getType()).dotclass()).arg(JExpr.lit(false));
        }

        @Override
        public JExpression visitIf(IfTree it, Void __) {
            JInvocation inv = $b.invoke("if_").arg(visit(it.getCondition())).arg(visit(it.getThenStatement()));
            if (it.getElseStatement() != null)
                inv.arg(visit(it.getElseStatement()));
            return inv;
        }

        @Override
        public JExpression visitNewClass(NewClassTree nt, Void __) {
            // TODO: outer class
            if (nt.getEnclosingExpression() != null)
                throw new UnsupportedOperationException();
            return $b.invoke("new_").tap(inv -> {
                inv.arg(loc(nt));
                inv.arg(cpsTypeTranslation(t(((JCTree) nt).type)));
                nt.getArguments().forEach(et -> inv.arg(visit(et)));
            });
        }

        @Override
        public JExpression visitExpressionStatement(ExpressionStatementTree et, Void __) {
            return visit(et.getExpression());
        }

        @Override
        public JExpression visitLiteral(LiteralTree lt, Void __) {
            return $b.invoke("constant").arg(JExpr.literal(lt.getValue()));
        }

        @Override
        public JExpression visitParenthesized(ParenthesizedTree pt, Void __) {
            return visit(pt.getExpression());
        }

        @Override
        public JExpression visitBinary(BinaryTree bt, Void __) {
            return $b.invoke(opName(bt.getKind())).arg(loc(bt)).arg(visit(bt.getLeftOperand())).arg(visit(bt.getRightOperand()));
        }

        @Override
        public JExpression visitUnary(UnaryTree ut, Void __) {
            return $b.invoke(opName(ut.getKind())).arg(loc(ut)).arg(visit(ut.getExpression()));
        }

        @Override
        public JExpression visitCompoundAssignment(CompoundAssignmentTree ct, Void __) {
            return $b.invoke(opName(ct.getKind())).arg(loc(ct)).arg(visit(ct.getVariable())).arg(visit(ct.getExpression()));
        }

        private String opName(Kind kind) {
            switch(kind) {
                case EQUAL_TO:
                    return "compareEqual";
                case NOT_EQUAL_TO:
                    return "compareNotEqual";
                case LESS_THAN_EQUAL:
                    return "lessThanEqual";
                case LESS_THAN:
                    return "lessThan";
                case GREATER_THAN_EQUAL:
                    return "greaterThanEqual";
                case GREATER_THAN:
                    return "greaterThan";
                case PREFIX_INCREMENT:
                    return "prefixInc";
                case POSTFIX_INCREMENT:
                    return "postfixInc";
                case POSTFIX_DECREMENT:
                    return "postfixDec";
                case LOGICAL_COMPLEMENT:
                    return "not";
                case CONDITIONAL_OR:
                    return "logicalOr";
                case CONDITIONAL_AND:
                    return "logicalAnd";
                case PLUS:
                    return "plus";
                case PLUS_ASSIGNMENT:
                    return "plusEqual";
                case MINUS:
                    return "minus";
                case MINUS_ASSIGNMENT:
                    return "minusEqual";
            }
            throw new UnsupportedOperationException(kind.toString());
        }

        @Override
        public JExpression visitAssignment(AssignmentTree at, Void __) {
            return $b.invoke("assign").arg(loc(at)).arg(visit(at.getVariable())).arg(visit(at.getExpression()));
        }

        /**
         * This is needed to handle cases like {@code Object[].class}.
         */
        @Override
        public JExpression visitArrayType(ArrayTypeTree at, Void __) {
            if (at.getType() instanceof IdentifierTree) {
                return visitIdentifier((IdentifierTree) at.getType(), __);
            } else {
                return defaultAction(at, __);
            }
        }

        @Override
        public JExpression visitNewArray(NewArrayTree nt, Void __) {
            if (nt.getInitializers() != null) {
                return $b.invoke("newArrayFromInitializers").tap(inv -> {
                    nt.getInitializers().forEach(d -> inv.arg(visit(d)));
                });
            } else {
                return $b.invoke("newArray").tap(inv -> {
                    inv.arg(loc(nt));
                    inv.arg(t(nt.getType()).dotclass());
                    nt.getDimensions().forEach(d -> inv.arg(visit(d)));
                });
            }
        }

        @Override
        public JExpression visitForLoop(ForLoopTree ft, Void __) {
            return $b.invoke("forLoop").arg(JExpr._null()).arg($b.invoke("sequence").tap(inv -> ft.getInitializer().forEach(i -> inv.arg(visit(i))))).arg(visit(ft.getCondition())).arg($b.invoke("sequence").tap(inv -> ft.getUpdate().forEach(i -> inv.arg(visit(i))))).arg(visit(ft.getStatement()));
        }

        @Override
        public JExpression visitEnhancedForLoop(EnhancedForLoopTree et, Void __) {
            return $b.invoke("forInLoop").arg(loc(et)).arg(JExpr._null()).arg(erasure(et.getVariable()).dotclass()).arg(n(et.getVariable())).arg(visit(et.getExpression())).arg(visit(et.getStatement()));
        }

        @Override
        public JExpression visitArrayAccess(ArrayAccessTree at, Void __) {
            return $b.invoke("array").arg(loc(at)).arg(visit(at.getExpression())).arg(visit(at.getIndex()));
        }

        @Override
        public JExpression visitBreak(BreakTree node, Void __) {
            if (node.getLabel() != null)
                throw new UnsupportedOperationException();
            return $b.invoke("break_").arg(JExpr._null());
        }

        @Override
        public JExpression visitContinue(ContinueTree node, Void aVoid) {
            if (node.getLabel() != null)
                throw new UnsupportedOperationException();
            return $b.invoke("continue_").arg(JExpr._null());
        }

        @Override
        public JExpression visitInstanceOf(InstanceOfTree it, Void __) {
            return $b.invoke("instanceOf").arg(loc(it)).arg(visit(it.getExpression())).arg($b.invoke("constant").arg(t(it.getType()).dotclass()));
        }

        @Override
        public JExpression visitThrow(ThrowTree tt, Void __) {
            return $b.invoke("throw_").arg(loc(tt)).arg(visit(tt.getExpression()));
        }

        @Override
        public JExpression visitDoWhileLoop(DoWhileLoopTree dt, Void __) {
            return $b.invoke("doWhile").arg(JExpr._null()).arg(visit(dt.getStatement())).arg(visit(dt.getCondition()));
        }

        @Override
        public JExpression visitConditionalExpression(ConditionalExpressionTree ct, Void __) {
            return $b.invoke("ternaryOp").arg(visit(ct.getCondition())).arg(visit(ct.getTrueExpression())).arg(visit(ct.getFalseExpression()));
        }

        @Override
        public JExpression visitTry(TryTree tt, Void __) {
            return $b.invoke("tryCatch").arg(visit(tt.getBlock())).arg(visit(tt.getFinallyBlock())).tap(inv -> tt.getCatches().forEach(ct -> JExpr._new($CatchExpression).arg(t(ct.getParameter()).dotclass()).arg(n(ct.getParameter())).arg(visit(ct.getBlock()))));
        }

        @Override
        protected JExpression defaultAction(Tree node, Void aVoid) {
            throw new UnsupportedOperationException(node.toString());
        }
    }, null));
    JVar $f = m.body().decl($CpsFunction, "f", f);
    m.body()._throw(JExpr._new($CpsCallableInvocation).arg(JExpr.lit(methodName)).arg($f).arg(JExpr._null()).args(params));
}
Also used : CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) Arrays(java.util.Arrays) LiteralTree(com.sun.source.tree.LiteralTree) JCodeModel(com.sun.codemodel.JCodeModel) Modifier(javax.lang.model.element.Modifier) Closure(groovy.lang.Closure) TypeElement(javax.lang.model.element.TypeElement) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) Elements(javax.lang.model.util.Elements) JExpr(com.sun.codemodel.JExpr) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) TypeCastTree(com.sun.source.tree.TypeCastTree) Map(java.util.Map) ForLoopTree(com.sun.source.tree.ForLoopTree) Trees(com.sun.source.util.Trees) InstanceOfTree(com.sun.source.tree.InstanceOfTree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) ArrayType(javax.lang.model.type.ArrayType) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) DefaultSymbolVisitor(com.sun.tools.javac.code.Types.DefaultSymbolVisitor) Symbol(com.sun.tools.javac.code.Symbol) Set(java.util.Set) Element(javax.lang.model.element.Element) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) StandardCharsets(java.nio.charset.StandardCharsets) ThrowTree(com.sun.source.tree.ThrowTree) BlockTree(com.sun.source.tree.BlockTree) JCIdent(com.sun.tools.javac.tree.JCTree.JCIdent) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) ReturnTree(com.sun.source.tree.ReturnTree) ArrayTypeTree(com.sun.source.tree.ArrayTypeTree) UnaryTree(com.sun.source.tree.UnaryTree) JInvocation(com.sun.codemodel.JInvocation) VariableTree(com.sun.source.tree.VariableTree) ArrayList(java.util.ArrayList) Kind(com.sun.source.tree.Tree.Kind) NewClassTree(com.sun.source.tree.NewClassTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) DeclaredType(javax.lang.model.type.DeclaredType) BreakTree(com.sun.source.tree.BreakTree) Tree(com.sun.source.tree.Tree) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) JClassAlreadyExistsException(com.sun.codemodel.JClassAlreadyExistsException) Resources(com.google.common.io.Resources) JDefinedClass(com.sun.codemodel.JDefinedClass) ExpressionTree(com.sun.source.tree.ExpressionTree) IOException(java.io.IOException) TreeMap(java.util.TreeMap) WildcardTree(com.sun.source.tree.WildcardTree) ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) JVar(com.sun.codemodel.JVar) SimpleTypeVisitor6(javax.lang.model.util.SimpleTypeVisitor6) Date(java.util.Date) JMethod(com.sun.codemodel.JMethod) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) JExpression(com.sun.codemodel.JExpression) Generated(javax.annotation.Generated) CompilationTask(javax.tools.JavaCompiler.CompilationTask) IdentifierTree(com.sun.source.tree.IdentifierTree) NewArrayTree(com.sun.source.tree.NewArrayTree) WildcardType(javax.lang.model.type.WildcardType) JMod(com.sun.codemodel.JMod) JOp(com.sun.codemodel.JOp) JavacTask(com.sun.source.util.JavacTask) ContinueTree(com.sun.source.tree.ContinueTree) SimpleTreeVisitor(com.sun.source.util.SimpleTreeVisitor) Types(javax.lang.model.util.Types) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) TypeKind(javax.lang.model.type.TypeKind) TypeVariableSymbol(com.sun.tools.javac.code.Symbol.TypeVariableSymbol) List(java.util.List) ElementScanner7(javax.lang.model.util.ElementScanner7) JType(com.sun.codemodel.JType) PrimitiveTypeTree(com.sun.source.tree.PrimitiveTypeTree) TypeVariable(javax.lang.model.type.TypeVariable) Optional(java.util.Optional) WhileLoopTree(com.sun.source.tree.WhileLoopTree) BinaryTree(com.sun.source.tree.BinaryTree) HashMap(java.util.HashMap) JTypeVar(com.sun.codemodel.JTypeVar) HashSet(java.util.HashSet) CodeWriter(com.sun.codemodel.CodeWriter) ClassTree(com.sun.source.tree.ClassTree) Name(javax.lang.model.element.Name) IfTree(com.sun.source.tree.IfTree) ElementKind(javax.lang.model.element.ElementKind) NoType(javax.lang.model.type.NoType) ExecutableElement(javax.lang.model.element.ExecutableElement) JCTree(com.sun.tools.javac.tree.JCTree) TypeMirror(javax.lang.model.type.TypeMirror) DoWhileLoopTree(com.sun.source.tree.DoWhileLoopTree) TryTree(com.sun.source.tree.TryTree) PrimitiveType(javax.lang.model.type.PrimitiveType) JClass(com.sun.codemodel.JClass) Collections(java.util.Collections) TypeCastTree(com.sun.source.tree.TypeCastTree) HashMap(java.util.HashMap) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ArrayList(java.util.ArrayList) BinaryTree(com.sun.source.tree.BinaryTree) IdentifierTree(com.sun.source.tree.IdentifierTree) ReturnTree(com.sun.source.tree.ReturnTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) JTypeVar(com.sun.codemodel.JTypeVar) Kind(com.sun.source.tree.Tree.Kind) TypeKind(javax.lang.model.type.TypeKind) ElementKind(javax.lang.model.element.ElementKind) ThrowTree(com.sun.source.tree.ThrowTree) InstanceOfTree(com.sun.source.tree.InstanceOfTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) AssignmentTree(com.sun.source.tree.AssignmentTree) TypeCastTree(com.sun.source.tree.TypeCastTree) ForLoopTree(com.sun.source.tree.ForLoopTree) InstanceOfTree(com.sun.source.tree.InstanceOfTree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) ThrowTree(com.sun.source.tree.ThrowTree) BlockTree(com.sun.source.tree.BlockTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) ReturnTree(com.sun.source.tree.ReturnTree) ArrayTypeTree(com.sun.source.tree.ArrayTypeTree) UnaryTree(com.sun.source.tree.UnaryTree) VariableTree(com.sun.source.tree.VariableTree) NewClassTree(com.sun.source.tree.NewClassTree) ParameterizedTypeTree(com.sun.source.tree.ParameterizedTypeTree) BreakTree(com.sun.source.tree.BreakTree) Tree(com.sun.source.tree.Tree) ExpressionTree(com.sun.source.tree.ExpressionTree) WildcardTree(com.sun.source.tree.WildcardTree) ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) IdentifierTree(com.sun.source.tree.IdentifierTree) NewArrayTree(com.sun.source.tree.NewArrayTree) ContinueTree(com.sun.source.tree.ContinueTree) CompilationUnitTree(com.sun.source.tree.CompilationUnitTree) PrimitiveTypeTree(com.sun.source.tree.PrimitiveTypeTree) WhileLoopTree(com.sun.source.tree.WhileLoopTree) BinaryTree(com.sun.source.tree.BinaryTree) ClassTree(com.sun.source.tree.ClassTree) IfTree(com.sun.source.tree.IfTree) JCTree(com.sun.tools.javac.tree.JCTree) DoWhileLoopTree(com.sun.source.tree.DoWhileLoopTree) TryTree(com.sun.source.tree.TryTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AssignmentTree(com.sun.source.tree.AssignmentTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) JType(com.sun.codemodel.JType) DoWhileLoopTree(com.sun.source.tree.DoWhileLoopTree) JCIdent(com.sun.tools.javac.tree.JCTree.JCIdent) Optional(java.util.Optional) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) IfTree(com.sun.source.tree.IfTree) Arrays(java.util.Arrays) TryTree(com.sun.source.tree.TryTree) ArrayTypeTree(com.sun.source.tree.ArrayTypeTree) ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) ClassSymbol(com.sun.tools.javac.code.Symbol.ClassSymbol) Symbol(com.sun.tools.javac.code.Symbol) VarSymbol(com.sun.tools.javac.code.Symbol.VarSymbol) TypeVariableSymbol(com.sun.tools.javac.code.Symbol.TypeVariableSymbol) TypeElement(javax.lang.model.element.TypeElement) Element(javax.lang.model.element.Element) ExecutableElement(javax.lang.model.element.ExecutableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) VariableTree(com.sun.source.tree.VariableTree) ParenthesizedTree(com.sun.source.tree.ParenthesizedTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) NewClassTree(com.sun.source.tree.NewClassTree) BreakTree(com.sun.source.tree.BreakTree) LiteralTree(com.sun.source.tree.LiteralTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) BlockTree(com.sun.source.tree.BlockTree) ContinueTree(com.sun.source.tree.ContinueTree) UnaryTree(com.sun.source.tree.UnaryTree) JVar(com.sun.codemodel.JVar) SimpleTreeVisitor(com.sun.source.util.SimpleTreeVisitor) JClass(com.sun.codemodel.JClass) ForLoopTree(com.sun.source.tree.ForLoopTree) EnhancedForLoopTree(com.sun.source.tree.EnhancedForLoopTree) ExpressionStatementTree(com.sun.source.tree.ExpressionStatementTree) JInvocation(com.sun.codemodel.JInvocation) JExpression(com.sun.codemodel.JExpression) NewArrayTree(com.sun.source.tree.NewArrayTree) WhileLoopTree(com.sun.source.tree.WhileLoopTree) DoWhileLoopTree(com.sun.source.tree.DoWhileLoopTree) JMethod(com.sun.codemodel.JMethod)

Example 7 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class CollectionToArrayHeuristics method isHandledArrayCreation.

/**
 * Returns true if {@code argument} is one of the array creation trees that the heuristic handles.
 *
 * @param argument the tree passed to {@link Collection#toArray(Object[]) Collection.toArray(T[])}
 * @param receiver the expression for the receiver collection
 * @return true if the argument is handled and assume to return nonnull elements
 */
private boolean isHandledArrayCreation(Tree argument, String receiver) {
    if (argument.getKind() != Tree.Kind.NEW_ARRAY) {
        return false;
    }
    NewArrayTree newArr = (NewArrayTree) argument;
    // empty array initializer
    if (newArr.getInitializers() != null) {
        return newArr.getInitializers().isEmpty();
    }
    assert !newArr.getDimensions().isEmpty();
    Tree dimension = newArr.getDimensions().get(newArr.getDimensions().size() - 1);
    // 0-length array creation
    if (dimension.toString().equals("0")) {
        return true;
    }
    // size()-length array creation
    if (TreeUtils.isMethodInvocation(dimension, size, processingEnv)) {
        MethodInvocationTree invok = (MethodInvocationTree) dimension;
        String invokReceiver = receiverName(invok.getMethodSelect());
        return invokReceiver.equals(receiver);
    }
    return false;
}
Also used : NewArrayTree(com.sun.source.tree.NewArrayTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree) MemberSelectTree(com.sun.source.tree.MemberSelectTree) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) NewArrayTree(com.sun.source.tree.NewArrayTree) Tree(com.sun.source.tree.Tree)

Example 8 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class BaseTypeVisitor method visitAnnotation.

/**
 * Ensure that the annotation arguments comply to their declarations. This needs some special
 * casing, as annotation arguments form special trees.
 */
@Override
public Void visitAnnotation(AnnotationTree node, Void p) {
    List<? extends ExpressionTree> args = node.getArguments();
    if (args.isEmpty()) {
        // Nothing to do if there are no annotation arguments.
        return null;
    }
    TypeElement anno = (TypeElement) TreeInfo.symbol((JCTree) node.getAnnotationType());
    Name annoName = anno.getQualifiedName();
    if (annoName.contentEquals(DefaultQualifier.class.getName()) || annoName.contentEquals(SuppressWarnings.class.getName())) {
        // Skip these two annotations, as we don't care about the arguments to them.
        return null;
    }
    List<ExecutableElement> methods = ElementFilter.methodsIn(anno.getEnclosedElements());
    // Mapping from argument simple name to its annotated type.
    Map<String, AnnotatedTypeMirror> annoTypes = new HashMap<>(methods.size());
    for (ExecutableElement meth : methods) {
        AnnotatedExecutableType exeatm = atypeFactory.getAnnotatedType(meth);
        AnnotatedTypeMirror retty = exeatm.getReturnType();
        annoTypes.put(meth.getSimpleName().toString(), retty);
    }
    for (ExpressionTree arg : args) {
        if (!(arg instanceof AssignmentTree)) {
            // TODO: when can this happen?
            continue;
        }
        AssignmentTree at = (AssignmentTree) arg;
        // we don't have a type for annotations.
        if (at.getExpression().getKind() == Tree.Kind.ANNOTATION) {
            visitAnnotation((AnnotationTree) at.getExpression(), p);
            continue;
        }
        if (at.getExpression().getKind() == Tree.Kind.NEW_ARRAY) {
            NewArrayTree nat = (NewArrayTree) at.getExpression();
            boolean isAnno = false;
            for (ExpressionTree init : nat.getInitializers()) {
                if (init.getKind() == Tree.Kind.ANNOTATION) {
                    visitAnnotation((AnnotationTree) init, p);
                    isAnno = true;
                }
            }
            if (isAnno) {
                continue;
            }
        }
        AnnotatedTypeMirror expected = annoTypes.get(at.getVariable().toString());
        AnnotatedTypeMirror actual = atypeFactory.getAnnotatedType(at.getExpression());
        if (expected.getKind() != TypeKind.ARRAY) {
            // Expected is not an array -> direct comparison.
            commonAssignmentCheck(expected, actual, at.getExpression(), "annotation");
        } else if (actual.getKind() == TypeKind.ARRAY) {
            // Both actual and expected are arrays.
            commonAssignmentCheck(expected, actual, at.getExpression(), "annotation");
        } else {
            // The declaration is an array type, but just a single element is given.
            commonAssignmentCheck(((AnnotatedArrayType) expected).getComponentType(), actual, at.getExpression(), "annotation");
        }
    }
    return null;
}
Also used : HashMap(java.util.HashMap) TypeElement(javax.lang.model.element.TypeElement) ExecutableElement(javax.lang.model.element.ExecutableElement) JCTree(com.sun.tools.javac.tree.JCTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror) Name(javax.lang.model.element.Name) AnnotatedExecutableType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedExecutableType) AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) NewArrayTree(com.sun.source.tree.NewArrayTree) LambdaExpressionTree(com.sun.source.tree.LambdaExpressionTree) ConditionalExpressionTree(com.sun.source.tree.ConditionalExpressionTree) ExpressionTree(com.sun.source.tree.ExpressionTree) CompoundAssignmentTree(com.sun.source.tree.CompoundAssignmentTree) AssignmentTree(com.sun.source.tree.AssignmentTree)

Example 9 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class BaseTypeVisitor method commonAssignmentCheck.

/**
 * Checks the validity of an assignment (or pseudo-assignment) from a value to a variable and
 * emits an error message (through the compiler's messaging interface) if it is not valid.
 *
 * @param varType the annotated type for the lvalue (usually a variable)
 * @param valueExp the AST node for the rvalue (the new value)
 * @param errorKey the error message key to use if the check fails
 * @param extraArgs arguments to the error message key, before "found" and "expected" types
 */
protected void commonAssignmentCheck(AnnotatedTypeMirror varType, ExpressionTree valueExp, @CompilerMessageKey String errorKey, Object... extraArgs) {
    if (shouldSkipUses(valueExp)) {
        return;
    }
    if (valueExp.getKind() == Tree.Kind.MEMBER_REFERENCE || valueExp.getKind() == Tree.Kind.LAMBDA_EXPRESSION) {
        // and do not need to be checked again as arguments.
        return;
    }
    if (varType.getKind() == TypeKind.ARRAY && valueExp instanceof NewArrayTree && ((NewArrayTree) valueExp).getType() == null) {
        AnnotatedTypeMirror compType = ((AnnotatedArrayType) varType).getComponentType();
        NewArrayTree arrayTree = (NewArrayTree) valueExp;
        assert arrayTree.getInitializers() != null : "array initializers are not expected to be null in: " + valueExp;
        checkArrayInitialization(compType, arrayTree.getInitializers());
    }
    if (!validateTypeOf(valueExp)) {
        return;
    }
    AnnotatedTypeMirror valueType = atypeFactory.getAnnotatedType(valueExp);
    assert valueType != null : "null type for expression: " + valueExp;
    commonAssignmentCheck(varType, valueType, valueExp, errorKey, extraArgs);
}
Also used : AnnotatedArrayType(org.checkerframework.framework.type.AnnotatedTypeMirror.AnnotatedArrayType) NewArrayTree(com.sun.source.tree.NewArrayTree) AnnotatedTypeMirror(org.checkerframework.framework.type.AnnotatedTypeMirror)

Example 10 with NewArrayTree

use of com.sun.source.tree.NewArrayTree in project checker-framework by typetools.

the class FlowExpressions method internalReprOf.

/**
 * We ignore operations such as widening and narrowing when computing the internal
 * representation.
 *
 * @return the internal representation (as {@link Receiver}) of any {@link ExpressionTree}.
 *     Might contain {@link Unknown}.
 */
public static Receiver internalReprOf(AnnotationProvider provider, ExpressionTree receiverTree, boolean allowNonDeterministic) {
    Receiver receiver;
    switch(receiverTree.getKind()) {
        case ARRAY_ACCESS:
            ArrayAccessTree a = (ArrayAccessTree) receiverTree;
            Receiver arrayAccessExpression = internalReprOf(provider, a.getExpression());
            Receiver index = internalReprOf(provider, a.getIndex());
            receiver = new ArrayAccess(TreeUtils.typeOf(a), arrayAccessExpression, index);
            break;
        case BOOLEAN_LITERAL:
        case CHAR_LITERAL:
        case DOUBLE_LITERAL:
        case FLOAT_LITERAL:
        case INT_LITERAL:
        case LONG_LITERAL:
        case NULL_LITERAL:
        case STRING_LITERAL:
            LiteralTree vn = (LiteralTree) receiverTree;
            receiver = new ValueLiteral(TreeUtils.typeOf(receiverTree), vn.getValue());
            break;
        case NEW_ARRAY:
            NewArrayTree newArrayTree = (NewArrayTree) receiverTree;
            List<Receiver> dimensions = new ArrayList<>();
            if (newArrayTree.getDimensions() != null) {
                for (ExpressionTree dimension : newArrayTree.getDimensions()) {
                    dimensions.add(internalReprOf(provider, dimension, allowNonDeterministic));
                }
            }
            List<Receiver> initializers = new ArrayList<>();
            if (newArrayTree.getInitializers() != null) {
                for (ExpressionTree initializer : newArrayTree.getInitializers()) {
                    initializers.add(internalReprOf(provider, initializer, allowNonDeterministic));
                }
            }
            receiver = new ArrayCreation(TreeUtils.typeOf(receiverTree), dimensions, initializers);
            break;
        case METHOD_INVOCATION:
            MethodInvocationTree mn = (MethodInvocationTree) receiverTree;
            ExecutableElement invokedMethod = TreeUtils.elementFromUse(mn);
            if (PurityUtils.isDeterministic(provider, invokedMethod) || allowNonDeterministic) {
                List<Receiver> parameters = new ArrayList<>();
                for (ExpressionTree p : mn.getArguments()) {
                    parameters.add(internalReprOf(provider, p));
                }
                Receiver methodReceiver;
                if (ElementUtils.isStatic(invokedMethod)) {
                    methodReceiver = new ClassName(TreeUtils.typeOf(mn.getMethodSelect()));
                } else {
                    ExpressionTree methodReceiverTree = TreeUtils.getReceiverTree(mn);
                    if (methodReceiverTree != null) {
                        methodReceiver = internalReprOf(provider, methodReceiverTree);
                    } else {
                        methodReceiver = internalReprOfImplicitReceiver(invokedMethod);
                    }
                }
                TypeMirror type = TreeUtils.typeOf(mn);
                receiver = new MethodCall(type, invokedMethod, methodReceiver, parameters);
            } else {
                receiver = null;
            }
            break;
        case MEMBER_SELECT:
            receiver = internalReprOfMemberSelect(provider, (MemberSelectTree) receiverTree);
            break;
        case IDENTIFIER:
            IdentifierTree identifierTree = (IdentifierTree) receiverTree;
            TypeMirror typeOfId = TreeUtils.typeOf(identifierTree);
            if (identifierTree.getName().contentEquals("this") || identifierTree.getName().contentEquals("super")) {
                receiver = new ThisReference(typeOfId);
                break;
            }
            Element ele = TreeUtils.elementFromUse(identifierTree);
            switch(ele.getKind()) {
                case LOCAL_VARIABLE:
                case RESOURCE_VARIABLE:
                case EXCEPTION_PARAMETER:
                case PARAMETER:
                    receiver = new LocalVariable(ele);
                    break;
                case FIELD:
                    // Implicit access expression, such as "this" or a class name
                    Receiver fieldAccessExpression;
                    TypeMirror enclosingType = ElementUtils.enclosingClass(ele).asType();
                    if (ElementUtils.isStatic(ele)) {
                        fieldAccessExpression = new ClassName(enclosingType);
                    } else {
                        fieldAccessExpression = new ThisReference(enclosingType);
                    }
                    receiver = new FieldAccess(fieldAccessExpression, typeOfId, (VariableElement) ele);
                    break;
                case CLASS:
                case ENUM:
                case ANNOTATION_TYPE:
                case INTERFACE:
                    receiver = new ClassName(ele.asType());
                    break;
                default:
                    receiver = null;
            }
            break;
        default:
            receiver = null;
    }
    if (receiver == null) {
        receiver = new Unknown(TreeUtils.typeOf(receiverTree));
    }
    return receiver;
}
Also used : ArrayAccessTree(com.sun.source.tree.ArrayAccessTree) ExecutableElement(javax.lang.model.element.ExecutableElement) MemberSelectTree(com.sun.source.tree.MemberSelectTree) VariableElement(javax.lang.model.element.VariableElement) ExecutableElement(javax.lang.model.element.ExecutableElement) Element(javax.lang.model.element.Element) ArrayList(java.util.ArrayList) IdentifierTree(com.sun.source.tree.IdentifierTree) VariableElement(javax.lang.model.element.VariableElement) LiteralTree(com.sun.source.tree.LiteralTree) NewArrayTree(com.sun.source.tree.NewArrayTree) TypeMirror(javax.lang.model.type.TypeMirror) MethodInvocationTree(com.sun.source.tree.MethodInvocationTree) ExpressionTree(com.sun.source.tree.ExpressionTree)

Aggregations

NewArrayTree (com.sun.source.tree.NewArrayTree)21 ExpressionTree (com.sun.source.tree.ExpressionTree)19 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)12 Tree (com.sun.source.tree.Tree)11 AssignmentTree (com.sun.source.tree.AssignmentTree)10 CompoundAssignmentTree (com.sun.source.tree.CompoundAssignmentTree)10 MemberSelectTree (com.sun.source.tree.MemberSelectTree)10 BinaryTree (com.sun.source.tree.BinaryTree)9 ArrayAccessTree (com.sun.source.tree.ArrayAccessTree)8 ConditionalExpressionTree (com.sun.source.tree.ConditionalExpressionTree)8 IdentifierTree (com.sun.source.tree.IdentifierTree)8 LiteralTree (com.sun.source.tree.LiteralTree)8 MethodTree (com.sun.source.tree.MethodTree)8 NewClassTree (com.sun.source.tree.NewClassTree)8 TypeCastTree (com.sun.source.tree.TypeCastTree)8 VariableTree (com.sun.source.tree.VariableTree)8 ClassTree (com.sun.source.tree.ClassTree)7 ParameterizedTypeTree (com.sun.source.tree.ParameterizedTypeTree)6 ReturnTree (com.sun.source.tree.ReturnTree)6 ExecutableElement (javax.lang.model.element.ExecutableElement)6