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