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