src/share/classes/com/sun/tools/javac/api/JavacTrees.java

changeset 1409
33abf479f202
parent 1357
c75be5bc5283
child 1416
c0f0c41cafa0
     1.1 --- a/src/share/classes/com/sun/tools/javac/api/JavacTrees.java	Wed Nov 14 16:41:51 2012 -0800
     1.2 +++ b/src/share/classes/com/sun/tools/javac/api/JavacTrees.java	Wed Nov 14 17:23:10 2012 -0800
     1.3 @@ -26,6 +26,8 @@
     1.4  package com.sun.tools.javac.api;
     1.5  
     1.6  import java.io.IOException;
     1.7 +import java.util.HashSet;
     1.8 +import java.util.Set;
     1.9  
    1.10  import javax.annotation.processing.ProcessingEnvironment;
    1.11  import javax.lang.model.element.AnnotationMirror;
    1.12 @@ -40,19 +42,31 @@
    1.13  import javax.tools.JavaCompiler;
    1.14  import javax.tools.JavaFileObject;
    1.15  
    1.16 +import com.sun.source.doctree.DocCommentTree;
    1.17 +import com.sun.source.doctree.ReferenceTree;
    1.18  import com.sun.source.tree.CatchTree;
    1.19  import com.sun.source.tree.CompilationUnitTree;
    1.20  import com.sun.source.tree.Scope;
    1.21  import com.sun.source.tree.Tree;
    1.22 +import com.sun.source.util.DocTrees;
    1.23  import com.sun.source.util.JavacTask;
    1.24  import com.sun.source.util.SourcePositions;
    1.25  import com.sun.source.util.TreePath;
    1.26 -import com.sun.source.util.Trees;
    1.27  import com.sun.tools.javac.code.Flags;
    1.28 +import com.sun.tools.javac.code.Kinds;
    1.29  import com.sun.tools.javac.code.Symbol;
    1.30  import com.sun.tools.javac.code.Symbol.ClassSymbol;
    1.31 +import com.sun.tools.javac.code.Symbol.MethodSymbol;
    1.32 +import com.sun.tools.javac.code.Symbol.PackageSymbol;
    1.33  import com.sun.tools.javac.code.Symbol.TypeSymbol;
    1.34 +import com.sun.tools.javac.code.Symbol.VarSymbol;
    1.35 +import com.sun.tools.javac.code.Type;
    1.36 +import com.sun.tools.javac.code.Type.ArrayType;
    1.37 +import com.sun.tools.javac.code.Type.ClassType;
    1.38 +import com.sun.tools.javac.code.Type.ErrorType;
    1.39  import com.sun.tools.javac.code.Type.UnionClassType;
    1.40 +import com.sun.tools.javac.code.Types;
    1.41 +import com.sun.tools.javac.code.Types.TypeRelation;
    1.42  import com.sun.tools.javac.comp.Attr;
    1.43  import com.sun.tools.javac.comp.AttrContext;
    1.44  import com.sun.tools.javac.comp.Enter;
    1.45 @@ -61,6 +75,9 @@
    1.46  import com.sun.tools.javac.comp.Resolve;
    1.47  import com.sun.tools.javac.model.JavacElements;
    1.48  import com.sun.tools.javac.processing.JavacProcessingEnvironment;
    1.49 +import com.sun.tools.javac.tree.DCTree;
    1.50 +import com.sun.tools.javac.tree.DCTree.DCDocComment;
    1.51 +import com.sun.tools.javac.tree.DCTree.DCReference;
    1.52  import com.sun.tools.javac.tree.EndPosTable;
    1.53  import com.sun.tools.javac.tree.JCTree;
    1.54  import com.sun.tools.javac.tree.JCTree.*;
    1.55 @@ -71,8 +88,12 @@
    1.56  import com.sun.tools.javac.util.Context;
    1.57  import com.sun.tools.javac.util.JCDiagnostic;
    1.58  import com.sun.tools.javac.util.List;
    1.59 +import com.sun.tools.javac.util.ListBuffer;
    1.60  import com.sun.tools.javac.util.Log;
    1.61 +import com.sun.tools.javac.util.Name;
    1.62 +import com.sun.tools.javac.util.Names;
    1.63  import com.sun.tools.javac.util.Pair;
    1.64 +import static com.sun.tools.javac.code.TypeTag.*;
    1.65  
    1.66  /**
    1.67   * Provides an implementation of Trees.
    1.68 @@ -84,7 +105,7 @@
    1.69   *
    1.70   * @author Peter von der Ahé
    1.71   */
    1.72 -public class JavacTrees extends Trees {
    1.73 +public class JavacTrees extends DocTrees {
    1.74  
    1.75      // in a world of a single context per compilation, these would all be final
    1.76      private Resolve resolve;
    1.77 @@ -95,6 +116,8 @@
    1.78      private TreeMaker treeMaker;
    1.79      private JavacElements elements;
    1.80      private JavacTaskImpl javacTaskImpl;
    1.81 +    private Names names;
    1.82 +    private Types types;
    1.83  
    1.84      // called reflectively from Trees.instance(CompilationTask task)
    1.85      public static JavacTrees instance(JavaCompiler.CompilationTask task) {
    1.86 @@ -134,6 +157,8 @@
    1.87          resolve = Resolve.instance(context);
    1.88          treeMaker = TreeMaker.instance(context);
    1.89          memberEnter = MemberEnter.instance(context);
    1.90 +        names = Names.instance(context);
    1.91 +        types = Types.instance(context);
    1.92  
    1.93          JavacTask t = context.get(JavacTask.class);
    1.94          if (t instanceof JavacTaskImpl)
    1.95 @@ -229,6 +254,324 @@
    1.96          return sym;
    1.97      }
    1.98  
    1.99 +    @Override
   1.100 +    public Element getElement(TreePath path, ReferenceTree reference) {
   1.101 +        if (!(reference instanceof DCReference))
   1.102 +            return null;
   1.103 +        DCReference ref = (DCReference) reference;
   1.104 +
   1.105 +        Env<AttrContext> env = getAttrContext(path);
   1.106 +
   1.107 +        Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
   1.108 +                new Log.DeferredDiagnosticHandler(log);
   1.109 +        try {
   1.110 +            final ClassSymbol tsym;
   1.111 +            final Name memberName;
   1.112 +            if (ref.qualifierExpression == null) {
   1.113 +                tsym = env.enclClass.sym;
   1.114 +                memberName = ref.memberName;
   1.115 +            } else {
   1.116 +                // See if the qualifierExpression is a type or package name.
   1.117 +                // javac does not provide the exact method required, so
   1.118 +                // we first check if qualifierExpression identifies a type,
   1.119 +                // and if not, then we check to see if it identifies a package.
   1.120 +                Type t = attr.attribType(ref.qualifierExpression, env);
   1.121 +                if (t.isErroneous()) {
   1.122 +                    if (ref.memberName == null) {
   1.123 +                        // Attr/Resolve assume packages exist and create symbols as needed
   1.124 +                        // so use getPackageElement to restrict search to existing packages
   1.125 +                        PackageSymbol pck = elements.getPackageElement(ref.qualifierExpression.toString());
   1.126 +                        if (pck != null) {
   1.127 +                            return pck;
   1.128 +                        } else if (ref.qualifierExpression.hasTag(JCTree.Tag.IDENT)) {
   1.129 +                            // fixup:  allow "identifier" instead of "#identifier"
   1.130 +                            // for compatibility with javadoc
   1.131 +                            tsym = env.enclClass.sym;
   1.132 +                            memberName = ((JCIdent) ref.qualifierExpression).name;
   1.133 +                        } else
   1.134 +                            return null;
   1.135 +                    } else {
   1.136 +                        return null;
   1.137 +                    }
   1.138 +                } else {
   1.139 +                    tsym = (ClassSymbol) t.tsym;
   1.140 +                    memberName = ref.memberName;
   1.141 +                }
   1.142 +            }
   1.143 +
   1.144 +            if (memberName == null)
   1.145 +                return tsym;
   1.146 +
   1.147 +            final List<Type> paramTypes;
   1.148 +            if (ref.paramTypes == null)
   1.149 +                paramTypes = null;
   1.150 +            else {
   1.151 +                ListBuffer<Type> lb = new ListBuffer<Type>();
   1.152 +                for (List<JCTree> l = ref.paramTypes; l.nonEmpty(); l = l.tail) {
   1.153 +                    JCTree tree = l.head;
   1.154 +                    Type t = attr.attribType(tree, env);
   1.155 +                    lb.add(t);
   1.156 +                }
   1.157 +                paramTypes = lb.toList();
   1.158 +            }
   1.159 +
   1.160 +            Symbol msym = (memberName == tsym.name)
   1.161 +                    ? findConstructor(tsym, paramTypes)
   1.162 +                    : findMethod(tsym, memberName, paramTypes);
   1.163 +            if (paramTypes != null) {
   1.164 +                // explicit (possibly empty) arg list given, so cannot be a field
   1.165 +                return msym;
   1.166 +            }
   1.167 +
   1.168 +            VarSymbol vsym = (ref.paramTypes != null) ? null : findField(tsym, memberName);
   1.169 +            // prefer a field over a method with no parameters
   1.170 +            if (vsym != null &&
   1.171 +                    (msym == null ||
   1.172 +                        types.isSubtypeUnchecked(vsym.enclClass().asType(), msym.enclClass().asType()))) {
   1.173 +                return vsym;
   1.174 +            } else {
   1.175 +                return msym;
   1.176 +            }
   1.177 +        } finally {
   1.178 +            log.popDiagnosticHandler(deferredDiagnosticHandler);
   1.179 +        }
   1.180 +    }
   1.181 +
   1.182 +    /** @see com.sun.tools.javadoc.ClassDocImpl#findField */
   1.183 +    private VarSymbol findField(ClassSymbol tsym, Name fieldName) {
   1.184 +        return searchField(tsym, fieldName, new HashSet<ClassSymbol>());
   1.185 +    }
   1.186 +
   1.187 +    /** @see com.sun.tools.javadoc.ClassDocImpl#searchField */
   1.188 +    private VarSymbol searchField(ClassSymbol tsym, Name fieldName, Set<ClassSymbol> searched) {
   1.189 +        if (searched.contains(tsym)) {
   1.190 +            return null;
   1.191 +        }
   1.192 +        searched.add(tsym);
   1.193 +
   1.194 +        for (com.sun.tools.javac.code.Scope.Entry e = tsym.members().lookup(fieldName);
   1.195 +                e.scope != null; e = e.next()) {
   1.196 +            if (e.sym.kind == Kinds.VAR) {
   1.197 +                return (VarSymbol)e.sym;
   1.198 +            }
   1.199 +        }
   1.200 +
   1.201 +        //### If we found a VarSymbol above, but which did not pass
   1.202 +        //### the modifier filter, we should return failure here!
   1.203 +
   1.204 +        ClassSymbol encl = tsym.owner.enclClass();
   1.205 +        if (encl != null) {
   1.206 +            VarSymbol vsym = searchField(encl, fieldName, searched);
   1.207 +            if (vsym != null) {
   1.208 +                return vsym;
   1.209 +            }
   1.210 +        }
   1.211 +
   1.212 +        // search superclass
   1.213 +        Type superclass = tsym.getSuperclass();
   1.214 +        if (superclass.tsym != null) {
   1.215 +            VarSymbol vsym = searchField((ClassSymbol) superclass.tsym, fieldName, searched);
   1.216 +            if (vsym != null) {
   1.217 +                return vsym;
   1.218 +            }
   1.219 +        }
   1.220 +
   1.221 +        // search interfaces
   1.222 +        List<Type> intfs = tsym.getInterfaces();
   1.223 +        for (List<Type> l = intfs; l.nonEmpty(); l = l.tail) {
   1.224 +            Type intf = l.head;
   1.225 +            if (intf.isErroneous()) continue;
   1.226 +            VarSymbol vsym = searchField((ClassSymbol) intf.tsym, fieldName, searched);
   1.227 +            if (vsym != null) {
   1.228 +                return vsym;
   1.229 +            }
   1.230 +        }
   1.231 +
   1.232 +        return null;
   1.233 +    }
   1.234 +
   1.235 +    /** @see com.sun.tools.javadoc.ClassDocImpl#findConstructor */
   1.236 +    MethodSymbol findConstructor(ClassSymbol tsym, List<Type> paramTypes) {
   1.237 +        for (com.sun.tools.javac.code.Scope.Entry e = tsym.members().lookup(names.init);
   1.238 +                e.scope != null; e = e.next()) {
   1.239 +            if (e.sym.kind == Kinds.MTH) {
   1.240 +                if (hasParameterTypes((MethodSymbol) e.sym, paramTypes)) {
   1.241 +                    return (MethodSymbol) e.sym;
   1.242 +                }
   1.243 +            }
   1.244 +        }
   1.245 +        return null;
   1.246 +    }
   1.247 +
   1.248 +    /** @see com.sun.tools.javadoc.ClassDocImpl#findMethod */
   1.249 +    private MethodSymbol findMethod(ClassSymbol tsym, Name methodName, List<Type> paramTypes) {
   1.250 +        return searchMethod(tsym, methodName, paramTypes, new HashSet<ClassSymbol>());
   1.251 +    }
   1.252 +
   1.253 +    /** @see com.sun.tools.javadoc.ClassDocImpl#searchMethod */
   1.254 +    private MethodSymbol searchMethod(ClassSymbol tsym, Name methodName,
   1.255 +                                       List<Type> paramTypes, Set<ClassSymbol> searched) {
   1.256 +        //### Note that this search is not necessarily what the compiler would do!
   1.257 +
   1.258 +        // do not match constructors
   1.259 +        if (methodName == names.init)
   1.260 +            return null;
   1.261 +
   1.262 +        if (searched.contains(tsym))
   1.263 +            return null;
   1.264 +        searched.add(tsym);
   1.265 +
   1.266 +        // search current class
   1.267 +        com.sun.tools.javac.code.Scope.Entry e = tsym.members().lookup(methodName);
   1.268 +
   1.269 +        //### Using modifier filter here isn't really correct,
   1.270 +        //### but emulates the old behavior.  Instead, we should
   1.271 +        //### apply the normal rules of visibility and inheritance.
   1.272 +
   1.273 +        if (paramTypes == null) {
   1.274 +            // If no parameters specified, we are allowed to return
   1.275 +            // any method with a matching name.  In practice, the old
   1.276 +            // code returned the first method, which is now the last!
   1.277 +            // In order to provide textually identical results, we
   1.278 +            // attempt to emulate the old behavior.
   1.279 +            MethodSymbol lastFound = null;
   1.280 +            for (; e.scope != null; e = e.next()) {
   1.281 +                if (e.sym.kind == Kinds.MTH) {
   1.282 +                    if (e.sym.name == methodName) {
   1.283 +                        lastFound = (MethodSymbol)e.sym;
   1.284 +                    }
   1.285 +                }
   1.286 +            }
   1.287 +            if (lastFound != null) {
   1.288 +                return lastFound;
   1.289 +            }
   1.290 +        } else {
   1.291 +            for (; e.scope != null; e = e.next()) {
   1.292 +                if (e.sym != null &&
   1.293 +                    e.sym.kind == Kinds.MTH) {
   1.294 +                    if (hasParameterTypes((MethodSymbol) e.sym, paramTypes)) {
   1.295 +                        return (MethodSymbol) e.sym;
   1.296 +                    }
   1.297 +                }
   1.298 +            }
   1.299 +        }
   1.300 +
   1.301 +        //### If we found a MethodSymbol above, but which did not pass
   1.302 +        //### the modifier filter, we should return failure here!
   1.303 +
   1.304 +        // search superclass
   1.305 +        Type superclass = tsym.getSuperclass();
   1.306 +        if (superclass.tsym != null) {
   1.307 +            MethodSymbol msym = searchMethod((ClassSymbol) superclass.tsym, methodName, paramTypes, searched);
   1.308 +            if (msym != null) {
   1.309 +                return msym;
   1.310 +            }
   1.311 +        }
   1.312 +
   1.313 +        // search interfaces
   1.314 +        List<Type> intfs = tsym.getInterfaces();
   1.315 +        for (List<Type> l = intfs; l.nonEmpty(); l = l.tail) {
   1.316 +            Type intf = l.head;
   1.317 +            if (intf.isErroneous()) continue;
   1.318 +            MethodSymbol msym = searchMethod((ClassSymbol) intf.tsym, methodName, paramTypes, searched);
   1.319 +            if (msym != null) {
   1.320 +                return msym;
   1.321 +            }
   1.322 +        }
   1.323 +
   1.324 +        // search enclosing class
   1.325 +        ClassSymbol encl = tsym.owner.enclClass();
   1.326 +        if (encl != null) {
   1.327 +            MethodSymbol msym = searchMethod(encl, methodName, paramTypes, searched);
   1.328 +            if (msym != null) {
   1.329 +                return msym;
   1.330 +            }
   1.331 +        }
   1.332 +
   1.333 +        return null;
   1.334 +    }
   1.335 +
   1.336 +    /** @see com.sun.tools.javadoc.ClassDocImpl */
   1.337 +    private boolean hasParameterTypes(MethodSymbol method, List<Type> paramTypes) {
   1.338 +        if (paramTypes == null)
   1.339 +            return true;
   1.340 +
   1.341 +        if (method.params().size() != paramTypes.size())
   1.342 +            return false;
   1.343 +
   1.344 +        List<Type> methodParamTypes = types.erasureRecursive(method.asType()).getParameterTypes();
   1.345 +
   1.346 +        return (Type.isErroneous(paramTypes))
   1.347 +            ? fuzzyMatch(paramTypes, methodParamTypes)
   1.348 +            : types.isSameTypes(paramTypes, methodParamTypes);
   1.349 +    }
   1.350 +
   1.351 +    boolean fuzzyMatch(List<Type> paramTypes, List<Type> methodParamTypes) {
   1.352 +        List<Type> l1 = paramTypes;
   1.353 +        List<Type> l2 = methodParamTypes;
   1.354 +        while (l1.nonEmpty()) {
   1.355 +            if (!fuzzyMatch(l1.head, l2.head))
   1.356 +                return false;
   1.357 +            l1 = l1.tail;
   1.358 +            l2 = l2.tail;
   1.359 +        }
   1.360 +        return true;
   1.361 +    }
   1.362 +
   1.363 +    boolean fuzzyMatch(Type paramType, Type methodParamType) {
   1.364 +        Boolean b = fuzzyMatcher.visit(paramType, methodParamType);
   1.365 +        return (b == Boolean.TRUE);
   1.366 +    }
   1.367 +
   1.368 +    TypeRelation fuzzyMatcher = new TypeRelation() {
   1.369 +        @Override
   1.370 +        public Boolean visitType(Type t, Type s) {
   1.371 +            if (t == s)
   1.372 +                return true;
   1.373 +
   1.374 +            if (s.isPartial())
   1.375 +                return visit(s, t);
   1.376 +
   1.377 +            switch (t.getTag()) {
   1.378 +            case BYTE: case CHAR: case SHORT: case INT: case LONG: case FLOAT:
   1.379 +            case DOUBLE: case BOOLEAN: case VOID: case BOT: case NONE:
   1.380 +                return t.getTag() == s.getTag();
   1.381 +
   1.382 +            default:
   1.383 +                throw new AssertionError("fuzzyMatcher " + t.getTag());
   1.384 +            }
   1.385 +        }
   1.386 +
   1.387 +        @Override
   1.388 +        public Boolean visitArrayType(ArrayType t, Type s) {
   1.389 +            if (t == s)
   1.390 +                return true;
   1.391 +
   1.392 +            if (s.isPartial())
   1.393 +                return visit(s, t);
   1.394 +
   1.395 +            return s.getTag() == ARRAY
   1.396 +                && visit(t.elemtype, types.elemtype(s));
   1.397 +        }
   1.398 +
   1.399 +        @Override
   1.400 +        public Boolean visitClassType(ClassType t, Type s) {
   1.401 +            if (t == s)
   1.402 +                return true;
   1.403 +
   1.404 +            if (s.isPartial())
   1.405 +                return visit(s, t);
   1.406 +
   1.407 +            return t.tsym == s.tsym;
   1.408 +        }
   1.409 +
   1.410 +        @Override
   1.411 +        public Boolean visitErrorType(ErrorType t, Type s) {
   1.412 +            return s.getTag() == CLASS
   1.413 +                    && t.tsym.name == ((ClassType) s).tsym.name;
   1.414 +        }
   1.415 +    };
   1.416 +
   1.417      public TypeMirror getTypeMirror(TreePath path) {
   1.418          Tree t = path.getLeaf();
   1.419          return ((JCTree)t).type;
   1.420 @@ -250,6 +593,18 @@
   1.421          return null;
   1.422      }
   1.423  
   1.424 +    public DocCommentTree getDocCommentTree(TreePath path) {
   1.425 +        CompilationUnitTree t = path.getCompilationUnit();
   1.426 +        Tree leaf = path.getLeaf();
   1.427 +        if (t instanceof JCTree.JCCompilationUnit && leaf instanceof JCTree) {
   1.428 +            JCCompilationUnit cu = (JCCompilationUnit) t;
   1.429 +            if (cu.docComments != null) {
   1.430 +                return cu.docComments.getCommentTree((JCTree) leaf);
   1.431 +            }
   1.432 +        }
   1.433 +        return null;
   1.434 +    }
   1.435 +
   1.436      public boolean isAccessible(Scope scope, TypeElement type) {
   1.437          if (scope instanceof JavacScope && type instanceof ClassSymbol) {
   1.438              Env<AttrContext> env = ((JavacScope) scope).env;
   1.439 @@ -418,14 +773,27 @@
   1.440      public void printMessage(Diagnostic.Kind kind, CharSequence msg,
   1.441              com.sun.source.tree.Tree t,
   1.442              com.sun.source.tree.CompilationUnitTree root) {
   1.443 +        printMessage(kind, msg, ((JCTree) t).pos(), root);
   1.444 +    }
   1.445 +
   1.446 +    public void printMessage(Diagnostic.Kind kind, CharSequence msg,
   1.447 +            com.sun.source.doctree.DocTree t,
   1.448 +            com.sun.source.doctree.DocCommentTree c,
   1.449 +            com.sun.source.tree.CompilationUnitTree root) {
   1.450 +        printMessage(kind, msg, ((DCTree) t).pos((DCDocComment) c), root);
   1.451 +    }
   1.452 +
   1.453 +    private void printMessage(Diagnostic.Kind kind, CharSequence msg,
   1.454 +            JCDiagnostic.DiagnosticPosition pos,
   1.455 +            com.sun.source.tree.CompilationUnitTree root) {
   1.456          JavaFileObject oldSource = null;
   1.457          JavaFileObject newSource = null;
   1.458 -        JCDiagnostic.DiagnosticPosition pos = null;
   1.459  
   1.460          newSource = root.getSourceFile();
   1.461 -        if (newSource != null) {
   1.462 +        if (newSource == null) {
   1.463 +            pos = null;
   1.464 +        } else {
   1.465              oldSource = log.useSource(newSource);
   1.466 -            pos = ((JCTree) t).pos();
   1.467          }
   1.468  
   1.469          try {

mercurial