Enter.java revision 2673:bf8500822576
1189251Ssam/* 2189251Ssam * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. 3189251Ssam * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4189251Ssam * 5252726Srpaulo * This code is free software; you can redistribute it and/or modify it 6252726Srpaulo * under the terms of the GNU General Public License version 2 only, as 7189251Ssam * published by the Free Software Foundation. Oracle designates this 8189251Ssam * particular file as subject to the "Classpath" exception as provided 9189251Ssam * by Oracle in the LICENSE file that accompanied this code. 10189251Ssam * 11189251Ssam * This code is distributed in the hope that it will be useful, but WITHOUT 12189251Ssam * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13214734Srpaulo * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14189251Ssam * version 2 for more details (a copy is included in the LICENSE file that 15189251Ssam * accompanied this code). 16189251Ssam * 17189251Ssam * You should have received a copy of the GNU General Public License version 18189251Ssam * 2 along with this work; if not, write to the Free Software Foundation, 19189251Ssam * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20189251Ssam * 21189251Ssam * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22189251Ssam * or visit www.oracle.com if you need additional information or have any 23189251Ssam * questions. 24189251Ssam */ 25189251Ssam 26189251Ssampackage com.sun.tools.javac.comp; 27189251Ssam 28189251Ssamimport java.util.*; 29189251Ssamimport javax.tools.JavaFileObject; 30189251Ssamimport javax.tools.JavaFileManager; 31189251Ssam 32189251Ssamimport com.sun.tools.javac.code.*; 33189251Ssamimport com.sun.tools.javac.code.Kinds.KindSelector; 34189251Ssamimport com.sun.tools.javac.code.Scope.*; 35189251Ssamimport com.sun.tools.javac.code.Symbol.*; 36189251Ssamimport com.sun.tools.javac.code.Type.*; 37189251Ssamimport com.sun.tools.javac.jvm.*; 38189251Ssamimport com.sun.tools.javac.main.Option.PkgInfo; 39189251Ssamimport com.sun.tools.javac.tree.*; 40189251Ssamimport com.sun.tools.javac.tree.JCTree.*; 41189251Ssamimport com.sun.tools.javac.util.*; 42189251Ssamimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 43189251Ssamimport com.sun.tools.javac.util.List; 44189251Ssam 45189251Ssam 46189251Ssamimport static com.sun.tools.javac.code.Flags.*; 47189251Ssamimport static com.sun.tools.javac.code.Kinds.Kind.*; 48189251Ssam 49189251Ssam/** This class enters symbols for all encountered definitions into 50189251Ssam * the symbol table. The pass consists of two phases, organized as 51189251Ssam * follows: 52189251Ssam * 53189251Ssam * <p>In the first phase, all class symbols are entered into their 54189251Ssam * enclosing scope, descending recursively down the tree for classes 55189251Ssam * which are members of other classes. The class symbols are given a 56189251Ssam * MemberEnter object as completer. 57189251Ssam * 58189251Ssam * <p>In the second phase classes are completed using 59189251Ssam * MemberEnter.complete(). Completion might occur on demand, but 60189251Ssam * any classes that are not completed that way will be eventually 61189251Ssam * completed by processing the `uncompleted' queue. Completion 62189251Ssam * entails (1) determination of a class's parameters, supertype and 63189251Ssam * interfaces, as well as (2) entering all symbols defined in the 64189251Ssam * class into its scope, with the exception of class symbols which 65189251Ssam * have been entered in phase 1. (2) depends on (1) having been 66189251Ssam * completed for a class and all its superclasses and enclosing 67189251Ssam * classes. That's why, after doing (1), we put classes in a 68189251Ssam * `halfcompleted' queue. Only when we have performed (1) for a class 69189251Ssam * and all it's superclasses and enclosing classes, we proceed to 70189251Ssam * (2). 71189251Ssam * 72189251Ssam * <p>Whereas the first phase is organized as a sweep through all 73189251Ssam * compiled syntax trees, the second phase is demand. Members of a 74189251Ssam * class are entered when the contents of a class are first 75189251Ssam * accessed. This is accomplished by installing completer objects in 76189251Ssam * class symbols for compiled classes which invoke the member-enter 77189251Ssam * phase for the corresponding class tree. 78189251Ssam * 79189251Ssam * <p>Classes migrate from one phase to the next via queues: 80189251Ssam * 81189251Ssam * <pre>{@literal 82189251Ssam * class enter -> (Enter.uncompleted) --> member enter (1) 83189251Ssam * -> (MemberEnter.halfcompleted) --> member enter (2) 84189251Ssam * -> (Todo) --> attribute 85189251Ssam * (only for toplevel classes) 86189251Ssam * }</pre> 87189251Ssam * 88189251Ssam * <p><b>This is NOT part of any supported API. 89189251Ssam * If you write code that depends on this, you do so at your own risk. 90189251Ssam * This code and its internal interfaces are subject to change or 91189251Ssam * deletion without notice.</b> 92189251Ssam */ 93189251Ssampublic class Enter extends JCTree.Visitor { 94189251Ssam protected static final Context.Key<Enter> enterKey = new Context.Key<>(); 95189251Ssam 96189251Ssam Log log; 97189251Ssam Symtab syms; 98189251Ssam Check chk; 99189251Ssam TreeMaker make; 100189251Ssam Annotate annotate; 101189251Ssam MemberEnter memberEnter; 102189251Ssam Types types; 103189251Ssam Lint lint; 104189251Ssam Names names; 105189251Ssam JavaFileManager fileManager; 106189251Ssam PkgInfo pkginfoOpt; 107189251Ssam TypeEnvs typeEnvs; 108189251Ssam 109189251Ssam private final Todo todo; 110189251Ssam 111189251Ssam public static Enter instance(Context context) { 112189251Ssam Enter instance = context.get(enterKey); 113189251Ssam if (instance == null) 114189251Ssam instance = new Enter(context); 115189251Ssam return instance; 116189251Ssam } 117189251Ssam 118189251Ssam protected Enter(Context context) { 119189251Ssam context.put(enterKey, this); 120189251Ssam 121189251Ssam log = Log.instance(context); 122189251Ssam make = TreeMaker.instance(context); 123189251Ssam syms = Symtab.instance(context); 124189251Ssam chk = Check.instance(context); 125189251Ssam memberEnter = MemberEnter.instance(context); 126189251Ssam types = Types.instance(context); 127189251Ssam annotate = Annotate.instance(context); 128189251Ssam lint = Lint.instance(context); 129189251Ssam names = Names.instance(context); 130189251Ssam 131189251Ssam predefClassDef = make.ClassDef( 132189251Ssam make.Modifiers(PUBLIC), 133189251Ssam syms.predefClass.name, 134189251Ssam List.<JCTypeParameter>nil(), 135189251Ssam null, 136189251Ssam List.<JCExpression>nil(), 137189251Ssam List.<JCTree>nil()); 138189251Ssam predefClassDef.sym = syms.predefClass; 139189251Ssam todo = Todo.instance(context); 140189251Ssam fileManager = context.get(JavaFileManager.class); 141189251Ssam 142189251Ssam Options options = Options.instance(context); 143189251Ssam pkginfoOpt = PkgInfo.get(options); 144189251Ssam typeEnvs = TypeEnvs.instance(context); 145189251Ssam } 146189251Ssam 147189251Ssam /** Accessor for typeEnvs 148189251Ssam */ 149189251Ssam public Env<AttrContext> getEnv(TypeSymbol sym) { 150189251Ssam return typeEnvs.get(sym); 151189251Ssam } 152189251Ssam 153189251Ssam public Iterable<Env<AttrContext>> getEnvs() { 154189251Ssam return typeEnvs.values(); 155189251Ssam } 156189251Ssam 157189251Ssam public Env<AttrContext> getClassEnv(TypeSymbol sym) { 158189251Ssam Env<AttrContext> localEnv = getEnv(sym); 159189251Ssam Env<AttrContext> lintEnv = localEnv; 160189251Ssam while (lintEnv.info.lint == null) 161189251Ssam lintEnv = lintEnv.next; 162189251Ssam localEnv.info.lint = lintEnv.info.lint.augment(sym); 163189251Ssam return localEnv; 164189251Ssam } 165189251Ssam 166189251Ssam /** The queue of all classes that might still need to be completed; 167189251Ssam * saved and initialized by main(). 168189251Ssam */ 169189251Ssam ListBuffer<ClassSymbol> uncompleted; 170189251Ssam 171189251Ssam /** A dummy class to serve as enclClass for toplevel environments. 172189251Ssam */ 173189251Ssam private JCClassDecl predefClassDef; 174189251Ssam 175189251Ssam/* ************************************************************************ 176189251Ssam * environment construction 177189251Ssam *************************************************************************/ 178189251Ssam 179189251Ssam 180189251Ssam /** Create a fresh environment for class bodies. 181189251Ssam * This will create a fresh scope for local symbols of a class, referred 182189251Ssam * to by the environments info.scope field. 183189251Ssam * This scope will contain 184189251Ssam * - symbols for this and super 185189251Ssam * - symbols for any type parameters 186189251Ssam * In addition, it serves as an anchor for scopes of methods and initializers 187189251Ssam * which are nested in this scope via Scope.dup(). 188189251Ssam * This scope should not be confused with the members scope of a class. 189189251Ssam * 190189251Ssam * @param tree The class definition. 191189251Ssam * @param env The environment current outside of the class definition. 192189251Ssam */ 193189251Ssam public Env<AttrContext> classEnv(JCClassDecl tree, Env<AttrContext> env) { 194189251Ssam Env<AttrContext> localEnv = 195189251Ssam env.dup(tree, env.info.dup(WriteableScope.create(tree.sym))); 196189251Ssam localEnv.enclClass = tree; 197189251Ssam localEnv.outer = env; 198189251Ssam localEnv.info.isSelfCall = false; 199189251Ssam localEnv.info.lint = null; // leave this to be filled in by Attr, 200189251Ssam // when annotations have been processed 201189251Ssam return localEnv; 202189251Ssam } 203189251Ssam 204189251Ssam /** Create a fresh environment for toplevels. 205189251Ssam * @param tree The toplevel tree. 206189251Ssam */ 207189251Ssam Env<AttrContext> topLevelEnv(JCCompilationUnit tree) { 208189251Ssam Env<AttrContext> localEnv = new Env<>(tree, new AttrContext()); 209189251Ssam localEnv.toplevel = tree; 210189251Ssam localEnv.enclClass = predefClassDef; 211189251Ssam tree.toplevelScope = WriteableScope.create(tree.packge); 212189251Ssam tree.namedImportScope = new NamedImportScope(tree.packge, tree.toplevelScope); 213189251Ssam tree.starImportScope = new StarImportScope(tree.packge); 214189251Ssam localEnv.info.scope = tree.toplevelScope; 215189251Ssam localEnv.info.lint = lint; 216189251Ssam return localEnv; 217189251Ssam } 218189251Ssam 219189251Ssam public Env<AttrContext> getTopLevelEnv(JCCompilationUnit tree) { 220189251Ssam Env<AttrContext> localEnv = new Env<>(tree, new AttrContext()); 221189251Ssam localEnv.toplevel = tree; 222189251Ssam localEnv.enclClass = predefClassDef; 223189251Ssam localEnv.info.scope = tree.toplevelScope; 224189251Ssam localEnv.info.lint = lint; 225189251Ssam return localEnv; 226189251Ssam } 227189251Ssam 228189251Ssam /** The scope in which a member definition in environment env is to be entered 229189251Ssam * This is usually the environment's scope, except for class environments, 230189251Ssam * where the local scope is for type variables, and the this and super symbol 231189251Ssam * only, and members go into the class member scope. 232189251Ssam */ 233189251Ssam WriteableScope enterScope(Env<AttrContext> env) { 234189251Ssam return (env.tree.hasTag(JCTree.Tag.CLASSDEF)) 235189251Ssam ? ((JCClassDecl) env.tree).sym.members_field 236189251Ssam : env.info.scope; 237189251Ssam } 238189251Ssam 239189251Ssam/* ************************************************************************ 240189251Ssam * Visitor methods for phase 1: class enter 241189251Ssam *************************************************************************/ 242189251Ssam 243189251Ssam /** Visitor argument: the current environment. 244189251Ssam */ 245189251Ssam protected Env<AttrContext> env; 246189251Ssam 247189251Ssam /** Visitor result: the computed type. 248189251Ssam */ 249189251Ssam Type result; 250189251Ssam 251189251Ssam /** Visitor method: enter all classes in given tree, catching any 252189251Ssam * completion failure exceptions. Return the tree's type. 253189251Ssam * 254189251Ssam * @param tree The tree to be visited. 255189251Ssam * @param env The environment visitor argument. 256189251Ssam */ 257189251Ssam Type classEnter(JCTree tree, Env<AttrContext> env) { 258189251Ssam Env<AttrContext> prevEnv = this.env; 259189251Ssam try { 260189251Ssam this.env = env; 261189251Ssam tree.accept(this); 262189251Ssam return result; 263189251Ssam } catch (CompletionFailure ex) { 264189251Ssam return chk.completionError(tree.pos(), ex); 265189251Ssam } finally { 266189251Ssam this.env = prevEnv; 267189251Ssam } 268189251Ssam } 269189251Ssam 270189251Ssam /** Visitor method: enter classes of a list of trees, returning a list of types. 271189251Ssam */ 272189251Ssam <T extends JCTree> List<Type> classEnter(List<T> trees, Env<AttrContext> env) { 273189251Ssam ListBuffer<Type> ts = new ListBuffer<>(); 274189251Ssam for (List<T> l = trees; l.nonEmpty(); l = l.tail) { 275189251Ssam Type t = classEnter(l.head, env); 276189251Ssam if (t != null) 277189251Ssam ts.append(t); 278189251Ssam } 279189251Ssam return ts.toList(); 280189251Ssam } 281189251Ssam 282189251Ssam @Override 283189251Ssam public void visitTopLevel(JCCompilationUnit tree) { 284189251Ssam JavaFileObject prev = log.useSource(tree.sourcefile); 285189251Ssam boolean addEnv = false; 286189251Ssam boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info", 287189251Ssam JavaFileObject.Kind.SOURCE); 288189251Ssam JCPackageDecl pd = tree.getPackage(); 289189251Ssam if (pd != null) { 290189251Ssam tree.packge = pd.packge = syms.enterPackage(TreeInfo.fullName(pd.pid)); 291189251Ssam if ( pd.annotations.nonEmpty() 292189251Ssam || pkginfoOpt == PkgInfo.ALWAYS 293189251Ssam || tree.docComments != null) { 294189251Ssam if (isPkgInfo) { 295189251Ssam addEnv = true; 296189251Ssam } else if (pd.annotations.nonEmpty()) { 297189251Ssam log.error(pd.annotations.head.pos(), 298189251Ssam "pkg.annotations.sb.in.package-info.java"); 299189251Ssam } 300189251Ssam } 301189251Ssam } else { 302189251Ssam tree.packge = syms.unnamedPackage; 303189251Ssam } 304189251Ssam tree.packge.complete(); // Find all classes in package. 305189251Ssam Env<AttrContext> topEnv = topLevelEnv(tree); 306189251Ssam Env<AttrContext> packageEnv = isPkgInfo ? topEnv.dup(pd) : null; 307189251Ssam 308189251Ssam // Save environment of package-info.java file. 309189251Ssam if (isPkgInfo) { 310189251Ssam Env<AttrContext> env0 = typeEnvs.get(tree.packge); 311189251Ssam if (env0 != null) { 312189251Ssam JCCompilationUnit tree0 = env0.toplevel; 313189251Ssam if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) { 314189251Ssam log.warning(pd != null ? pd.pid.pos() : null, 315189251Ssam "pkg-info.already.seen", 316189251Ssam tree.packge); 317189251Ssam } 318189251Ssam } 319189251Ssam typeEnvs.put(tree.packge, packageEnv); 320189251Ssam 321189251Ssam for (Symbol q = tree.packge; q != null && q.kind == PCK; q = q.owner) 322189251Ssam q.flags_field |= EXISTS; 323189251Ssam 324189251Ssam Name name = names.package_info; 325189251Ssam ClassSymbol c = syms.enterClass(name, tree.packge); 326189251Ssam c.flatname = names.fromString(tree.packge + "." + name); 327189251Ssam c.sourcefile = tree.sourcefile; 328189251Ssam c.completer = null; 329189251Ssam c.members_field = WriteableScope.create(c); 330189251Ssam tree.packge.package_info = c; 331189251Ssam } 332189251Ssam classEnter(tree.defs, topEnv); 333189251Ssam if (addEnv) { 334189251Ssam todo.append(packageEnv); 335189251Ssam } 336189251Ssam log.useSource(prev); 337189251Ssam result = null; 338189251Ssam } 339189251Ssam 340189251Ssam @Override 341189251Ssam public void visitClassDef(JCClassDecl tree) { 342189251Ssam Symbol owner = env.info.scope.owner; 343189251Ssam WriteableScope enclScope = enterScope(env); 344189251Ssam ClassSymbol c; 345189251Ssam if (owner.kind == PCK) { 346189251Ssam // We are seeing a toplevel class. 347189251Ssam PackageSymbol packge = (PackageSymbol)owner; 348189251Ssam for (Symbol q = packge; q != null && q.kind == PCK; q = q.owner) 349189251Ssam q.flags_field |= EXISTS; 350189251Ssam c = syms.enterClass(tree.name, packge); 351189251Ssam packge.members().enterIfAbsent(c); 352189251Ssam if ((tree.mods.flags & PUBLIC) != 0 && !classNameMatchesFileName(c, env)) { 353189251Ssam log.error(tree.pos(), 354189251Ssam "class.public.should.be.in.file", tree.name); 355189251Ssam } 356189251Ssam } else { 357189251Ssam if (!tree.name.isEmpty() && 358189251Ssam !chk.checkUniqueClassName(tree.pos(), tree.name, enclScope)) { 359189251Ssam result = null; 360189251Ssam return; 361189251Ssam } 362189251Ssam if (owner.kind == TYP) { 363189251Ssam // We are seeing a member class. 364189251Ssam c = syms.enterClass(tree.name, (TypeSymbol)owner); 365189251Ssam if ((owner.flags_field & INTERFACE) != 0) { 366189251Ssam tree.mods.flags |= PUBLIC | STATIC; 367189251Ssam } 368189251Ssam } else { 369189251Ssam // We are seeing a local class. 370189251Ssam c = syms.defineClass(tree.name, owner); 371189251Ssam c.flatname = chk.localClassName(c); 372189251Ssam if (!c.name.isEmpty()) 373189251Ssam chk.checkTransparentClass(tree.pos(), c, env.info.scope); 374189251Ssam } 375189251Ssam } 376189251Ssam tree.sym = c; 377189251Ssam 378189251Ssam // Enter class into `compiled' table and enclosing scope. 379189251Ssam if (chk.compiled.get(c.flatname) != null) { 380189251Ssam duplicateClass(tree.pos(), c); 381189251Ssam result = types.createErrorType(tree.name, (TypeSymbol)owner, Type.noType); 382189251Ssam tree.sym = (ClassSymbol)result.tsym; 383189251Ssam return; 384189251Ssam } 385189251Ssam chk.compiled.put(c.flatname, c); 386189251Ssam enclScope.enter(c); 387189251Ssam 388 // Set up an environment for class block and store in `typeEnvs' 389 // table, to be retrieved later in memberEnter and attribution. 390 Env<AttrContext> localEnv = classEnv(tree, env); 391 typeEnvs.put(c, localEnv); 392 393 // Fill out class fields. 394 c.completer = memberEnter; 395 c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree); 396 c.sourcefile = env.toplevel.sourcefile; 397 c.members_field = WriteableScope.create(c); 398 399 ClassType ct = (ClassType)c.type; 400 if (owner.kind != PCK && (c.flags_field & STATIC) == 0) { 401 // We are seeing a local or inner class. 402 // Set outer_field of this class to closest enclosing class 403 // which contains this class in a non-static context 404 // (its "enclosing instance class"), provided such a class exists. 405 Symbol owner1 = owner; 406 while (owner1.kind.matches(KindSelector.VAL_MTH) && 407 (owner1.flags_field & STATIC) == 0) { 408 owner1 = owner1.owner; 409 } 410 if (owner1.kind == TYP) { 411 ct.setEnclosingType(owner1.type); 412 } 413 } 414 415 // Enter type parameters. 416 ct.typarams_field = classEnter(tree.typarams, localEnv); 417 418 // Add non-local class to uncompleted, to make sure it will be 419 // completed later. 420 if (!c.isLocal() && uncompleted != null) uncompleted.append(c); 421// System.err.println("entering " + c.fullname + " in " + c.owner);//DEBUG 422 423 // Recursively enter all member classes. 424 classEnter(tree.defs, localEnv); 425 426 result = c.type; 427 } 428 //where 429 /** Does class have the same name as the file it appears in? 430 */ 431 private static boolean classNameMatchesFileName(ClassSymbol c, 432 Env<AttrContext> env) { 433 return env.toplevel.sourcefile.isNameCompatible(c.name.toString(), 434 JavaFileObject.Kind.SOURCE); 435 } 436 437 /** Complain about a duplicate class. */ 438 protected void duplicateClass(DiagnosticPosition pos, ClassSymbol c) { 439 log.error(pos, "duplicate.class", c.fullname); 440 } 441 442 /** Class enter visitor method for type parameters. 443 * Enter a symbol for type parameter in local scope, after checking that it 444 * is unique. 445 */ 446 @Override 447 public void visitTypeParameter(JCTypeParameter tree) { 448 TypeVar a = (tree.type != null) 449 ? (TypeVar)tree.type 450 : new TypeVar(tree.name, env.info.scope.owner, syms.botType); 451 tree.type = a; 452 if (chk.checkUnique(tree.pos(), a.tsym, env.info.scope)) { 453 env.info.scope.enter(a.tsym); 454 } 455 result = a; 456 } 457 458 /** Default class enter visitor method: do nothing. 459 */ 460 @Override 461 public void visitTree(JCTree tree) { 462 result = null; 463 } 464 465 /** Main method: enter all classes in a list of toplevel trees. 466 * @param trees The list of trees to be processed. 467 */ 468 public void main(List<JCCompilationUnit> trees) { 469 complete(trees, null); 470 } 471 472 /** Main method: enter one class from a list of toplevel trees and 473 * place the rest on uncompleted for later processing. 474 * @param trees The list of trees to be processed. 475 * @param c The class symbol to be processed. 476 */ 477 public void complete(List<JCCompilationUnit> trees, ClassSymbol c) { 478 annotate.enterStart(); 479 ListBuffer<ClassSymbol> prevUncompleted = uncompleted; 480 if (memberEnter.completionEnabled) uncompleted = new ListBuffer<>(); 481 482 try { 483 // enter all classes, and construct uncompleted list 484 classEnter(trees, null); 485 486 // complete all uncompleted classes in memberEnter 487 if (memberEnter.completionEnabled) { 488 while (uncompleted.nonEmpty()) { 489 ClassSymbol clazz = uncompleted.next(); 490 if (c == null || c == clazz || prevUncompleted == null) 491 clazz.complete(); 492 else 493 // defer 494 prevUncompleted.append(clazz); 495 } 496 497 // if there remain any unimported toplevels (these must have 498 // no classes at all), process their import statements as well. 499 for (JCCompilationUnit tree : trees) { 500 if (tree.starImportScope.isEmpty()) { 501 JavaFileObject prev = log.useSource(tree.sourcefile); 502 Env<AttrContext> topEnv = topLevelEnv(tree); 503 memberEnter.memberEnter(tree, topEnv); 504 log.useSource(prev); 505 } 506 } 507 } 508 } finally { 509 uncompleted = prevUncompleted; 510 annotate.enterDone(); 511 } 512 } 513 514 public void newRound() { 515 typeEnvs.clear(); 516 } 517} 518