JavacTrees.java revision 3074:522e516b8a83
172445Sassar/* 272445Sassar * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. 3178825Sdfr * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 472445Sassar * 572445Sassar * This code is free software; you can redistribute it and/or modify it 672445Sassar * under the terms of the GNU General Public License version 2 only, as 7178825Sdfr * published by the Free Software Foundation. Oracle designates this 872445Sassar * particular file as subject to the "Classpath" exception as provided 972445Sassar * by Oracle in the LICENSE file that accompanied this code. 1072445Sassar * 1190926Snectar * This code is distributed in the hope that it will be useful, but WITHOUT 1272445Sassar * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13178825Sdfr * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1472445Sassar * version 2 for more details (a copy is included in the LICENSE file that 1572445Sassar * accompanied this code). 1672445Sassar * 1772445Sassar * You should have received a copy of the GNU General Public License version 1890926Snectar * 2 along with this work; if not, write to the Free Software Foundation, 1990926Snectar * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2072445Sassar * 2190926Snectar * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22178825Sdfr * or visit www.oracle.com if you need additional information or have any 23178825Sdfr * questions. 24178825Sdfr */ 25178825Sdfr 26178825Sdfrpackage com.sun.tools.javac.api; 27178825Sdfr 28178825Sdfrimport java.io.FileNotFoundException; 29178825Sdfrimport java.io.IOException; 30178825Sdfrimport java.text.BreakIterator; 31178825Sdfrimport java.util.HashSet; 3272445Sassarimport java.util.Set; 3372445Sassarimport java.util.regex.Matcher; 3490926Snectarimport java.util.regex.Pattern; 35178825Sdfr 36178825Sdfrimport javax.annotation.processing.ProcessingEnvironment; 37178825Sdfrimport javax.lang.model.element.AnnotationMirror; 38178825Sdfrimport javax.lang.model.element.AnnotationValue; 3990926Snectarimport javax.lang.model.element.Element; 40178825Sdfrimport javax.lang.model.element.ElementKind; 4190926Snectarimport javax.lang.model.element.ExecutableElement; 4290926Snectarimport javax.lang.model.element.Modifier; 4390926Snectarimport javax.lang.model.element.NestingKind; 44178825Sdfrimport javax.lang.model.element.PackageElement; 45178825Sdfrimport javax.lang.model.element.TypeElement; 4690926Snectarimport javax.lang.model.type.DeclaredType; 4790926Snectarimport javax.lang.model.type.TypeKind; 4890926Snectarimport javax.lang.model.type.TypeMirror; 49178825Sdfrimport javax.tools.Diagnostic; 5090926Snectarimport javax.tools.FileObject; 51178825Sdfrimport javax.tools.ForwardingFileObject; 5290926Snectarimport javax.tools.ForwardingJavaFileObject; 5390926Snectarimport javax.tools.JavaCompiler; 5490926Snectarimport javax.tools.JavaFileManager; 55178825Sdfrimport javax.tools.JavaFileObject; 56178825Sdfrimport javax.tools.JavaFileObject.Kind; 5790926Snectarimport javax.tools.StandardLocation; 5890926Snectar 5990926Snectarimport com.sun.source.doctree.DocCommentTree; 6090926Snectarimport com.sun.source.doctree.DocTree; 61178825Sdfrimport com.sun.source.tree.CatchTree; 62178825Sdfrimport com.sun.source.tree.CompilationUnitTree; 63178825Sdfrimport com.sun.source.tree.Scope; 64178825Sdfrimport com.sun.source.tree.Tree; 65178825Sdfrimport com.sun.source.util.DocSourcePositions; 66178825Sdfrimport com.sun.source.util.DocTreePath; 67178825Sdfrimport com.sun.source.util.DocTreeScanner; 68178825Sdfrimport com.sun.source.util.DocTrees; 69178825Sdfrimport com.sun.source.util.JavacTask; 7090926Snectarimport com.sun.source.util.TreePath; 7190926Snectarimport com.sun.tools.javac.code.Flags; 7272445Sassarimport com.sun.tools.javac.code.Symbol; 73import com.sun.tools.javac.code.Symbol.ClassSymbol; 74import com.sun.tools.javac.code.Symbol.MethodSymbol; 75import com.sun.tools.javac.code.Symbol.PackageSymbol; 76import com.sun.tools.javac.code.Symbol.TypeSymbol; 77import com.sun.tools.javac.code.Symbol.VarSymbol; 78import com.sun.tools.javac.code.Type; 79import com.sun.tools.javac.code.Type.ArrayType; 80import com.sun.tools.javac.code.Type.ClassType; 81import com.sun.tools.javac.code.Type.ErrorType; 82import com.sun.tools.javac.code.Type.UnionClassType; 83import com.sun.tools.javac.code.Types; 84import com.sun.tools.javac.code.Types.TypeRelation; 85import com.sun.tools.javac.comp.Attr; 86import com.sun.tools.javac.comp.AttrContext; 87import com.sun.tools.javac.comp.Enter; 88import com.sun.tools.javac.comp.Env; 89import com.sun.tools.javac.comp.MemberEnter; 90import com.sun.tools.javac.comp.Resolve; 91import com.sun.tools.javac.file.BaseFileManager; 92import com.sun.tools.javac.model.JavacElements; 93import com.sun.tools.javac.parser.DocCommentParser; 94import com.sun.tools.javac.parser.ParserFactory; 95import com.sun.tools.javac.parser.Tokens.Comment; 96import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; 97import com.sun.tools.javac.processing.JavacProcessingEnvironment; 98import com.sun.tools.javac.tree.DCTree; 99import com.sun.tools.javac.tree.DCTree.DCBlockTag; 100import com.sun.tools.javac.tree.DCTree.DCDocComment; 101import com.sun.tools.javac.tree.DCTree.DCEndPosTree; 102import com.sun.tools.javac.tree.DCTree.DCErroneous; 103import com.sun.tools.javac.tree.DCTree.DCIdentifier; 104import com.sun.tools.javac.tree.DCTree.DCParam; 105import com.sun.tools.javac.tree.DCTree.DCReference; 106import com.sun.tools.javac.tree.DCTree.DCText; 107import com.sun.tools.javac.tree.DocTreeMaker; 108import com.sun.tools.javac.tree.EndPosTable; 109import com.sun.tools.javac.tree.JCTree; 110import com.sun.tools.javac.tree.JCTree.JCBlock; 111import com.sun.tools.javac.tree.JCTree.JCCatch; 112import com.sun.tools.javac.tree.JCTree.JCClassDecl; 113import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; 114import com.sun.tools.javac.tree.JCTree.JCExpression; 115import com.sun.tools.javac.tree.JCTree.JCIdent; 116import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 117import com.sun.tools.javac.tree.JCTree.JCVariableDecl; 118import com.sun.tools.javac.tree.TreeCopier; 119import com.sun.tools.javac.tree.TreeInfo; 120import com.sun.tools.javac.tree.TreeMaker; 121import com.sun.tools.javac.util.Abort; 122import com.sun.tools.javac.util.Assert; 123import com.sun.tools.javac.util.Context; 124import com.sun.tools.javac.util.DefinedBy; 125import com.sun.tools.javac.util.DefinedBy.Api; 126import com.sun.tools.javac.util.DiagnosticSource; 127import com.sun.tools.javac.util.JCDiagnostic; 128import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; 129import com.sun.tools.javac.util.List; 130import com.sun.tools.javac.util.ListBuffer; 131import com.sun.tools.javac.util.Log; 132import com.sun.tools.javac.util.Name; 133import com.sun.tools.javac.util.Names; 134import com.sun.tools.javac.util.Pair; 135import com.sun.tools.javac.util.Position; 136 137import static com.sun.tools.javac.code.Kinds.Kind.*; 138import static com.sun.tools.javac.code.TypeTag.*; 139 140/** 141 * Provides an implementation of Trees. 142 * 143 * <p><b>This is NOT part of any supported API. 144 * If you write code that depends on this, you do so at your own 145 * risk. This code and its internal interfaces are subject to change 146 * or deletion without notice.</b></p> 147 * 148 * @author Peter von der Ahé 149 */ 150public class JavacTrees extends DocTrees { 151 152 // in a world of a single context per compilation, these would all be final 153 private Resolve resolve; 154 private Enter enter; 155 private Log log; 156 private MemberEnter memberEnter; 157 private Attr attr; 158 private TreeMaker treeMaker; 159 private JavacElements elements; 160 private JavacTaskImpl javacTaskImpl; 161 private Names names; 162 private Types types; 163 private DocTreeMaker doctreeMaker; 164 private BreakIterator breakIterator; 165 private JavaFileManager fileManager; 166 private ParserFactory parser; 167 168 // called reflectively from Trees.instance(CompilationTask task) 169 public static JavacTrees instance(JavaCompiler.CompilationTask task) { 170 if (!(task instanceof BasicJavacTask)) 171 throw new IllegalArgumentException(); 172 return instance(((BasicJavacTask)task).getContext()); 173 } 174 175 // called reflectively from Trees.instance(ProcessingEnvironment env) 176 public static JavacTrees instance(ProcessingEnvironment env) { 177 if (!(env instanceof JavacProcessingEnvironment)) 178 throw new IllegalArgumentException(); 179 return instance(((JavacProcessingEnvironment)env).getContext()); 180 } 181 182 public static JavacTrees instance(Context context) { 183 JavacTrees instance = context.get(JavacTrees.class); 184 if (instance == null) 185 instance = new JavacTrees(context); 186 return instance; 187 } 188 189 protected JavacTrees(Context context) { 190 this.breakIterator = null; 191 context.put(JavacTrees.class, this); 192 init(context); 193 } 194 195 public void updateContext(Context context) { 196 init(context); 197 } 198 199 private void init(Context context) { 200 attr = Attr.instance(context); 201 enter = Enter.instance(context); 202 elements = JavacElements.instance(context); 203 log = Log.instance(context); 204 resolve = Resolve.instance(context); 205 treeMaker = TreeMaker.instance(context); 206 memberEnter = MemberEnter.instance(context); 207 names = Names.instance(context); 208 types = Types.instance(context); 209 doctreeMaker = DocTreeMaker.instance(context); 210 parser = ParserFactory.instance(context); 211 fileManager = context.get(JavaFileManager.class); 212 JavacTask t = context.get(JavacTask.class); 213 if (t instanceof JavacTaskImpl) 214 javacTaskImpl = (JavacTaskImpl) t; 215 } 216 217 @Override @DefinedBy(Api.COMPILER_TREE) 218 public BreakIterator getBreakIterator() { 219 return breakIterator; 220 } 221 222 @Override @DefinedBy(Api.COMPILER_TREE) 223 public DocSourcePositions getSourcePositions() { 224 return new DocSourcePositions() { 225 @Override @DefinedBy(Api.COMPILER_TREE) 226 public long getStartPosition(CompilationUnitTree file, Tree tree) { 227 return TreeInfo.getStartPos((JCTree) tree); 228 } 229 230 @Override @DefinedBy(Api.COMPILER_TREE) 231 public long getEndPosition(CompilationUnitTree file, Tree tree) { 232 EndPosTable endPosTable = ((JCCompilationUnit) file).endPositions; 233 return TreeInfo.getEndPos((JCTree) tree, endPosTable); 234 } 235 236 @Override @DefinedBy(Api.COMPILER_TREE) 237 public long getStartPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { 238 return ((DCTree) tree).getSourcePosition((DCDocComment) comment); 239 } 240 @Override @DefinedBy(Api.COMPILER_TREE) @SuppressWarnings("fallthrough") 241 public long getEndPosition(CompilationUnitTree file, DocCommentTree comment, DocTree tree) { 242 DCDocComment dcComment = (DCDocComment) comment; 243 if (tree instanceof DCEndPosTree) { 244 int endPos = ((DCEndPosTree) tree).getEndPos(dcComment); 245 246 if (endPos != Position.NOPOS) { 247 return endPos; 248 } 249 } 250 int correction = 0; 251 switch (tree.getKind()) { 252 case TEXT: 253 DCText text = (DCText) tree; 254 255 return dcComment.comment.getSourcePos(text.pos + text.text.length()); 256 case ERRONEOUS: 257 DCErroneous err = (DCErroneous) tree; 258 259 return dcComment.comment.getSourcePos(err.pos + err.body.length()); 260 case IDENTIFIER: 261 DCIdentifier ident = (DCIdentifier) tree; 262 263 return dcComment.comment.getSourcePos(ident.pos + (ident.name != names.error ? ident.name.length() : 0)); 264 case PARAM: 265 DCParam param = (DCParam) tree; 266 267 if (param.isTypeParameter && param.getDescription().isEmpty()) { 268 correction = 1; 269 } 270 case AUTHOR: case DEPRECATED: case RETURN: case SEE: 271 case SERIAL: case SERIAL_DATA: case SERIAL_FIELD: case SINCE: 272 case THROWS: case UNKNOWN_BLOCK_TAG: case VERSION: { 273 DocTree last = getLastChild(tree); 274 275 if (last != null) { 276 return getEndPosition(file, comment, last) + correction; 277 } 278 279 DCBlockTag block = (DCBlockTag) tree; 280 281 return dcComment.comment.getSourcePos(block.pos + block.getTagName().length() + 1); 282 } 283 default: 284 DocTree last = getLastChild(tree); 285 286 if (last != null) { 287 return getEndPosition(file, comment, last); 288 } 289 break; 290 } 291 292 return Position.NOPOS; 293 } 294 }; 295 } 296 297 private DocTree getLastChild(DocTree tree) { 298 final DocTree[] last = new DocTree[] {null}; 299 300 tree.accept(new DocTreeScanner<Void, Void>() { 301 @Override @DefinedBy(Api.COMPILER_TREE) 302 public Void scan(DocTree node, Void p) { 303 if (node != null) last[0] = node; 304 return null; 305 } 306 }, null); 307 308 return last[0]; 309 } 310 311 @Override @DefinedBy(Api.COMPILER_TREE) 312 public JCClassDecl getTree(TypeElement element) { 313 return (JCClassDecl) getTree((Element) element); 314 } 315 316 @Override @DefinedBy(Api.COMPILER_TREE) 317 public JCMethodDecl getTree(ExecutableElement method) { 318 return (JCMethodDecl) getTree((Element) method); 319 } 320 321 @Override @DefinedBy(Api.COMPILER_TREE) 322 public JCTree getTree(Element element) { 323 return getTree(element, null); 324 } 325 326 @Override @DefinedBy(Api.COMPILER_TREE) 327 public JCTree getTree(Element e, AnnotationMirror a) { 328 return getTree(e, a, null); 329 } 330 331 @Override @DefinedBy(Api.COMPILER_TREE) 332 public JCTree getTree(Element e, AnnotationMirror a, AnnotationValue v) { 333 Pair<JCTree, JCCompilationUnit> treeTopLevel = elements.getTreeAndTopLevel(e, a, v); 334 if (treeTopLevel == null) 335 return null; 336 return treeTopLevel.fst; 337 } 338 339 @Override @DefinedBy(Api.COMPILER_TREE) 340 public TreePath getPath(CompilationUnitTree unit, Tree node) { 341 return TreePath.getPath(unit, node); 342 } 343 344 @Override @DefinedBy(Api.COMPILER_TREE) 345 public TreePath getPath(Element e) { 346 return getPath(e, null, null); 347 } 348 349 @Override @DefinedBy(Api.COMPILER_TREE) 350 public TreePath getPath(Element e, AnnotationMirror a) { 351 return getPath(e, a, null); 352 } 353 354 @Override @DefinedBy(Api.COMPILER_TREE) 355 public TreePath getPath(Element e, AnnotationMirror a, AnnotationValue v) { 356 final Pair<JCTree, JCCompilationUnit> treeTopLevel = elements.getTreeAndTopLevel(e, a, v); 357 if (treeTopLevel == null) 358 return null; 359 return TreePath.getPath(treeTopLevel.snd, treeTopLevel.fst); 360 } 361 362 @Override @DefinedBy(Api.COMPILER_TREE) 363 public Symbol getElement(TreePath path) { 364 JCTree tree = (JCTree) path.getLeaf(); 365 Symbol sym = TreeInfo.symbolFor(tree); 366 if (sym == null) { 367 if (TreeInfo.isDeclaration(tree)) { 368 for (TreePath p = path; p != null; p = p.getParentPath()) { 369 JCTree t = (JCTree) p.getLeaf(); 370 if (t.hasTag(JCTree.Tag.CLASSDEF)) { 371 JCClassDecl ct = (JCClassDecl) t; 372 if (ct.sym != null) { 373 if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) { 374 attr.attribClass(ct.pos(), ct.sym); 375 sym = TreeInfo.symbolFor(tree); 376 } 377 break; 378 } 379 } 380 } 381 } 382 } 383 return sym; 384 } 385 386 @Override @DefinedBy(Api.COMPILER_TREE) 387 public Element getElement(DocTreePath path) { 388 DocTree forTree = path.getLeaf(); 389 if (forTree instanceof DCReference) 390 return attributeDocReference(path.getTreePath(), ((DCReference) forTree)); 391 if (forTree instanceof DCIdentifier) { 392 if (path.getParentPath().getLeaf() instanceof DCParam) { 393 return attributeParamIdentifier(path.getTreePath(), (DCParam) path.getParentPath().getLeaf()); 394 } 395 } 396 return null; 397 } 398 399 @Override @DefinedBy(Api.COMPILER_TREE) 400 public java.util.List<DocTree> getFirstSentence(java.util.List<? extends DocTree> list) { 401 return doctreeMaker.getFirstSentence(list); 402 } 403 404 private Symbol attributeDocReference(TreePath path, DCReference ref) { 405 Env<AttrContext> env = getAttrContext(path); 406 407 Log.DeferredDiagnosticHandler deferredDiagnosticHandler = 408 new Log.DeferredDiagnosticHandler(log); 409 try { 410 final TypeSymbol tsym; 411 final Name memberName; 412 if (ref.qualifierExpression == null) { 413 tsym = env.enclClass.sym; 414 memberName = ref.memberName; 415 } else { 416 // See if the qualifierExpression is a type or package name. 417 // javac does not provide the exact method required, so 418 // we first check if qualifierExpression identifies a type, 419 // and if not, then we check to see if it identifies a package. 420 Type t = attr.attribType(ref.qualifierExpression, env); 421 if (t.isErroneous()) { 422 if (ref.memberName == null) { 423 // Attr/Resolve assume packages exist and create symbols as needed 424 // so use getPackageElement to restrict search to existing packages 425 PackageSymbol pck = elements.getPackageElement(ref.qualifierExpression.toString()); 426 if (pck != null) { 427 return pck; 428 } else if (ref.qualifierExpression.hasTag(JCTree.Tag.IDENT)) { 429 // fixup: allow "identifier" instead of "#identifier" 430 // for compatibility with javadoc 431 tsym = env.enclClass.sym; 432 memberName = ((JCIdent) ref.qualifierExpression).name; 433 } else 434 return null; 435 } else { 436 return null; 437 } 438 } else { 439 tsym = t.tsym; 440 memberName = ref.memberName; 441 } 442 } 443 444 if (memberName == null) 445 return tsym; 446 447 final List<Type> paramTypes; 448 if (ref.paramTypes == null) 449 paramTypes = null; 450 else { 451 ListBuffer<Type> lb = new ListBuffer<>(); 452 for (List<JCTree> l = ref.paramTypes; l.nonEmpty(); l = l.tail) { 453 JCTree tree = l.head; 454 Type t = attr.attribType(tree, env); 455 lb.add(t); 456 } 457 paramTypes = lb.toList(); 458 } 459 460 ClassSymbol sym = (ClassSymbol) types.cvarUpperBound(tsym.type).tsym; 461 462 Symbol msym = (memberName == sym.name) 463 ? findConstructor(sym, paramTypes) 464 : findMethod(sym, memberName, paramTypes); 465 if (paramTypes != null) { 466 // explicit (possibly empty) arg list given, so cannot be a field 467 return msym; 468 } 469 470 VarSymbol vsym = (ref.paramTypes != null) ? null : findField(sym, memberName); 471 // prefer a field over a method with no parameters 472 if (vsym != null && 473 (msym == null || 474 types.isSubtypeUnchecked(vsym.enclClass().asType(), msym.enclClass().asType()))) { 475 return vsym; 476 } else { 477 return msym; 478 } 479 } catch (Abort e) { // may be thrown by Check.completionError in case of bad class file 480 return null; 481 } finally { 482 log.popDiagnosticHandler(deferredDiagnosticHandler); 483 } 484 } 485 486 private Symbol attributeParamIdentifier(TreePath path, DCParam ptag) { 487 Symbol javadocSymbol = getElement(path); 488 if (javadocSymbol == null) 489 return null; 490 ElementKind kind = javadocSymbol.getKind(); 491 List<? extends Symbol> params = List.nil(); 492 if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) { 493 MethodSymbol ee = (MethodSymbol) javadocSymbol; 494 params = ptag.isTypeParameter() 495 ? ee.getTypeParameters() 496 : ee.getParameters(); 497 } else if (kind.isClass() || kind.isInterface()) { 498 ClassSymbol te = (ClassSymbol) javadocSymbol; 499 params = te.getTypeParameters(); 500 } 501 502 for (Symbol param : params) { 503 if (param.getSimpleName() == ptag.getName().getName()) { 504 return param; 505 } 506 } 507 return null; 508 } 509 510 /** @see com.sun.tools.javadoc.ClassDocImpl#findField */ 511 private VarSymbol findField(ClassSymbol tsym, Name fieldName) { 512 return searchField(tsym, fieldName, new HashSet<>()); 513 } 514 515 /** @see com.sun.tools.javadoc.ClassDocImpl#searchField */ 516 private VarSymbol searchField(ClassSymbol tsym, Name fieldName, Set<ClassSymbol> searched) { 517 if (searched.contains(tsym)) { 518 return null; 519 } 520 searched.add(tsym); 521 522 for (Symbol sym : tsym.members().getSymbolsByName(fieldName)) { 523 if (sym.kind == VAR) { 524 return (VarSymbol)sym; 525 } 526 } 527 528 //### If we found a VarSymbol above, but which did not pass 529 //### the modifier filter, we should return failure here! 530 531 ClassSymbol encl = tsym.owner.enclClass(); 532 if (encl != null) { 533 VarSymbol vsym = searchField(encl, fieldName, searched); 534 if (vsym != null) { 535 return vsym; 536 } 537 } 538 539 // search superclass 540 Type superclass = tsym.getSuperclass(); 541 if (superclass.tsym != null) { 542 VarSymbol vsym = searchField((ClassSymbol) superclass.tsym, fieldName, searched); 543 if (vsym != null) { 544 return vsym; 545 } 546 } 547 548 // search interfaces 549 List<Type> intfs = tsym.getInterfaces(); 550 for (List<Type> l = intfs; l.nonEmpty(); l = l.tail) { 551 Type intf = l.head; 552 if (intf.isErroneous()) continue; 553 VarSymbol vsym = searchField((ClassSymbol) intf.tsym, fieldName, searched); 554 if (vsym != null) { 555 return vsym; 556 } 557 } 558 559 return null; 560 } 561 562 /** @see com.sun.tools.javadoc.ClassDocImpl#findConstructor */ 563 MethodSymbol findConstructor(ClassSymbol tsym, List<Type> paramTypes) { 564 for (Symbol sym : tsym.members().getSymbolsByName(names.init)) { 565 if (sym.kind == MTH) { 566 if (hasParameterTypes((MethodSymbol) sym, paramTypes)) { 567 return (MethodSymbol) sym; 568 } 569 } 570 } 571 return null; 572 } 573 574 /** @see com.sun.tools.javadoc.ClassDocImpl#findMethod */ 575 private MethodSymbol findMethod(ClassSymbol tsym, Name methodName, List<Type> paramTypes) { 576 return searchMethod(tsym, methodName, paramTypes, new HashSet<>()); 577 } 578 579 /** @see com.sun.tools.javadoc.ClassDocImpl#searchMethod */ 580 private MethodSymbol searchMethod(ClassSymbol tsym, Name methodName, 581 List<Type> paramTypes, Set<ClassSymbol> searched) { 582 //### Note that this search is not necessarily what the compiler would do! 583 584 // do not match constructors 585 if (methodName == names.init) 586 return null; 587 588 if (searched.contains(tsym)) 589 return null; 590 searched.add(tsym); 591 592 // search current class 593 594 //### Using modifier filter here isn't really correct, 595 //### but emulates the old behavior. Instead, we should 596 //### apply the normal rules of visibility and inheritance. 597 598 if (paramTypes == null) { 599 // If no parameters specified, we are allowed to return 600 // any method with a matching name. In practice, the old 601 // code returned the first method, which is now the last! 602 // In order to provide textually identical results, we 603 // attempt to emulate the old behavior. 604 MethodSymbol lastFound = null; 605 for (Symbol sym : tsym.members().getSymbolsByName(methodName)) { 606 if (sym.kind == MTH) { 607 if (sym.name == methodName) { 608 lastFound = (MethodSymbol)sym; 609 } 610 } 611 } 612 if (lastFound != null) { 613 return lastFound; 614 } 615 } else { 616 for (Symbol sym : tsym.members().getSymbolsByName(methodName)) { 617 if (sym != null && 618 sym.kind == MTH) { 619 if (hasParameterTypes((MethodSymbol) sym, paramTypes)) { 620 return (MethodSymbol) sym; 621 } 622 } 623 } 624 } 625 626 //### If we found a MethodSymbol above, but which did not pass 627 //### the modifier filter, we should return failure here! 628 629 // search superclass 630 Type superclass = tsym.getSuperclass(); 631 if (superclass.tsym != null) { 632 MethodSymbol msym = searchMethod((ClassSymbol) superclass.tsym, methodName, paramTypes, searched); 633 if (msym != null) { 634 return msym; 635 } 636 } 637 638 // search interfaces 639 List<Type> intfs = tsym.getInterfaces(); 640 for (List<Type> l = intfs; l.nonEmpty(); l = l.tail) { 641 Type intf = l.head; 642 if (intf.isErroneous()) continue; 643 MethodSymbol msym = searchMethod((ClassSymbol) intf.tsym, methodName, paramTypes, searched); 644 if (msym != null) { 645 return msym; 646 } 647 } 648 649 // search enclosing class 650 ClassSymbol encl = tsym.owner.enclClass(); 651 if (encl != null) { 652 MethodSymbol msym = searchMethod(encl, methodName, paramTypes, searched); 653 if (msym != null) { 654 return msym; 655 } 656 } 657 658 return null; 659 } 660 661 /** @see com.sun.tools.javadoc.ClassDocImpl */ 662 private boolean hasParameterTypes(MethodSymbol method, List<Type> paramTypes) { 663 if (paramTypes == null) 664 return true; 665 666 if (method.params().size() != paramTypes.size()) 667 return false; 668 669 List<Type> methodParamTypes = types.erasureRecursive(method.asType()).getParameterTypes(); 670 671 return (Type.isErroneous(paramTypes)) 672 ? fuzzyMatch(paramTypes, methodParamTypes) 673 : types.isSameTypes(paramTypes, methodParamTypes); 674 } 675 676 boolean fuzzyMatch(List<Type> paramTypes, List<Type> methodParamTypes) { 677 List<Type> l1 = paramTypes; 678 List<Type> l2 = methodParamTypes; 679 while (l1.nonEmpty()) { 680 if (!fuzzyMatch(l1.head, l2.head)) 681 return false; 682 l1 = l1.tail; 683 l2 = l2.tail; 684 } 685 return true; 686 } 687 688 boolean fuzzyMatch(Type paramType, Type methodParamType) { 689 Boolean b = fuzzyMatcher.visit(paramType, methodParamType); 690 return (b == Boolean.TRUE); 691 } 692 693 TypeRelation fuzzyMatcher = new TypeRelation() { 694 @Override 695 public Boolean visitType(Type t, Type s) { 696 if (t == s) 697 return true; 698 699 if (s.isPartial()) 700 return visit(s, t); 701 702 switch (t.getTag()) { 703 case BYTE: case CHAR: case SHORT: case INT: case LONG: case FLOAT: 704 case DOUBLE: case BOOLEAN: case VOID: case BOT: case NONE: 705 return t.hasTag(s.getTag()); 706 default: 707 throw new AssertionError("fuzzyMatcher " + t.getTag()); 708 } 709 } 710 711 @Override 712 public Boolean visitArrayType(ArrayType t, Type s) { 713 if (t == s) 714 return true; 715 716 if (s.isPartial()) 717 return visit(s, t); 718 719 return s.hasTag(ARRAY) 720 && visit(t.elemtype, types.elemtype(s)); 721 } 722 723 @Override 724 public Boolean visitClassType(ClassType t, Type s) { 725 if (t == s) 726 return true; 727 728 if (s.isPartial()) 729 return visit(s, t); 730 731 return t.tsym == s.tsym; 732 } 733 734 @Override 735 public Boolean visitErrorType(ErrorType t, Type s) { 736 return s.hasTag(CLASS) 737 && t.tsym.name == ((ClassType) s).tsym.name; 738 } 739 }; 740 741 @Override @DefinedBy(Api.COMPILER_TREE) 742 public TypeMirror getTypeMirror(TreePath path) { 743 Tree t = path.getLeaf(); 744 Type ty = ((JCTree)t).type; 745 return ty == null ? null : ty.stripMetadataIfNeeded(); 746 } 747 748 @Override @DefinedBy(Api.COMPILER_TREE) 749 public JavacScope getScope(TreePath path) { 750 return JavacScope.create(getAttrContext(path)); 751 } 752 753 @Override @DefinedBy(Api.COMPILER_TREE) 754 public String getDocComment(TreePath path) { 755 CompilationUnitTree t = path.getCompilationUnit(); 756 Tree leaf = path.getLeaf(); 757 if (t instanceof JCTree.JCCompilationUnit && leaf instanceof JCTree) { 758 JCCompilationUnit cu = (JCCompilationUnit) t; 759 if (cu.docComments != null) { 760 return cu.docComments.getCommentText((JCTree) leaf); 761 } 762 } 763 return null; 764 } 765 766 @Override @DefinedBy(Api.COMPILER_TREE) 767 public DocCommentTree getDocCommentTree(TreePath path) { 768 CompilationUnitTree t = path.getCompilationUnit(); 769 Tree leaf = path.getLeaf(); 770 if (t instanceof JCTree.JCCompilationUnit && leaf instanceof JCTree) { 771 JCCompilationUnit cu = (JCCompilationUnit) t; 772 if (cu.docComments != null) { 773 return cu.docComments.getCommentTree((JCTree) leaf); 774 } 775 } 776 return null; 777 } 778 779 @Override @DefinedBy(Api.COMPILER_TREE) 780 public DocCommentTree getDocCommentTree(Element e) { 781 TreePath path = getPath(e); 782 if (path == null) { 783 return null; 784 } 785 return getDocCommentTree(path); 786 } 787 788 @Override @DefinedBy(Api.COMPILER_TREE) 789 public DocCommentTree getDocCommentTree(Element e, String relativeFileName) throws IOException { 790 PackageElement pkg = elements.getPackageOf(e); 791 FileObject fileForInput = fileManager.getFileForInput(StandardLocation.SOURCE_PATH, 792 pkg.getQualifiedName().toString(), relativeFileName); 793 794 if (fileForInput == null) { 795 throw new FileNotFoundException(relativeFileName); 796 } 797 return getDocCommentTree(fileForInput); 798 } 799 800 @Override @DefinedBy(Api.COMPILER_TREE) 801 public boolean isAccessible(Scope scope, TypeElement type) { 802 if (scope instanceof JavacScope && type instanceof ClassSymbol) { 803 Env<AttrContext> env = ((JavacScope) scope).env; 804 return resolve.isAccessible(env, (ClassSymbol)type, true); 805 } else 806 return false; 807 } 808 809 @Override @DefinedBy(Api.COMPILER_TREE) 810 public boolean isAccessible(Scope scope, Element member, DeclaredType type) { 811 if (scope instanceof JavacScope 812 && member instanceof Symbol 813 && type instanceof com.sun.tools.javac.code.Type) { 814 Env<AttrContext> env = ((JavacScope) scope).env; 815 return resolve.isAccessible(env, (com.sun.tools.javac.code.Type)type, (Symbol)member, true); 816 } else 817 return false; 818 } 819 820 private Env<AttrContext> getAttrContext(TreePath path) { 821 if (!(path.getLeaf() instanceof JCTree)) // implicit null-check 822 throw new IllegalArgumentException(); 823 824 // if we're being invoked from a Tree API client via parse/enter/analyze, 825 // we need to make sure all the classes have been entered; 826 // if we're being invoked from JSR 199 or JSR 269, then the classes 827 // will already have been entered. 828 if (javacTaskImpl != null) { 829 javacTaskImpl.enter(null); 830 } 831 832 JCCompilationUnit unit = (JCCompilationUnit) path.getCompilationUnit(); 833 Copier copier = createCopier(treeMaker.forToplevel(unit)); 834 835 Env<AttrContext> env = null; 836 JCMethodDecl method = null; 837 JCVariableDecl field = null; 838 839 List<Tree> l = List.nil(); 840 TreePath p = path; 841 while (p != null) { 842 l = l.prepend(p.getLeaf()); 843 p = p.getParentPath(); 844 } 845 846 for ( ; l.nonEmpty(); l = l.tail) { 847 Tree tree = l.head; 848 switch (tree.getKind()) { 849 case COMPILATION_UNIT: 850// System.err.println("COMP: " + ((JCCompilationUnit)tree).sourcefile); 851 env = enter.getTopLevelEnv((JCCompilationUnit)tree); 852 break; 853 case ANNOTATION_TYPE: 854 case CLASS: 855 case ENUM: 856 case INTERFACE: 857// System.err.println("CLASS: " + ((JCClassDecl)tree).sym.getSimpleName()); 858 env = enter.getClassEnv(((JCClassDecl)tree).sym); 859 break; 860 case METHOD: 861// System.err.println("METHOD: " + ((JCMethodDecl)tree).sym.getSimpleName()); 862 method = (JCMethodDecl)tree; 863 env = memberEnter.getMethodEnv(method, env); 864 break; 865 case VARIABLE: 866// System.err.println("FIELD: " + ((JCVariableDecl)tree).sym.getSimpleName()); 867 field = (JCVariableDecl)tree; 868 break; 869 case BLOCK: { 870// System.err.println("BLOCK: "); 871 if (method != null) { 872 try { 873 Assert.check(method.body == tree); 874 method.body = copier.copy((JCBlock)tree, (JCTree) path.getLeaf()); 875 env = attribStatToTree(method.body, env, copier.leafCopy); 876 } finally { 877 method.body = (JCBlock) tree; 878 } 879 } else { 880 JCBlock body = copier.copy((JCBlock)tree, (JCTree) path.getLeaf()); 881 env = attribStatToTree(body, env, copier.leafCopy); 882 } 883 return env; 884 } 885 default: 886// System.err.println("DEFAULT: " + tree.getKind()); 887 if (field != null && field.getInitializer() == tree) { 888 env = memberEnter.getInitEnv(field, env); 889 JCExpression expr = copier.copy((JCExpression)tree, (JCTree) path.getLeaf()); 890 env = attribExprToTree(expr, env, copier.leafCopy); 891 return env; 892 } 893 } 894 } 895 return (field != null) ? memberEnter.getInitEnv(field, env) : env; 896 } 897 898 private Env<AttrContext> attribStatToTree(JCTree stat, Env<AttrContext>env, JCTree tree) { 899 JavaFileObject prev = log.useSource(env.toplevel.sourcefile); 900 try { 901 return attr.attribStatToTree(stat, env, tree); 902 } finally { 903 log.useSource(prev); 904 } 905 } 906 907 private Env<AttrContext> attribExprToTree(JCExpression expr, Env<AttrContext>env, JCTree tree) { 908 JavaFileObject prev = log.useSource(env.toplevel.sourcefile); 909 try { 910 return attr.attribExprToTree(expr, env, tree); 911 } finally { 912 log.useSource(prev); 913 } 914 } 915 916 private JavaFileObject asJavaFileObject(FileObject fileObject) { 917 JavaFileObject jfo = null; 918 919 if (fileObject instanceof JavaFileObject) { 920 jfo = (JavaFileObject) fileObject; 921 checkHtmlKind(fileObject, Kind.HTML); 922 return jfo; 923 } 924 925 checkHtmlKind(fileObject); 926 jfo = new HtmlFileObject(fileObject); 927 return jfo; 928 } 929 930 private void checkHtmlKind(FileObject fileObject) { 931 checkHtmlKind(fileObject, BaseFileManager.getKind(fileObject.getName())); 932 } 933 934 private void checkHtmlKind(FileObject fileObject, JavaFileObject.Kind kind) { 935 if (kind != JavaFileObject.Kind.HTML) { 936 throw new IllegalArgumentException("HTML file expected:" + fileObject.getName()); 937 } 938 } 939 940 private static class HtmlFileObject extends ForwardingFileObject<FileObject> 941 implements JavaFileObject { 942 943 public HtmlFileObject(FileObject fileObject) { 944 super(fileObject); 945 } 946 947 @Override @DefinedBy(Api.COMPILER) 948 public Kind getKind() { 949 return BaseFileManager.getKind(fileObject.getName()); 950 } 951 952 @Override @DefinedBy(Api.COMPILER) 953 public boolean isNameCompatible(String simpleName, Kind kind) { 954 return false; 955 } 956 957 @Override @DefinedBy(Api.COMPILER) 958 public NestingKind getNestingKind() { 959 return null; 960 } 961 962 @Override @DefinedBy(Api.COMPILER) 963 public Modifier getAccessLevel() { 964 return null; 965 } 966 } 967 968 @Override @DefinedBy(Api.COMPILER_TREE) 969 public DocCommentTree getDocCommentTree(FileObject fileObject) { 970 JavaFileObject jfo = asJavaFileObject(fileObject); 971 DiagnosticSource diagSource = new DiagnosticSource(jfo, log); 972 973 final Comment comment = new Comment() { 974 int offset = 0; 975 @Override 976 public String getText() { 977 try { 978 CharSequence rawDoc = fileObject.getCharContent(true); 979 Pattern bodyPat = 980 Pattern.compile("(?is).*?<body\\b[^>]*>(.*)</body\\b.*"); 981 Matcher m = bodyPat.matcher(rawDoc); 982 if (m.matches()) { 983 offset = m.end(1); 984 return m.group(1); 985 } else { 986 // Assume doclint will do the right thing. 987 return ""; 988 } 989 } catch (IOException ignore) { 990 // do nothing 991 } 992 return ""; 993 } 994 995 @Override 996 public int getSourcePos(int index) { 997 return offset + index; 998 } 999 1000 @Override 1001 public CommentStyle getStyle() { 1002 throw new UnsupportedOperationException(); 1003 } 1004 1005 @Override 1006 public boolean isDeprecated() { 1007 throw new UnsupportedOperationException(); 1008 } 1009 }; 1010 1011 return new DocCommentParser(parser, diagSource, comment).parse(); 1012 } 1013 1014 @Override @DefinedBy(Api.COMPILER_TREE) 1015 public void setBreakIterator(BreakIterator breakiterator) { 1016 this.breakIterator = breakiterator; 1017 } 1018 1019 /** 1020 * Makes a copy of a tree, noting the value resulting from copying a particular leaf. 1021 **/ 1022 protected static class Copier extends TreeCopier<JCTree> { 1023 JCTree leafCopy = null; 1024 1025 protected Copier(TreeMaker M) { 1026 super(M); 1027 } 1028 1029 @Override 1030 public <T extends JCTree> T copy(T t, JCTree leaf) { 1031 T t2 = super.copy(t, leaf); 1032 if (t == leaf) 1033 leafCopy = t2; 1034 return t2; 1035 } 1036 } 1037 1038 protected Copier createCopier(TreeMaker maker) { 1039 return new Copier(maker); 1040 } 1041 1042 /** 1043 * Returns the original type from the ErrorType object. 1044 * @param errorType The errorType for which we want to get the original type. 1045 * @return TypeMirror corresponding to the original type, replaced by the ErrorType. 1046 * noType (type.tag == NONE) is returned if there is no original type. 1047 */ 1048 @Override @DefinedBy(Api.COMPILER_TREE) 1049 public TypeMirror getOriginalType(javax.lang.model.type.ErrorType errorType) { 1050 if (errorType instanceof com.sun.tools.javac.code.Type.ErrorType) { 1051 return ((com.sun.tools.javac.code.Type.ErrorType)errorType).getOriginalType(); 1052 } 1053 1054 return com.sun.tools.javac.code.Type.noType; 1055 } 1056 1057 /** 1058 * Prints a message of the specified kind at the location of the 1059 * tree within the provided compilation unit 1060 * 1061 * @param kind the kind of message 1062 * @param msg the message, or an empty string if none 1063 * @param t the tree to use as a position hint 1064 * @param root the compilation unit that contains tree 1065 */ 1066 @Override @DefinedBy(Api.COMPILER_TREE) 1067 public void printMessage(Diagnostic.Kind kind, CharSequence msg, 1068 com.sun.source.tree.Tree t, 1069 com.sun.source.tree.CompilationUnitTree root) { 1070 printMessage(kind, msg, ((JCTree) t).pos(), root); 1071 } 1072 1073 @Override @DefinedBy(Api.COMPILER_TREE) 1074 public void printMessage(Diagnostic.Kind kind, CharSequence msg, 1075 com.sun.source.doctree.DocTree t, 1076 com.sun.source.doctree.DocCommentTree c, 1077 com.sun.source.tree.CompilationUnitTree root) { 1078 printMessage(kind, msg, ((DCTree) t).pos((DCDocComment) c), root); 1079 } 1080 1081 private void printMessage(Diagnostic.Kind kind, CharSequence msg, 1082 JCDiagnostic.DiagnosticPosition pos, 1083 com.sun.source.tree.CompilationUnitTree root) { 1084 JavaFileObject oldSource = null; 1085 JavaFileObject newSource = null; 1086 1087 newSource = root.getSourceFile(); 1088 if (newSource == null) { 1089 pos = null; 1090 } else { 1091 oldSource = log.useSource(newSource); 1092 } 1093 1094 try { 1095 switch (kind) { 1096 case ERROR: 1097 log.error(DiagnosticFlag.MULTIPLE, pos, "proc.messager", msg.toString()); 1098 break; 1099 1100 case WARNING: 1101 log.warning(pos, "proc.messager", msg.toString()); 1102 break; 1103 1104 case MANDATORY_WARNING: 1105 log.mandatoryWarning(pos, "proc.messager", msg.toString()); 1106 break; 1107 1108 default: 1109 log.note(pos, "proc.messager", msg.toString()); 1110 } 1111 } finally { 1112 if (oldSource != null) 1113 log.useSource(oldSource); 1114 } 1115 } 1116 1117 @Override @DefinedBy(Api.COMPILER_TREE) 1118 public TypeMirror getLub(CatchTree tree) { 1119 JCCatch ct = (JCCatch) tree; 1120 JCVariableDecl v = ct.param; 1121 if (v.type != null && v.type.getKind() == TypeKind.UNION) { 1122 UnionClassType ut = (UnionClassType) v.type; 1123 return ut.getLub(); 1124 } else { 1125 return v.type; 1126 } 1127 } 1128 1129 public TreePath makeTreePath(final FileObject fileObject, final int offset) { 1130 JavaFileObject jfo = asJavaFileObject(fileObject); 1131 JCCompilationUnit jcCompilationUnit = new JCCompilationUnit(List.nil()) { 1132 public int getPos() { 1133 return offset; 1134 } 1135 1136 public JavaFileObject getSourcefile() { 1137 return jfo; 1138 } 1139 1140 @Override @DefinedBy(Api.COMPILER_TREE) 1141 public Position.LineMap getLineMap() { 1142 try { 1143 CharSequence content = fileObject.getCharContent(true); 1144 String s = content.toString(); 1145 return Position.makeLineMap(s.toCharArray(), s.length(), true); 1146 } catch (IOException ignore) {} 1147 return null; 1148 } 1149 }; 1150 jcCompilationUnit.sourcefile = jfo; 1151 enter.main(List.of(jcCompilationUnit)); 1152 return new TreePath(jcCompilationUnit); 1153 } 1154} 1155