langtools/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java
changeset 33362 65ec6de1d6b4
child 34857 14d1224cfed3
equal deleted inserted replaced
33361:1c96344ecd49 33362:65ec6de1d6b4
       
     1 /*
       
     2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package jdk.jshell;
       
    27 
       
    28 
       
    29 import com.sun.source.tree.ClassTree;
       
    30 import com.sun.source.tree.CompilationUnitTree;
       
    31 import com.sun.source.tree.ExpressionTree;
       
    32 import com.sun.source.tree.MethodTree;
       
    33 import com.sun.source.tree.ReturnTree;
       
    34 import com.sun.source.tree.StatementTree;
       
    35 import com.sun.source.tree.Tree;
       
    36 import com.sun.source.tree.VariableTree;
       
    37 import com.sun.source.util.SourcePositions;
       
    38 import com.sun.source.util.TreePath;
       
    39 import com.sun.source.util.Trees;
       
    40 import com.sun.tools.javac.code.Type;
       
    41 import com.sun.tools.javac.code.Type.MethodType;
       
    42 import com.sun.tools.javac.code.Types;
       
    43 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
       
    44 import com.sun.tools.javac.util.JavacMessages;
       
    45 import com.sun.tools.javac.util.Name;
       
    46 import static jdk.jshell.Util.isDoIt;
       
    47 import jdk.jshell.Wrap.Range;
       
    48 import java.util.List;
       
    49 import java.util.Locale;
       
    50 import java.util.function.BinaryOperator;
       
    51 import javax.lang.model.type.TypeMirror;
       
    52 
       
    53 /**
       
    54  * Utilities for analyzing compiler API parse trees.
       
    55  * @author Robert Field
       
    56  */
       
    57 
       
    58 class TreeDissector {
       
    59 
       
    60     private static final String OBJECT_TYPE = "Object";
       
    61 
       
    62     static class ExpressionInfo {
       
    63 
       
    64         boolean isNonVoid;
       
    65         String typeName;
       
    66         ExpressionTree tree;
       
    67         String signature;
       
    68     }
       
    69 
       
    70     private final TaskFactory.BaseTask bt;
       
    71     private ClassTree firstClass;
       
    72     private SourcePositions theSourcePositions = null;
       
    73 
       
    74     TreeDissector(TaskFactory.BaseTask bt) {
       
    75         this.bt = bt;
       
    76     }
       
    77 
       
    78 
       
    79     ClassTree firstClass() {
       
    80         if (firstClass == null) {
       
    81             firstClass = computeFirstClass();
       
    82         }
       
    83         return firstClass;
       
    84     }
       
    85 
       
    86     CompilationUnitTree cuTree() {
       
    87         return bt.cuTree();
       
    88     }
       
    89 
       
    90     Types types() {
       
    91         return bt.types();
       
    92     }
       
    93 
       
    94     Trees trees() {
       
    95         return bt.trees();
       
    96     }
       
    97 
       
    98     SourcePositions getSourcePositions() {
       
    99         if (theSourcePositions == null) {
       
   100             theSourcePositions = trees().getSourcePositions();
       
   101         }
       
   102         return theSourcePositions;
       
   103     }
       
   104 
       
   105     int getStartPosition(Tree tree) {
       
   106         return (int) getSourcePositions().getStartPosition(cuTree(), tree);
       
   107     }
       
   108 
       
   109     int getEndPosition(Tree tree) {
       
   110         return (int) getSourcePositions().getEndPosition(cuTree(), tree);
       
   111     }
       
   112 
       
   113     Range treeToRange(Tree tree) {
       
   114         return new Range(getStartPosition(tree), getEndPosition(tree));
       
   115     }
       
   116 
       
   117     Range treeListToRange(List<? extends Tree> treeList) {
       
   118         int start = Integer.MAX_VALUE;
       
   119         int end = -1;
       
   120         for (Tree t : treeList) {
       
   121             int tstart = getStartPosition(t);
       
   122             int tend = getEndPosition(t);
       
   123             if (tstart < start) {
       
   124                 start = tstart;
       
   125             }
       
   126             if (tend > end) {
       
   127                 end = tend;
       
   128             }
       
   129         }
       
   130         if (start == Integer.MAX_VALUE) {
       
   131             return null;
       
   132         }
       
   133         return new Range(start, end);
       
   134     }
       
   135 
       
   136     Tree firstClassMember() {
       
   137         if (firstClass() != null) {
       
   138             //TODO: missing classes
       
   139             for (Tree mem : firstClass().getMembers()) {
       
   140                 if (mem.getKind() == Tree.Kind.VARIABLE) {
       
   141                     return mem;
       
   142                 }
       
   143                 if (mem.getKind() == Tree.Kind.METHOD) {
       
   144                     MethodTree mt = (MethodTree) mem;
       
   145                     if (!isDoIt(mt.getName()) && !mt.getName().toString().equals("<init>")) {
       
   146                         return mt;
       
   147                     }
       
   148                 }
       
   149             }
       
   150         }
       
   151         return null;
       
   152     }
       
   153 
       
   154     StatementTree firstStatement() {
       
   155         if (firstClass() != null) {
       
   156             for (Tree mem : firstClass().getMembers()) {
       
   157                 if (mem.getKind() == Tree.Kind.METHOD) {
       
   158                     MethodTree mt = (MethodTree) mem;
       
   159                     if (isDoIt(mt.getName())) {
       
   160                         List<? extends StatementTree> stmts = mt.getBody().getStatements();
       
   161                         if (!stmts.isEmpty()) {
       
   162                             return stmts.get(0);
       
   163                         }
       
   164                     }
       
   165                 }
       
   166             }
       
   167         }
       
   168         return null;
       
   169     }
       
   170 
       
   171     VariableTree firstVariable() {
       
   172         if (firstClass() != null) {
       
   173             for (Tree mem : firstClass().getMembers()) {
       
   174                 if (mem.getKind() == Tree.Kind.VARIABLE) {
       
   175                     VariableTree vt = (VariableTree) mem;
       
   176                     return vt;
       
   177                 }
       
   178             }
       
   179         }
       
   180         return null;
       
   181     }
       
   182 
       
   183     private ClassTree computeFirstClass() {
       
   184         if (cuTree() == null) {
       
   185             return null;
       
   186         }
       
   187         for (Tree decl : cuTree().getTypeDecls()) {
       
   188             if (decl.getKind() == Tree.Kind.CLASS || decl.getKind() == Tree.Kind.INTERFACE) {
       
   189                 return (ClassTree) decl;
       
   190             }
       
   191         }
       
   192         return null;
       
   193     }
       
   194 
       
   195     ExpressionInfo typeOfReturnStatement(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
       
   196         ExpressionInfo ei = new ExpressionInfo();
       
   197         Tree unitTree = firstStatement();
       
   198         if (unitTree instanceof ReturnTree) {
       
   199             ei.tree = ((ReturnTree) unitTree).getExpression();
       
   200             if (ei.tree != null) {
       
   201                 TreePath viPath = trees().getPath(cuTree(), ei.tree);
       
   202                 if (viPath != null) {
       
   203                     TypeMirror tm = trees().getTypeMirror(viPath);
       
   204                     if (tm != null) {
       
   205                         Type type = (Type)tm;
       
   206                         TypePrinter tp = new TypePrinter(messages, fullClassNameAndPackageToClass, type);
       
   207                         ei.typeName = tp.visit(type, Locale.getDefault());
       
   208                         switch (tm.getKind()) {
       
   209                             case VOID:
       
   210                             case NONE:
       
   211                             case ERROR:
       
   212                             case OTHER:
       
   213                                 break;
       
   214                             case NULL:
       
   215                                 ei.isNonVoid = true;
       
   216                                 ei.typeName = OBJECT_TYPE;
       
   217                                 break;
       
   218                             default: {
       
   219                                 ei.isNonVoid = true;
       
   220                                 break;
       
   221 
       
   222                             }
       
   223                         }
       
   224                     }
       
   225                 }
       
   226             }
       
   227         }
       
   228         return ei;
       
   229     }
       
   230 
       
   231     String typeOfMethod() {
       
   232         Tree unitTree = firstClassMember();
       
   233         if (unitTree instanceof JCMethodDecl) {
       
   234             JCMethodDecl mtree = (JCMethodDecl) unitTree;
       
   235             Type mt = types().erasure(mtree.type);
       
   236             if (mt instanceof MethodType) {
       
   237                 return signature(types(), (MethodType) mt);
       
   238             }
       
   239         }
       
   240         return null;
       
   241     }
       
   242 
       
   243     static String signature(Types types, MethodType mt) {
       
   244         TDSignatureGenerator sg = new TDSignatureGenerator(types);
       
   245         sg.assembleSig(mt);
       
   246         return sg.toString();
       
   247     }
       
   248 
       
   249     /**
       
   250      * Signature Generation
       
   251      */
       
   252     private static class TDSignatureGenerator extends Types.SignatureGenerator {
       
   253 
       
   254         /**
       
   255          * An output buffer for type signatures.
       
   256          */
       
   257         StringBuilder sb = new StringBuilder();
       
   258 
       
   259         TDSignatureGenerator(Types types) {
       
   260             super(types);
       
   261         }
       
   262 
       
   263         @Override
       
   264         protected void append(char ch) {
       
   265             sb.append(ch);
       
   266         }
       
   267 
       
   268         @Override
       
   269         protected void append(byte[] ba) {
       
   270             sb.append(new String(ba));
       
   271         }
       
   272 
       
   273         @Override
       
   274         protected void append(Name name) {
       
   275             sb.append(name);
       
   276         }
       
   277 
       
   278         @Override
       
   279         public String toString() {
       
   280             return sb.toString();
       
   281         }
       
   282     }
       
   283 }