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 {