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