TreeDissector.java revision 3264:ddfdf0304052
11592Srgrimes/*
21592Srgrimes * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
31592Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41592Srgrimes *
51592Srgrimes * This code is free software; you can redistribute it and/or modify it
61592Srgrimes * under the terms of the GNU General Public License version 2 only, as
71592Srgrimes * published by the Free Software Foundation.  Oracle designates this
81592Srgrimes * particular file as subject to the "Classpath" exception as provided
91592Srgrimes * by Oracle in the LICENSE file that accompanied this code.
101592Srgrimes *
111592Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT
121592Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131592Srgrimes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141592Srgrimes * version 2 for more details (a copy is included in the LICENSE file that
151592Srgrimes * accompanied this code).
161592Srgrimes *
171592Srgrimes * You should have received a copy of the GNU General Public License version
181592Srgrimes * 2 along with this work; if not, write to the Free Software Foundation,
191592Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201592Srgrimes *
211592Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221592Srgrimes * or visit www.oracle.com if you need additional information or have any
231592Srgrimes * questions.
241592Srgrimes */
251592Srgrimes
261592Srgrimespackage jdk.jshell;
271592Srgrimes
281592Srgrimes
291592Srgrimesimport com.sun.source.tree.ClassTree;
301592Srgrimesimport com.sun.source.tree.CompilationUnitTree;
311592Srgrimesimport com.sun.source.tree.ExpressionTree;
321592Srgrimesimport com.sun.source.tree.MethodTree;
331592Srgrimesimport com.sun.source.tree.ReturnTree;
341592Srgrimesimport com.sun.source.tree.StatementTree;
3531512Scharnierimport com.sun.source.tree.Tree;
361592Srgrimesimport com.sun.source.tree.VariableTree;
371592Srgrimesimport com.sun.source.util.SourcePositions;
381592Srgrimesimport com.sun.source.util.TreePath;
391592Srgrimesimport com.sun.source.util.Trees;
401592Srgrimesimport com.sun.tools.javac.code.Type;
4131512Scharnierimport com.sun.tools.javac.code.Type.MethodType;
421592Srgrimesimport com.sun.tools.javac.code.Types;
4331512Scharnierimport com.sun.tools.javac.tree.JCTree.JCMethodDecl;
4431512Scharnierimport com.sun.tools.javac.util.Name;
4550476Speterimport static jdk.jshell.Util.isDoIt;
461592Srgrimesimport jdk.jshell.TaskFactory.AnalyzeTask;
471592Srgrimesimport jdk.jshell.Wrap.Range;
481592Srgrimes
491592Srgrimesimport java.util.List;
501592Srgrimesimport java.util.Locale;
511592Srgrimes
521592Srgrimesimport java.util.function.Predicate;
531592Srgrimesimport java.util.stream.Stream;
541592Srgrimesimport javax.lang.model.type.TypeMirror;
551592Srgrimesimport jdk.jshell.Util.Pair;
561592Srgrimes
571592Srgrimes/**
581592Srgrimes * Utilities for analyzing compiler API parse trees.
5918458Simp * @author Robert Field
601592Srgrimes */
611592Srgrimes
621592Srgrimesclass TreeDissector {
631592Srgrimes
641592Srgrimes    private static final String OBJECT_TYPE = "Object";
651592Srgrimes
661592Srgrimes    static class ExpressionInfo {
671592Srgrimes
6845393Sbrian        boolean isNonVoid;
691592Srgrimes        String typeName;
7031512Scharnier        ExpressionTree tree;
711592Srgrimes        String signature;
721592Srgrimes    }
731592Srgrimes
741592Srgrimes    private final TaskFactory.BaseTask bt;
751592Srgrimes    private final ClassTree targetClass;
761592Srgrimes    private final CompilationUnitTree targetCompilationUnit;
771592Srgrimes    private SourcePositions theSourcePositions = null;
781592Srgrimes
791592Srgrimes    private TreeDissector(TaskFactory.BaseTask bt, CompilationUnitTree targetCompilationUnit, ClassTree targetClass) {
801592Srgrimes        this.bt = bt;
811592Srgrimes        this.targetCompilationUnit = targetCompilationUnit;
8284047Sobrien        this.targetClass = targetClass;
831592Srgrimes    }
841592Srgrimes
851592Srgrimes    static TreeDissector createByFirstClass(TaskFactory.BaseTask bt) {
8684047Sobrien        Pair<CompilationUnitTree, ClassTree> pair = classes(bt.firstCuTree())
871592Srgrimes                .findFirst().orElseGet(() -> new Pair<>(bt.firstCuTree(), null));
881592Srgrimes
891592Srgrimes        return new TreeDissector(bt, pair.first, pair.second);
901592Srgrimes    }
9194443Sume
921592Srgrimes    private static final Predicate<? super Tree> isClassOrInterface =
931592Srgrimes            t -> t.getKind() == Tree.Kind.CLASS || t.getKind() == Tree.Kind.INTERFACE;
9490333Simp
9594443Sume    private static Stream<Pair<CompilationUnitTree, ClassTree>> classes(CompilationUnitTree cut) {
961592Srgrimes        return cut == null
971592Srgrimes                ? Stream.empty()
981592Srgrimes                : cut.getTypeDecls().stream()
991592Srgrimes                        .filter(isClassOrInterface)
1001592Srgrimes                        .map(decl -> new Pair<>(cut, (ClassTree)decl));
1011592Srgrimes    }
1021592Srgrimes
1031592Srgrimes    private static Stream<Pair<CompilationUnitTree, ClassTree>> classes(Iterable<? extends CompilationUnitTree> cuts) {
1041592Srgrimes        return Util.stream(cuts)
1051592Srgrimes                .flatMap(TreeDissector::classes);
106112452Sdwmalone    }
1071592Srgrimes
1081592Srgrimes    static TreeDissector createBySnippet(TaskFactory.BaseTask bt, Snippet si) {
1091592Srgrimes        String name = si.className();
1101592Srgrimes
11171616Sbillf        Pair<CompilationUnitTree, ClassTree> pair = classes(bt.cuTrees())
112129680Smdodd                .filter(p -> p.second.getSimpleName().contentEquals(name))
113129680Smdodd                .findFirst().orElseThrow(() ->
1141592Srgrimes                        new IllegalArgumentException("Class " + name + " is not found."));
115112452Sdwmalone
11690333Simp        return new TreeDissector(bt, pair.first, pair.second);
117112452Sdwmalone    }
1181592Srgrimes
119112452Sdwmalone    Types types() {
120112452Sdwmalone        return bt.types();
121112452Sdwmalone    }
1221592Srgrimes
12390333Simp    Trees trees() {
1241592Srgrimes        return bt.trees();
12590333Simp    }
12690333Simp
1271592Srgrimes    SourcePositions getSourcePositions() {
12894443Sume        if (theSourcePositions == null) {
12994443Sume            theSourcePositions = trees().getSourcePositions();
13018458Simp        }
13118458Simp        return theSourcePositions;
132112452Sdwmalone    }
1331592Srgrimes
13435152Sphk    int getStartPosition(Tree tree) {
135129680Smdodd        return (int) getSourcePositions().getStartPosition(targetCompilationUnit, tree);
1361592Srgrimes    }
13771616Sbillf
13871616Sbillf    int getEndPosition(Tree tree) {
13971616Sbillf        return (int) getSourcePositions().getEndPosition(targetCompilationUnit, tree);
14071616Sbillf    }
14171616Sbillf
14271616Sbillf    Range treeToRange(Tree tree) {
1431592Srgrimes        return new Range(getStartPosition(tree), getEndPosition(tree));
1441592Srgrimes    }
1451592Srgrimes
1461592Srgrimes    Range treeListToRange(List<? extends Tree> treeList) {
1471592Srgrimes        int start = Integer.MAX_VALUE;
1481592Srgrimes        int end = -1;
14918458Simp        for (Tree t : treeList) {
15018458Simp            int tstart = getStartPosition(t);
15118458Simp            int tend = getEndPosition(t);
15265850Swollman            if (tstart < start) {
15365850Swollman                start = tstart;
15465850Swollman            }
155129680Smdodd            if (tend > end) {
156129680Smdodd                end = tend;
157129680Smdodd            }
158129680Smdodd        }
159129680Smdodd        if (start == Integer.MAX_VALUE) {
160129680Smdodd            return null;
1611592Srgrimes        }
1621592Srgrimes        return new Range(start, end);
1631592Srgrimes    }
1641592Srgrimes
1651592Srgrimes    Tree firstClassMember() {
1661592Srgrimes        if (targetClass != null) {
1671592Srgrimes            //TODO: missing classes
1681592Srgrimes            for (Tree mem : targetClass.getMembers()) {
1691592Srgrimes                if (mem.getKind() == Tree.Kind.VARIABLE) {
1701592Srgrimes                    return mem;
1711592Srgrimes                }
1721592Srgrimes                if (mem.getKind() == Tree.Kind.METHOD) {
1731592Srgrimes                    MethodTree mt = (MethodTree) mem;
1741592Srgrimes                    if (!isDoIt(mt.getName()) && !mt.getName().toString().equals("<init>")) {
1751592Srgrimes                        return mt;
1761592Srgrimes                    }
1771592Srgrimes                }
17818458Simp            }
17918458Simp        }
18018458Simp        return null;
18118458Simp    }
182113714Sbillf
18371616Sbillf    StatementTree firstStatement() {
18471616Sbillf        if (targetClass != null) {
18571616Sbillf            for (Tree mem : targetClass.getMembers()) {
1861592Srgrimes                if (mem.getKind() == Tree.Kind.METHOD) {
187129680Smdodd                    MethodTree mt = (MethodTree) mem;
188129680Smdodd                    if (isDoIt(mt.getName())) {
1891592Srgrimes                        List<? extends StatementTree> stmts = mt.getBody().getStatements();
1901592Srgrimes                        if (!stmts.isEmpty()) {
19131512Scharnier                            return stmts.get(0);
1921592Srgrimes                        }
1931592Srgrimes                    }
1941592Srgrimes                }
1951592Srgrimes            }
1961592Srgrimes        }
1971592Srgrimes        return null;
19831512Scharnier    }
1991592Srgrimes
2001592Srgrimes    VariableTree firstVariable() {
2011592Srgrimes        if (targetClass != null) {
2021592Srgrimes            for (Tree mem : targetClass.getMembers()) {
2031592Srgrimes                if (mem.getKind() == Tree.Kind.VARIABLE) {
2041592Srgrimes                    VariableTree vt = (VariableTree) mem;
2051592Srgrimes                    return vt;
2061592Srgrimes                }
2071592Srgrimes            }
2081592Srgrimes        }
2091592Srgrimes        return null;
2101592Srgrimes    }
2111592Srgrimes
2121592Srgrimes
2131592Srgrimes    ExpressionInfo typeOfReturnStatement(AnalyzeTask at, JShell state) {
2141592Srgrimes        ExpressionInfo ei = new ExpressionInfo();
2151592Srgrimes        Tree unitTree = firstStatement();
2161592Srgrimes        if (unitTree instanceof ReturnTree) {
2171592Srgrimes            ei.tree = ((ReturnTree) unitTree).getExpression();
2181592Srgrimes            if (ei.tree != null) {
2191592Srgrimes                TreePath viPath = trees().getPath(targetCompilationUnit, ei.tree);
2201592Srgrimes                if (viPath != null) {
2211592Srgrimes                    TypeMirror tm = trees().getTypeMirror(viPath);
2221592Srgrimes                    if (tm != null) {
2231592Srgrimes                        ei.typeName = printType(at, state, tm);
2241592Srgrimes                        switch (tm.getKind()) {
2251592Srgrimes                            case VOID:
2261592Srgrimes                            case NONE:
2271592Srgrimes                            case ERROR:
2281592Srgrimes                            case OTHER:
2291592Srgrimes                                break;
2301592Srgrimes                            case NULL:
2311592Srgrimes                                ei.isNonVoid = true;
2321592Srgrimes                                ei.typeName = OBJECT_TYPE;
2331592Srgrimes                                break;
2341592Srgrimes                            default: {
2351592Srgrimes                                ei.isNonVoid = true;
2361592Srgrimes                                break;
2371592Srgrimes
2381592Srgrimes                            }
2391592Srgrimes                        }
2401592Srgrimes                    }
2411592Srgrimes                }
2421592Srgrimes            }
2431592Srgrimes        }
2441592Srgrimes        return ei;
24531512Scharnier    }
2461592Srgrimes
2471592Srgrimes    String typeOfMethod() {
2481592Srgrimes        Tree unitTree = firstClassMember();
2491592Srgrimes        if (unitTree instanceof JCMethodDecl) {
2501592Srgrimes            JCMethodDecl mtree = (JCMethodDecl) unitTree;
25118458Simp            Type mt = types().erasure(mtree.type);
25218458Simp            if (mt instanceof MethodType) {
25318458Simp                return signature(types(), (MethodType) mt);
25418458Simp            }
25518458Simp        }
25618458Simp        return null;
25718458Simp    }
258113714Sbillf
25971616Sbillf    static String signature(Types types, MethodType mt) {
26071616Sbillf        TDSignatureGenerator sg = new TDSignatureGenerator(types);
26171616Sbillf        sg.assembleSig(mt);
26294443Sume        return sg.toString();
26394443Sume    }
26471616Sbillf
26594443Sume    public static String printType(AnalyzeTask at, JShell state, TypeMirror type) {
26694443Sume        Type typeImpl = (Type) type;
26794443Sume        TypePrinter tp = new TypePrinter(at.messages(), state.maps::fullClassNameAndPackageToClass, typeImpl);
26894443Sume        return tp.visit(typeImpl, Locale.getDefault());
26994443Sume    }
27094443Sume
271113714Sbillf    /**
272113714Sbillf     * Signature Generation
273113714Sbillf     */
274113714Sbillf    private static class TDSignatureGenerator extends Types.SignatureGenerator {
27571616Sbillf
27671616Sbillf        /**
27718458Simp         * An output buffer for type signatures.
27865850Swollman         */
27965850Swollman        StringBuilder sb = new StringBuilder();
28018458Simp
28118458Simp        TDSignatureGenerator(Types types) {
28218458Simp            super(types);
28318458Simp        }
28418458Simp
28518458Simp        @Override
28618458Simp        protected void append(char ch) {
28718458Simp            sb.append(ch);
28885299Sobrien        }
28918458Simp
29018458Simp        @Override
29194443Sume        protected void append(byte[] ba) {
29294443Sume            sb.append(new String(ba));
29394443Sume        }
29494443Sume
29594443Sume        @Override
29694443Sume        protected void append(Name name) {
29794443Sume            sb.append(name);
29894443Sume        }
29994443Sume
30094443Sume        @Override
30194443Sume        public String toString() {
30294443Sume            return sb.toString();
30394443Sume        }
30494443Sume    }
30594443Sume}
30694443Sume