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