1 /* 2 * Copyright (c) 2014, 2018, 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.MethodTree; 32 import com.sun.source.tree.StatementTree; 33 import com.sun.source.tree.Tree; 34 import com.sun.source.tree.VariableTree; 35 import com.sun.source.util.SourcePositions; 36 import com.sun.source.util.Trees; 37 import com.sun.tools.javac.code.Type; 38 import com.sun.tools.javac.code.Type.MethodType; 39 import com.sun.tools.javac.code.Types; 40 import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 41 import com.sun.tools.javac.util.Name; 42 import static jdk.jshell.Util.isDoIt; 43 import jdk.jshell.TaskFactory.AnalyzeTask; 44 import jdk.jshell.Wrap.Range; 45 46 import java.util.List; 47 48 import java.util.function.Predicate; 49 import java.util.stream.Stream; 50 import javax.lang.model.type.TypeMirror; 51 import jdk.jshell.TypePrinter.AnonymousTypeKind; 52 import jdk.jshell.Util.Pair; 53 54 /** 55 * Utilities for analyzing compiler API parse trees. 56 * @author Robert Field 57 */ 58 59 class TreeDissector { 60 61 private final TaskFactory.BaseTask bt; 62 private final ClassTree targetClass; 63 private final CompilationUnitTree targetCompilationUnit; 64 private SourcePositions theSourcePositions = null; 65 TreeDissector(TaskFactory.BaseTask bt, CompilationUnitTree targetCompilationUnit, ClassTree targetClass)66 private TreeDissector(TaskFactory.BaseTask bt, CompilationUnitTree targetCompilationUnit, ClassTree targetClass) { 67 this.bt = bt; 68 this.targetCompilationUnit = targetCompilationUnit; 69 this.targetClass = targetClass; 70 } 71 createByFirstClass(TaskFactory.BaseTask bt)72 static TreeDissector createByFirstClass(TaskFactory.BaseTask bt) { 73 Pair<CompilationUnitTree, ClassTree> pair = classes(bt.firstCuTree()) 74 .findFirst().orElseGet(() -> new Pair<>(bt.firstCuTree(), null)); 75 76 return new TreeDissector(bt, pair.first, pair.second); 77 } 78 79 private static final Predicate<? super Tree> isClassOrInterface = 80 t -> t.getKind() == Tree.Kind.CLASS || t.getKind() == Tree.Kind.INTERFACE; 81 classes(CompilationUnitTree cut)82 private static Stream<Pair<CompilationUnitTree, ClassTree>> classes(CompilationUnitTree cut) { 83 return cut == null 84 ? Stream.empty() 85 : cut.getTypeDecls().stream() 86 .filter(isClassOrInterface) 87 .map(decl -> new Pair<>(cut, (ClassTree)decl)); 88 } 89 classes(Iterable<? extends CompilationUnitTree> cuts)90 private static Stream<Pair<CompilationUnitTree, ClassTree>> classes(Iterable<? extends CompilationUnitTree> cuts) { 91 return Util.stream(cuts) 92 .flatMap(TreeDissector::classes); 93 } 94 createBySnippet(TaskFactory.BaseTask bt, Snippet si)95 static TreeDissector createBySnippet(TaskFactory.BaseTask bt, Snippet si) { 96 String name = si.className(); 97 98 Pair<CompilationUnitTree, ClassTree> pair = classes(bt.cuTrees()) 99 .filter(p -> p.second.getSimpleName().contentEquals(name)) 100 .findFirst().orElseThrow(() -> 101 new IllegalArgumentException("Class " + name + " is not found.")); 102 103 return new TreeDissector(bt, pair.first, pair.second); 104 } 105 types()106 Types types() { 107 return bt.types(); 108 } 109 trees()110 Trees trees() { 111 return bt.trees(); 112 } 113 getSourcePositions()114 SourcePositions getSourcePositions() { 115 if (theSourcePositions == null) { 116 theSourcePositions = trees().getSourcePositions(); 117 } 118 return theSourcePositions; 119 } 120 getStartPosition(Tree tree)121 int getStartPosition(Tree tree) { 122 return (int) getSourcePositions().getStartPosition(targetCompilationUnit, tree); 123 } 124 getEndPosition(Tree tree)125 int getEndPosition(Tree tree) { 126 return (int) getSourcePositions().getEndPosition(targetCompilationUnit, tree); 127 } 128 treeToRange(Tree tree)129 Range treeToRange(Tree tree) { 130 return new Range(getStartPosition(tree), getEndPosition(tree)); 131 } 132 treeListToRange(List<? extends Tree> treeList)133 Range treeListToRange(List<? extends Tree> treeList) { 134 int start = Integer.MAX_VALUE; 135 int end = -1; 136 for (Tree t : treeList) { 137 int tstart = getStartPosition(t); 138 int tend = getEndPosition(t); 139 if (tstart < start) { 140 start = tstart; 141 } 142 if (tend > end) { 143 end = tend; 144 } 145 } 146 if (start == Integer.MAX_VALUE) { 147 return null; 148 } 149 return new Range(start, end); 150 } 151 method(MethodSnippet msn)152 MethodTree method(MethodSnippet msn) { 153 if (targetClass == null) { 154 return null; 155 } 156 OuterWrap ow = msn.outerWrap(); 157 if (!(ow instanceof OuterSnippetsClassWrap)) { 158 return null; 159 } 160 int ordinal = ((OuterSnippetsClassWrap) ow).ordinal(msn); 161 if (ordinal < 0) { 162 return null; 163 } 164 int count = 0; 165 String name = msn.name(); 166 for (Tree mem : targetClass.getMembers()) { 167 if (mem.getKind() == Tree.Kind.METHOD) { 168 MethodTree mt = (MethodTree) mem; 169 if (mt.getName().toString().equals(name)) { 170 if (count == ordinal) { 171 return mt; 172 } 173 ++count; 174 } 175 } 176 } 177 return null; 178 } 179 firstStatement()180 StatementTree firstStatement() { 181 if (targetClass != null) { 182 for (Tree mem : targetClass.getMembers()) { 183 if (mem.getKind() == Tree.Kind.METHOD) { 184 MethodTree mt = (MethodTree) mem; 185 if (isDoIt(mt.getName())) { 186 List<? extends StatementTree> stmts = mt.getBody().getStatements(); 187 if (!stmts.isEmpty()) { 188 return stmts.get(0); 189 } 190 } 191 } 192 } 193 } 194 return null; 195 } 196 firstVariable()197 VariableTree firstVariable() { 198 if (targetClass != null) { 199 for (Tree mem : targetClass.getMembers()) { 200 if (mem.getKind() == Tree.Kind.VARIABLE) { 201 VariableTree vt = (VariableTree) mem; 202 return vt; 203 } 204 } 205 } 206 return null; 207 } 208 typeOfMethod(MethodSnippet msn)209 String typeOfMethod(MethodSnippet msn) { 210 Tree unitTree = method(msn); 211 if (unitTree instanceof JCMethodDecl) { 212 JCMethodDecl mtree = (JCMethodDecl) unitTree; 213 Type mt = types().erasure(mtree.type); 214 if (mt instanceof MethodType) { 215 return signature(types(), (MethodType) mt); 216 } 217 } 218 return null; 219 } 220 signature(Types types, MethodType mt)221 static String signature(Types types, MethodType mt) { 222 TDSignatureGenerator sg = new TDSignatureGenerator(types); 223 sg.assembleSig(mt); 224 return sg.toString(); 225 } 226 printType(AnalyzeTask at, JShell state, TypeMirror type)227 public static String printType(AnalyzeTask at, JShell state, TypeMirror type) { 228 Type typeImpl = (Type) type; 229 try { 230 TypePrinter tp = new TypePrinter(at.messages(), 231 state.maps::fullClassNameAndPackageToClass, true, AnonymousTypeKind.DISPLAY); 232 return tp.toString(typeImpl); 233 } catch (Exception ex) { 234 return null; 235 } 236 } 237 238 /** 239 * Signature Generation 240 */ 241 private static class TDSignatureGenerator extends Types.SignatureGenerator { 242 243 /** 244 * An output buffer for type signatures. 245 */ 246 StringBuilder sb = new StringBuilder(); 247 TDSignatureGenerator(Types types)248 TDSignatureGenerator(Types types) { 249 super(types); 250 } 251 252 @Override append(char ch)253 protected void append(char ch) { 254 sb.append(ch); 255 } 256 257 @Override append(byte[] ba)258 protected void append(byte[] ba) { 259 sb.append(new String(ba)); 260 } 261 262 @Override append(Name name)263 protected void append(Name name) { 264 sb.append(name); 265 } 266 267 @Override toString()268 public String toString() { 269 return sb.toString(); 270 } 271 } 272 } 273