duke@1: /* xdono@54: * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as duke@1: * published by the Free Software Foundation. Sun designates this duke@1: * particular file as subject to the "Classpath" exception as provided duke@1: * by Sun in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * duke@1: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@1: * CA 95054 USA or visit www.sun.com if you need additional information or duke@1: * have any questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.comp; duke@1: duke@1: import java.util.*; duke@1: import java.util.Set; duke@1: import javax.tools.JavaFileObject; duke@1: duke@1: import com.sun.tools.javac.code.*; duke@1: import com.sun.tools.javac.jvm.*; duke@1: import com.sun.tools.javac.tree.*; duke@1: import com.sun.tools.javac.util.*; duke@1: import com.sun.tools.javac.util.List; duke@1: duke@1: import com.sun.tools.javac.code.Type.*; duke@1: import com.sun.tools.javac.code.Symbol.*; duke@1: import com.sun.tools.javac.tree.JCTree.*; duke@1: duke@1: import static com.sun.tools.javac.code.Flags.*; duke@1: import static com.sun.tools.javac.code.Kinds.*; duke@1: import static com.sun.tools.javac.code.TypeTags.*; duke@1: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; duke@1: duke@1: /** This is the second phase of Enter, in which classes are completed duke@1: * by entering their members into the class scope using duke@1: * MemberEnter.complete(). See Enter for an overview. duke@1: * duke@1: *

This is NOT part of any API supported by Sun Microsystems. If duke@1: * you write code that depends on this, you do so at your own risk. duke@1: * This code and its internal interfaces are subject to change or duke@1: * deletion without notice. duke@1: */ duke@1: public class MemberEnter extends JCTree.Visitor implements Completer { duke@1: protected static final Context.Key memberEnterKey = duke@1: new Context.Key(); duke@1: duke@1: /** A switch to determine whether we check for package/class conflicts duke@1: */ duke@1: final static boolean checkClash = true; duke@1: jjg@113: private final Names names; duke@1: private final Enter enter; duke@1: private final Log log; duke@1: private final Check chk; duke@1: private final Attr attr; duke@1: private final Symtab syms; duke@1: private final TreeMaker make; duke@1: private final ClassReader reader; duke@1: private final Todo todo; duke@1: private final Annotate annotate; duke@1: private final Types types; mcimadamore@89: private final JCDiagnostic.Factory diags; duke@1: private final Target target; duke@1: duke@1: private final boolean skipAnnotations; duke@1: duke@1: public static MemberEnter instance(Context context) { duke@1: MemberEnter instance = context.get(memberEnterKey); duke@1: if (instance == null) duke@1: instance = new MemberEnter(context); duke@1: return instance; duke@1: } duke@1: duke@1: protected MemberEnter(Context context) { duke@1: context.put(memberEnterKey, this); jjg@113: names = Names.instance(context); duke@1: enter = Enter.instance(context); duke@1: log = Log.instance(context); duke@1: chk = Check.instance(context); duke@1: attr = Attr.instance(context); duke@1: syms = Symtab.instance(context); duke@1: make = TreeMaker.instance(context); duke@1: reader = ClassReader.instance(context); duke@1: todo = Todo.instance(context); duke@1: annotate = Annotate.instance(context); duke@1: types = Types.instance(context); mcimadamore@89: diags = JCDiagnostic.Factory.instance(context); duke@1: target = Target.instance(context); duke@1: skipAnnotations = duke@1: Options.instance(context).get("skipAnnotations") != null; duke@1: } duke@1: duke@1: /** A queue for classes whose members still need to be entered into the duke@1: * symbol table. duke@1: */ duke@1: ListBuffer> halfcompleted = new ListBuffer>(); duke@1: duke@1: /** Set to true only when the first of a set of classes is duke@1: * processed from the halfcompleted queue. duke@1: */ duke@1: boolean isFirst = true; duke@1: duke@1: /** A flag to disable completion from time to time during member duke@1: * enter, as we only need to look up types. This avoids duke@1: * unnecessarily deep recursion. duke@1: */ duke@1: boolean completionEnabled = true; duke@1: duke@1: /* ---------- Processing import clauses ---------------- duke@1: */ duke@1: duke@1: /** Import all classes of a class or package on demand. duke@1: * @param pos Position to be used for error reporting. duke@1: * @param tsym The class or package the members of which are imported. duke@1: * @param toScope The (import) scope in which imported classes duke@1: * are entered. duke@1: */ duke@1: private void importAll(int pos, duke@1: final TypeSymbol tsym, duke@1: Env env) { duke@1: // Check that packages imported from exist (JLS ???). duke@1: if (tsym.kind == PCK && tsym.members().elems == null && !tsym.exists()) { duke@1: // If we can't find java.lang, exit immediately. duke@1: if (((PackageSymbol)tsym).fullname.equals(names.java_lang)) { mcimadamore@89: JCDiagnostic msg = diags.fragment("fatal.err.no.java.lang"); duke@1: throw new FatalError(msg); duke@1: } else { duke@1: log.error(pos, "doesnt.exist", tsym); duke@1: } duke@1: } duke@1: final Scope fromScope = tsym.members(); duke@1: final Scope toScope = env.toplevel.starImportScope; duke@1: for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) { duke@1: if (e.sym.kind == TYP && !toScope.includes(e.sym)) duke@1: toScope.enter(e.sym, fromScope); duke@1: } duke@1: } duke@1: duke@1: /** Import all static members of a class or package on demand. duke@1: * @param pos Position to be used for error reporting. duke@1: * @param tsym The class or package the members of which are imported. duke@1: * @param toScope The (import) scope in which imported classes duke@1: * are entered. duke@1: */ duke@1: private void importStaticAll(int pos, duke@1: final TypeSymbol tsym, duke@1: Env env) { duke@1: final JavaFileObject sourcefile = env.toplevel.sourcefile; duke@1: final Scope toScope = env.toplevel.starImportScope; duke@1: final PackageSymbol packge = env.toplevel.packge; duke@1: final TypeSymbol origin = tsym; duke@1: duke@1: // enter imported types immediately duke@1: new Object() { duke@1: Set processed = new HashSet(); duke@1: void importFrom(TypeSymbol tsym) { duke@1: if (tsym == null || !processed.add(tsym)) duke@1: return; duke@1: duke@1: // also import inherited names duke@1: importFrom(types.supertype(tsym.type).tsym); duke@1: for (Type t : types.interfaces(tsym.type)) duke@1: importFrom(t.tsym); duke@1: duke@1: final Scope fromScope = tsym.members(); duke@1: for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) { duke@1: Symbol sym = e.sym; duke@1: if (sym.kind == TYP && duke@1: (sym.flags() & STATIC) != 0 && duke@1: staticImportAccessible(sym, packge) && duke@1: sym.isMemberOf(origin, types) && duke@1: !toScope.includes(sym)) duke@1: toScope.enter(sym, fromScope, origin.members()); duke@1: } duke@1: } duke@1: }.importFrom(tsym); duke@1: duke@1: // enter non-types before annotations that might use them duke@1: annotate.earlier(new Annotate.Annotator() { duke@1: Set processed = new HashSet(); duke@1: duke@1: public String toString() { duke@1: return "import static " + tsym + ".*" + " in " + sourcefile; duke@1: } duke@1: void importFrom(TypeSymbol tsym) { duke@1: if (tsym == null || !processed.add(tsym)) duke@1: return; duke@1: duke@1: // also import inherited names duke@1: importFrom(types.supertype(tsym.type).tsym); duke@1: for (Type t : types.interfaces(tsym.type)) duke@1: importFrom(t.tsym); duke@1: duke@1: final Scope fromScope = tsym.members(); duke@1: for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) { duke@1: Symbol sym = e.sym; duke@1: if (sym.isStatic() && sym.kind != TYP && duke@1: staticImportAccessible(sym, packge) && duke@1: !toScope.includes(sym) && duke@1: sym.isMemberOf(origin, types)) { duke@1: toScope.enter(sym, fromScope, origin.members()); duke@1: } duke@1: } duke@1: } duke@1: public void enterAnnotation() { duke@1: importFrom(tsym); duke@1: } duke@1: }); duke@1: } duke@1: duke@1: // is the sym accessible everywhere in packge? duke@1: boolean staticImportAccessible(Symbol sym, PackageSymbol packge) { duke@1: int flags = (int)(sym.flags() & AccessFlags); duke@1: switch (flags) { duke@1: default: duke@1: case PUBLIC: duke@1: return true; duke@1: case PRIVATE: duke@1: return false; duke@1: case 0: duke@1: case PROTECTED: duke@1: return sym.packge() == packge; duke@1: } duke@1: } duke@1: duke@1: /** Import statics types of a given name. Non-types are handled in Attr. duke@1: * @param pos Position to be used for error reporting. duke@1: * @param tsym The class from which the name is imported. duke@1: * @param name The (simple) name being imported. duke@1: * @param env The environment containing the named import duke@1: * scope to add to. duke@1: */ duke@1: private void importNamedStatic(final DiagnosticPosition pos, duke@1: final TypeSymbol tsym, duke@1: final Name name, duke@1: final Env env) { duke@1: if (tsym.kind != TYP) { duke@1: log.error(pos, "static.imp.only.classes.and.interfaces"); duke@1: return; duke@1: } duke@1: duke@1: final Scope toScope = env.toplevel.namedImportScope; duke@1: final PackageSymbol packge = env.toplevel.packge; duke@1: final TypeSymbol origin = tsym; duke@1: duke@1: // enter imported types immediately duke@1: new Object() { duke@1: Set processed = new HashSet(); duke@1: void importFrom(TypeSymbol tsym) { duke@1: if (tsym == null || !processed.add(tsym)) duke@1: return; duke@1: duke@1: // also import inherited names duke@1: importFrom(types.supertype(tsym.type).tsym); duke@1: for (Type t : types.interfaces(tsym.type)) duke@1: importFrom(t.tsym); duke@1: duke@1: for (Scope.Entry e = tsym.members().lookup(name); duke@1: e.scope != null; duke@1: e = e.next()) { duke@1: Symbol sym = e.sym; duke@1: if (sym.isStatic() && duke@1: sym.kind == TYP && duke@1: staticImportAccessible(sym, packge) && duke@1: sym.isMemberOf(origin, types) && duke@1: chk.checkUniqueStaticImport(pos, sym, toScope)) duke@1: toScope.enter(sym, sym.owner.members(), origin.members()); duke@1: } duke@1: } duke@1: }.importFrom(tsym); duke@1: duke@1: // enter non-types before annotations that might use them duke@1: annotate.earlier(new Annotate.Annotator() { duke@1: Set processed = new HashSet(); duke@1: boolean found = false; duke@1: duke@1: public String toString() { duke@1: return "import static " + tsym + "." + name; duke@1: } duke@1: void importFrom(TypeSymbol tsym) { duke@1: if (tsym == null || !processed.add(tsym)) duke@1: return; duke@1: duke@1: // also import inherited names duke@1: importFrom(types.supertype(tsym.type).tsym); duke@1: for (Type t : types.interfaces(tsym.type)) duke@1: importFrom(t.tsym); duke@1: duke@1: for (Scope.Entry e = tsym.members().lookup(name); duke@1: e.scope != null; duke@1: e = e.next()) { duke@1: Symbol sym = e.sym; duke@1: if (sym.isStatic() && duke@1: staticImportAccessible(sym, packge) && duke@1: sym.isMemberOf(origin, types)) { duke@1: found = true; duke@1: if (sym.kind == MTH || duke@1: sym.kind != TYP && chk.checkUniqueStaticImport(pos, sym, toScope)) duke@1: toScope.enter(sym, sym.owner.members(), origin.members()); duke@1: } duke@1: } duke@1: } duke@1: public void enterAnnotation() { duke@1: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); duke@1: try { duke@1: importFrom(tsym); duke@1: if (!found) { duke@1: log.error(pos, "cant.resolve.location", mcimadamore@80: KindName.STATIC, mcimadamore@80: name, List.nil(), List.nil(), mcimadamore@89: Kinds.typeKindName(tsym.type), duke@1: tsym.type); duke@1: } duke@1: } finally { duke@1: log.useSource(prev); duke@1: } duke@1: } duke@1: }); duke@1: } duke@1: /** Import given class. duke@1: * @param pos Position to be used for error reporting. duke@1: * @param tsym The class to be imported. duke@1: * @param env The environment containing the named import duke@1: * scope to add to. duke@1: */ duke@1: private void importNamed(DiagnosticPosition pos, Symbol tsym, Env env) { duke@1: if (tsym.kind == TYP && duke@1: chk.checkUniqueImport(pos, tsym, env.toplevel.namedImportScope)) duke@1: env.toplevel.namedImportScope.enter(tsym, tsym.owner.members()); duke@1: } duke@1: duke@1: /** Construct method type from method signature. duke@1: * @param typarams The method's type parameters. duke@1: * @param params The method's value parameters. duke@1: * @param res The method's result type, duke@1: * null if it is a constructor. duke@1: * @param thrown The method's thrown exceptions. duke@1: * @param env The method's (local) environment. duke@1: */ duke@1: Type signature(List typarams, duke@1: List params, duke@1: JCTree res, duke@1: List thrown, duke@1: Env env) { duke@1: duke@1: // Enter and attribute type parameters. duke@1: List tvars = enter.classEnter(typarams, env); duke@1: attr.attribTypeVariables(typarams, env); duke@1: duke@1: // Enter and attribute value parameters. duke@1: ListBuffer argbuf = new ListBuffer(); duke@1: for (List l = params; l.nonEmpty(); l = l.tail) { duke@1: memberEnter(l.head, env); duke@1: argbuf.append(l.head.vartype.type); duke@1: } duke@1: duke@1: // Attribute result type, if one is given. duke@1: Type restype = res == null ? syms.voidType : attr.attribType(res, env); duke@1: duke@1: // Attribute thrown exceptions. duke@1: ListBuffer thrownbuf = new ListBuffer(); duke@1: for (List l = thrown; l.nonEmpty(); l = l.tail) { duke@1: Type exc = attr.attribType(l.head, env); duke@1: if (exc.tag != TYPEVAR) duke@1: exc = chk.checkClassType(l.head.pos(), exc); duke@1: thrownbuf.append(exc); duke@1: } duke@1: Type mtype = new MethodType(argbuf.toList(), duke@1: restype, duke@1: thrownbuf.toList(), duke@1: syms.methodClass); duke@1: return tvars.isEmpty() ? mtype : new ForAll(tvars, mtype); duke@1: } duke@1: duke@1: /* ******************************************************************** duke@1: * Visitor methods for member enter duke@1: *********************************************************************/ duke@1: duke@1: /** Visitor argument: the current environment duke@1: */ duke@1: protected Env env; duke@1: duke@1: /** Enter field and method definitions and process import duke@1: * clauses, catching any completion failure exceptions. duke@1: */ duke@1: protected void memberEnter(JCTree tree, Env env) { duke@1: Env prevEnv = this.env; duke@1: try { duke@1: this.env = env; duke@1: tree.accept(this); duke@1: } catch (CompletionFailure ex) { duke@1: chk.completionError(tree.pos(), ex); duke@1: } finally { duke@1: this.env = prevEnv; duke@1: } duke@1: } duke@1: duke@1: /** Enter members from a list of trees. duke@1: */ duke@1: void memberEnter(List trees, Env env) { duke@1: for (List l = trees; l.nonEmpty(); l = l.tail) duke@1: memberEnter(l.head, env); duke@1: } duke@1: duke@1: /** Enter members for a class. duke@1: */ duke@1: void finishClass(JCClassDecl tree, Env env) { duke@1: if ((tree.mods.flags & Flags.ENUM) != 0 && duke@1: (types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) { duke@1: addEnumMembers(tree, env); duke@1: } duke@1: memberEnter(tree.defs, env); duke@1: } duke@1: duke@1: /** Add the implicit members for an enum type duke@1: * to the symbol table. duke@1: */ duke@1: private void addEnumMembers(JCClassDecl tree, Env env) { duke@1: JCExpression valuesType = make.Type(new ArrayType(tree.sym.type, syms.arrayClass)); duke@1: duke@1: // public static T[] values() { return ???; } duke@1: JCMethodDecl values = make. duke@1: MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), duke@1: names.values, duke@1: valuesType, duke@1: List.nil(), duke@1: List.nil(), duke@1: List.nil(), // thrown duke@1: null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), duke@1: null); duke@1: memberEnter(values, env); duke@1: duke@1: // public static T valueOf(String name) { return ???; } duke@1: JCMethodDecl valueOf = make. duke@1: MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), duke@1: names.valueOf, duke@1: make.Type(tree.sym.type), duke@1: List.nil(), duke@1: List.of(make.VarDef(make.Modifiers(Flags.PARAMETER), duke@1: names.fromString("name"), duke@1: make.Type(syms.stringType), null)), duke@1: List.nil(), // thrown duke@1: null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), duke@1: null); duke@1: memberEnter(valueOf, env); duke@1: duke@1: // the remaining members are for bootstrapping only duke@1: if (!target.compilerBootstrap(tree.sym)) return; duke@1: duke@1: // public final int ordinal() { return ???; } duke@1: JCMethodDecl ordinal = make.at(tree.pos). duke@1: MethodDef(make.Modifiers(Flags.PUBLIC|Flags.FINAL), duke@1: names.ordinal, duke@1: make.Type(syms.intType), duke@1: List.nil(), duke@1: List.nil(), duke@1: List.nil(), duke@1: null, duke@1: null); duke@1: memberEnter(ordinal, env); duke@1: duke@1: // public final String name() { return ???; } duke@1: JCMethodDecl name = make. duke@1: MethodDef(make.Modifiers(Flags.PUBLIC|Flags.FINAL), duke@1: names._name, duke@1: make.Type(syms.stringType), duke@1: List.nil(), duke@1: List.nil(), duke@1: List.nil(), duke@1: null, duke@1: null); duke@1: memberEnter(name, env); duke@1: duke@1: // public int compareTo(E other) { return ???; } duke@1: MethodSymbol compareTo = new duke@1: MethodSymbol(Flags.PUBLIC, duke@1: names.compareTo, duke@1: new MethodType(List.of(tree.sym.type), duke@1: syms.intType, duke@1: List.nil(), duke@1: syms.methodClass), duke@1: tree.sym); duke@1: memberEnter(make.MethodDef(compareTo, null), env); duke@1: } duke@1: duke@1: public void visitTopLevel(JCCompilationUnit tree) { duke@1: if (tree.starImportScope.elems != null) { duke@1: // we must have already processed this toplevel duke@1: return; duke@1: } duke@1: duke@1: // check that no class exists with same fully qualified name as duke@1: // toplevel package duke@1: if (checkClash && tree.pid != null) { duke@1: Symbol p = tree.packge; duke@1: while (p.owner != syms.rootPackage) { duke@1: p.owner.complete(); // enter all class members of p duke@1: if (syms.classes.get(p.getQualifiedName()) != null) { duke@1: log.error(tree.pos, duke@1: "pkg.clashes.with.class.of.same.name", duke@1: p); duke@1: } duke@1: p = p.owner; duke@1: } duke@1: } duke@1: duke@1: // process package annotations duke@1: annotateLater(tree.packageAnnotations, env, tree.packge); duke@1: duke@1: // Import-on-demand java.lang. duke@1: importAll(tree.pos, reader.enterPackage(names.java_lang), env); duke@1: duke@1: // Process all import clauses. duke@1: memberEnter(tree.defs, env); duke@1: } duke@1: duke@1: // process the non-static imports and the static imports of types. duke@1: public void visitImport(JCImport tree) { duke@1: JCTree imp = tree.qualid; duke@1: Name name = TreeInfo.name(imp); duke@1: TypeSymbol p; duke@1: duke@1: // Create a local environment pointing to this tree to disable duke@1: // effects of other imports in Resolve.findGlobalType duke@1: Env localEnv = env.dup(tree); duke@1: duke@1: // Attribute qualifying package or class. duke@1: JCFieldAccess s = (JCFieldAccess) imp; duke@1: p = attr. duke@1: attribTree(s.selected, duke@1: localEnv, duke@1: tree.staticImport ? TYP : (TYP | PCK), duke@1: Type.noType).tsym; duke@1: if (name == names.asterisk) { duke@1: // Import on demand. duke@1: chk.checkCanonical(s.selected); duke@1: if (tree.staticImport) duke@1: importStaticAll(tree.pos, p, env); duke@1: else duke@1: importAll(tree.pos, p, env); duke@1: } else { duke@1: // Named type import. duke@1: if (tree.staticImport) { duke@1: importNamedStatic(tree.pos(), p, name, localEnv); duke@1: chk.checkCanonical(s.selected); duke@1: } else { duke@1: TypeSymbol c = attribImportType(imp, localEnv).tsym; duke@1: chk.checkCanonical(imp); duke@1: importNamed(tree.pos(), c, env); duke@1: } duke@1: } duke@1: } duke@1: duke@1: public void visitMethodDef(JCMethodDecl tree) { duke@1: Scope enclScope = enter.enterScope(env); duke@1: MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner); duke@1: m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree); duke@1: tree.sym = m; duke@1: Env localEnv = methodEnv(tree, env); duke@1: duke@1: // Compute the method type duke@1: m.type = signature(tree.typarams, tree.params, duke@1: tree.restype, tree.thrown, duke@1: localEnv); duke@1: duke@1: // Set m.params duke@1: ListBuffer params = new ListBuffer(); duke@1: JCVariableDecl lastParam = null; duke@1: for (List l = tree.params; l.nonEmpty(); l = l.tail) { duke@1: JCVariableDecl param = lastParam = l.head; duke@1: assert param.sym != null; duke@1: params.append(param.sym); duke@1: } duke@1: m.params = params.toList(); duke@1: duke@1: // mark the method varargs, if necessary duke@1: if (lastParam != null && (lastParam.mods.flags & Flags.VARARGS) != 0) duke@1: m.flags_field |= Flags.VARARGS; duke@1: duke@1: localEnv.info.scope.leave(); duke@1: if (chk.checkUnique(tree.pos(), m, enclScope)) { duke@1: enclScope.enter(m); duke@1: } duke@1: annotateLater(tree.mods.annotations, localEnv, m); duke@1: if (tree.defaultValue != null) duke@1: annotateDefaultValueLater(tree.defaultValue, localEnv, m); duke@1: } duke@1: duke@1: /** Create a fresh environment for method bodies. duke@1: * @param tree The method definition. duke@1: * @param env The environment current outside of the method definition. duke@1: */ duke@1: Env methodEnv(JCMethodDecl tree, Env env) { duke@1: Env localEnv = duke@1: env.dup(tree, env.info.dup(env.info.scope.dupUnshared())); duke@1: localEnv.enclMethod = tree; duke@1: localEnv.info.scope.owner = tree.sym; duke@1: if ((tree.mods.flags & STATIC) != 0) localEnv.info.staticLevel++; duke@1: return localEnv; duke@1: } duke@1: duke@1: public void visitVarDef(JCVariableDecl tree) { duke@1: Env localEnv = env; duke@1: if ((tree.mods.flags & STATIC) != 0 || duke@1: (env.info.scope.owner.flags() & INTERFACE) != 0) { duke@1: localEnv = env.dup(tree, env.info.dup()); duke@1: localEnv.info.staticLevel++; duke@1: } duke@1: attr.attribType(tree.vartype, localEnv); duke@1: Scope enclScope = enter.enterScope(env); duke@1: VarSymbol v = duke@1: new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner); duke@1: v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree); duke@1: tree.sym = v; duke@1: if (tree.init != null) { duke@1: v.flags_field |= HASINIT; mcimadamore@94: if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS) { mcimadamore@94: Env initEnv = getInitEnv(tree, env); mcimadamore@94: initEnv.info.enclVar = v; mcimadamore@94: v.setLazyConstValue(initEnv(tree, initEnv), log, attr, tree.init); mcimadamore@94: } duke@1: } duke@1: if (chk.checkUnique(tree.pos(), v, enclScope)) { duke@1: chk.checkTransparentVar(tree.pos(), v, enclScope); duke@1: enclScope.enter(v); duke@1: } duke@1: annotateLater(tree.mods.annotations, localEnv, v); duke@1: v.pos = tree.pos; duke@1: } duke@1: duke@1: /** Create a fresh environment for a variable's initializer. duke@1: * If the variable is a field, the owner of the environment's scope duke@1: * is be the variable itself, otherwise the owner is the method duke@1: * enclosing the variable definition. duke@1: * duke@1: * @param tree The variable definition. duke@1: * @param env The environment current outside of the variable definition. duke@1: */ duke@1: Env initEnv(JCVariableDecl tree, Env env) { duke@1: Env localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup())); duke@1: if (tree.sym.owner.kind == TYP) { duke@1: localEnv.info.scope = new Scope.DelegatedScope(env.info.scope); duke@1: localEnv.info.scope.owner = tree.sym; duke@1: } duke@1: if ((tree.mods.flags & STATIC) != 0 || duke@1: (env.enclClass.sym.flags() & INTERFACE) != 0) duke@1: localEnv.info.staticLevel++; duke@1: return localEnv; duke@1: } duke@1: duke@1: /** Default member enter visitor method: do nothing duke@1: */ duke@1: public void visitTree(JCTree tree) { duke@1: } duke@1: duke@1: duke@1: public void visitErroneous(JCErroneous tree) { duke@1: memberEnter(tree.errs, env); duke@1: } duke@1: duke@1: public Env getMethodEnv(JCMethodDecl tree, Env env) { duke@1: Env mEnv = methodEnv(tree, env); duke@1: mEnv.info.lint = mEnv.info.lint.augment(tree.sym.attributes_field, tree.sym.flags()); duke@1: for (List l = tree.typarams; l.nonEmpty(); l = l.tail) duke@1: mEnv.info.scope.enterIfAbsent(l.head.type.tsym); duke@1: for (List l = tree.params; l.nonEmpty(); l = l.tail) duke@1: mEnv.info.scope.enterIfAbsent(l.head.sym); duke@1: return mEnv; duke@1: } duke@1: duke@1: public Env getInitEnv(JCVariableDecl tree, Env env) { duke@1: Env iEnv = initEnv(tree, env); duke@1: return iEnv; duke@1: } duke@1: duke@1: /* ******************************************************************** duke@1: * Type completion duke@1: *********************************************************************/ duke@1: duke@1: Type attribImportType(JCTree tree, Env env) { duke@1: assert completionEnabled; duke@1: try { duke@1: // To prevent deep recursion, suppress completion of some duke@1: // types. duke@1: completionEnabled = false; duke@1: return attr.attribType(tree, env); duke@1: } finally { duke@1: completionEnabled = true; duke@1: } duke@1: } duke@1: duke@1: /* ******************************************************************** duke@1: * Annotation processing duke@1: *********************************************************************/ duke@1: duke@1: /** Queue annotations for later processing. */ duke@1: void annotateLater(final List annotations, duke@1: final Env localEnv, duke@1: final Symbol s) { duke@1: if (annotations.isEmpty()) return; duke@1: if (s.kind != PCK) s.attributes_field = null; // mark it incomplete for now duke@1: annotate.later(new Annotate.Annotator() { duke@1: public String toString() { duke@1: return "annotate " + annotations + " onto " + s + " in " + s.owner; duke@1: } duke@1: public void enterAnnotation() { duke@1: assert s.kind == PCK || s.attributes_field == null; duke@1: JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); duke@1: try { duke@1: if (s.attributes_field != null && duke@1: s.attributes_field.nonEmpty() && duke@1: annotations.nonEmpty()) duke@1: log.error(annotations.head.pos, duke@1: "already.annotated", mcimadamore@80: kindName(s), s); duke@1: enterAnnotations(annotations, localEnv, s); duke@1: } finally { duke@1: log.useSource(prev); duke@1: } duke@1: } duke@1: }); duke@1: } duke@1: duke@1: /** duke@1: * Check if a list of annotations contains a reference to duke@1: * java.lang.Deprecated. duke@1: **/ duke@1: private boolean hasDeprecatedAnnotation(List annotations) { duke@1: for (List al = annotations; al.nonEmpty(); al = al.tail) { duke@1: JCAnnotation a = al.head; duke@1: if (a.annotationType.type == syms.deprecatedType && a.args.isEmpty()) duke@1: return true; duke@1: } duke@1: return false; duke@1: } duke@1: duke@1: duke@1: /** Enter a set of annotations. */ duke@1: private void enterAnnotations(List annotations, duke@1: Env env, duke@1: Symbol s) { duke@1: ListBuffer buf = duke@1: new ListBuffer(); duke@1: Set annotated = new HashSet(); duke@1: if (!skipAnnotations) duke@1: for (List al = annotations; al.nonEmpty(); al = al.tail) { duke@1: JCAnnotation a = al.head; duke@1: Attribute.Compound c = annotate.enterAnnotation(a, duke@1: syms.annotationType, duke@1: env); duke@1: if (c == null) continue; duke@1: buf.append(c); duke@1: // Note: @Deprecated has no effect on local variables and parameters duke@1: if (!c.type.isErroneous() duke@1: && s.owner.kind != MTH duke@1: && types.isSameType(c.type, syms.deprecatedType)) duke@1: s.flags_field |= Flags.DEPRECATED; duke@1: if (!annotated.add(a.type.tsym)) duke@1: log.error(a.pos, "duplicate.annotation"); duke@1: } duke@1: s.attributes_field = buf.toList(); duke@1: } duke@1: duke@1: /** Queue processing of an attribute default value. */ duke@1: void annotateDefaultValueLater(final JCExpression defaultValue, duke@1: final Env localEnv, duke@1: final MethodSymbol m) { duke@1: annotate.later(new Annotate.Annotator() { duke@1: public String toString() { duke@1: return "annotate " + m.owner + "." + duke@1: m + " default " + defaultValue; duke@1: } duke@1: public void enterAnnotation() { duke@1: JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); duke@1: try { duke@1: enterDefaultValue(defaultValue, localEnv, m); duke@1: } finally { duke@1: log.useSource(prev); duke@1: } duke@1: } duke@1: }); duke@1: } duke@1: duke@1: /** Enter a default value for an attribute method. */ duke@1: private void enterDefaultValue(final JCExpression defaultValue, duke@1: final Env localEnv, duke@1: final MethodSymbol m) { duke@1: m.defaultValue = annotate.enterAttributeValue(m.type.getReturnType(), duke@1: defaultValue, duke@1: localEnv); duke@1: } duke@1: duke@1: /* ******************************************************************** duke@1: * Source completer duke@1: *********************************************************************/ duke@1: duke@1: /** Complete entering a class. duke@1: * @param sym The symbol of the class to be completed. duke@1: */ duke@1: public void complete(Symbol sym) throws CompletionFailure { duke@1: // Suppress some (recursive) MemberEnter invocations duke@1: if (!completionEnabled) { duke@1: // Re-install same completer for next time around and return. duke@1: assert (sym.flags() & Flags.COMPOUND) == 0; duke@1: sym.completer = this; duke@1: return; duke@1: } duke@1: duke@1: ClassSymbol c = (ClassSymbol)sym; duke@1: ClassType ct = (ClassType)c.type; duke@1: Env env = enter.typeEnvs.get(c); duke@1: JCClassDecl tree = (JCClassDecl)env.tree; duke@1: boolean wasFirst = isFirst; duke@1: isFirst = false; duke@1: duke@1: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); duke@1: try { duke@1: // Save class environment for later member enter (2) processing. duke@1: halfcompleted.append(env); duke@1: mcimadamore@92: // Mark class as not yet attributed. mcimadamore@92: c.flags_field |= UNATTRIBUTED; mcimadamore@92: duke@1: // If this is a toplevel-class, make sure any preceding import duke@1: // clauses have been seen. duke@1: if (c.owner.kind == PCK) { duke@1: memberEnter(env.toplevel, env.enclosing(JCTree.TOPLEVEL)); duke@1: todo.append(env); duke@1: } duke@1: duke@1: if (c.owner.kind == TYP) duke@1: c.owner.complete(); duke@1: duke@1: // create an environment for evaluating the base clauses duke@1: Env baseEnv = baseEnv(tree, env); duke@1: duke@1: // Determine supertype. duke@1: Type supertype = duke@1: (tree.extending != null) duke@1: ? attr.attribBase(tree.extending, baseEnv, true, false, true) duke@1: : ((tree.mods.flags & Flags.ENUM) != 0 && !target.compilerBootstrap(c)) duke@1: ? attr.attribBase(enumBase(tree.pos, c), baseEnv, duke@1: true, false, false) duke@1: : (c.fullname == names.java_lang_Object) duke@1: ? Type.noType duke@1: : syms.objectType; duke@1: ct.supertype_field = supertype; duke@1: duke@1: // Determine interfaces. duke@1: ListBuffer interfaces = new ListBuffer(); duke@1: Set interfaceSet = new HashSet(); duke@1: List interfaceTrees = tree.implementing; duke@1: if ((tree.mods.flags & Flags.ENUM) != 0 && target.compilerBootstrap(c)) { duke@1: // add interface Comparable duke@1: interfaceTrees = duke@1: interfaceTrees.prepend(make.Type(new ClassType(syms.comparableType.getEnclosingType(), duke@1: List.of(c.type), duke@1: syms.comparableType.tsym))); duke@1: // add interface Serializable duke@1: interfaceTrees = duke@1: interfaceTrees.prepend(make.Type(syms.serializableType)); duke@1: } duke@1: for (JCExpression iface : interfaceTrees) { duke@1: Type i = attr.attribBase(iface, baseEnv, false, true, true); duke@1: if (i.tag == CLASS) { duke@1: interfaces.append(i); duke@1: chk.checkNotRepeated(iface.pos(), types.erasure(i), interfaceSet); duke@1: } duke@1: } duke@1: if ((c.flags_field & ANNOTATION) != 0) duke@1: ct.interfaces_field = List.of(syms.annotationType); duke@1: else duke@1: ct.interfaces_field = interfaces.toList(); duke@1: duke@1: if (c.fullname == names.java_lang_Object) { duke@1: if (tree.extending != null) { duke@1: chk.checkNonCyclic(tree.extending.pos(), duke@1: supertype); duke@1: ct.supertype_field = Type.noType; duke@1: } duke@1: else if (tree.implementing.nonEmpty()) { duke@1: chk.checkNonCyclic(tree.implementing.head.pos(), duke@1: ct.interfaces_field.head); duke@1: ct.interfaces_field = List.nil(); duke@1: } duke@1: } duke@1: duke@1: // Annotations. duke@1: // In general, we cannot fully process annotations yet, but we duke@1: // can attribute the annotation types and then check to see if the duke@1: // @Deprecated annotation is present. duke@1: attr.attribAnnotationTypes(tree.mods.annotations, baseEnv); duke@1: if (hasDeprecatedAnnotation(tree.mods.annotations)) duke@1: c.flags_field |= DEPRECATED; duke@1: annotateLater(tree.mods.annotations, baseEnv, c); duke@1: mcimadamore@8: chk.checkNonCyclic(tree.pos(), c.type); mcimadamore@8: duke@1: attr.attribTypeVariables(tree.typarams, baseEnv); duke@1: duke@1: // Add default constructor if needed. duke@1: if ((c.flags() & INTERFACE) == 0 && duke@1: !TreeInfo.hasConstructors(tree.defs)) { duke@1: List argtypes = List.nil(); duke@1: List typarams = List.nil(); duke@1: List thrown = List.nil(); duke@1: long ctorFlags = 0; duke@1: boolean based = false; jjg@113: if (c.name.isEmpty()) { duke@1: JCNewClass nc = (JCNewClass)env.next.tree; duke@1: if (nc.constructor != null) { duke@1: Type superConstrType = types.memberType(c.type, duke@1: nc.constructor); duke@1: argtypes = superConstrType.getParameterTypes(); duke@1: typarams = superConstrType.getTypeArguments(); duke@1: ctorFlags = nc.constructor.flags() & VARARGS; duke@1: if (nc.encl != null) { duke@1: argtypes = argtypes.prepend(nc.encl.type); duke@1: based = true; duke@1: } duke@1: thrown = superConstrType.getThrownTypes(); duke@1: } duke@1: } duke@1: JCTree constrDef = DefaultConstructor(make.at(tree.pos), c, duke@1: typarams, argtypes, thrown, duke@1: ctorFlags, based); duke@1: tree.defs = tree.defs.prepend(constrDef); duke@1: } duke@1: duke@1: // If this is a class, enter symbols for this and super into duke@1: // current scope. duke@1: if ((c.flags_field & INTERFACE) == 0) { duke@1: VarSymbol thisSym = duke@1: new VarSymbol(FINAL | HASINIT, names._this, c.type, c); duke@1: thisSym.pos = Position.FIRSTPOS; duke@1: env.info.scope.enter(thisSym); duke@1: if (ct.supertype_field.tag == CLASS) { duke@1: VarSymbol superSym = duke@1: new VarSymbol(FINAL | HASINIT, names._super, duke@1: ct.supertype_field, c); duke@1: superSym.pos = Position.FIRSTPOS; duke@1: env.info.scope.enter(superSym); duke@1: } duke@1: } duke@1: duke@1: // check that no package exists with same fully qualified name, duke@1: // but admit classes in the unnamed package which have the same duke@1: // name as a top-level package. duke@1: if (checkClash && duke@1: c.owner.kind == PCK && c.owner != syms.unnamedPackage && duke@1: reader.packageExists(c.fullname)) duke@1: { duke@1: log.error(tree.pos, "clash.with.pkg.of.same.name", c); duke@1: } duke@1: duke@1: } catch (CompletionFailure ex) { duke@1: chk.completionError(tree.pos(), ex); duke@1: } finally { duke@1: log.useSource(prev); duke@1: } duke@1: duke@1: // Enter all member fields and methods of a set of half completed duke@1: // classes in a second phase. duke@1: if (wasFirst) { duke@1: try { duke@1: while (halfcompleted.nonEmpty()) { duke@1: finish(halfcompleted.next()); duke@1: } duke@1: } finally { duke@1: isFirst = true; duke@1: } duke@1: duke@1: // commit pending annotations duke@1: annotate.flush(); duke@1: } duke@1: } duke@1: duke@1: private Env baseEnv(JCClassDecl tree, Env env) { duke@1: Scope typaramScope = new Scope(tree.sym); duke@1: if (tree.typarams != null) duke@1: for (List typarams = tree.typarams; duke@1: typarams.nonEmpty(); duke@1: typarams = typarams.tail) duke@1: typaramScope.enter(typarams.head.type.tsym); duke@1: Env outer = env.outer; // the base clause can't see members of this class duke@1: Env localEnv = outer.dup(tree, outer.info.dup(typaramScope)); duke@1: localEnv.baseClause = true; duke@1: localEnv.outer = outer; duke@1: localEnv.info.isSelfCall = false; duke@1: return localEnv; duke@1: } duke@1: duke@1: /** Enter member fields and methods of a class duke@1: * @param env the environment current for the class block. duke@1: */ duke@1: private void finish(Env env) { duke@1: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); duke@1: try { duke@1: JCClassDecl tree = (JCClassDecl)env.tree; duke@1: finishClass(tree, env); duke@1: } finally { duke@1: log.useSource(prev); duke@1: } duke@1: } duke@1: duke@1: /** Generate a base clause for an enum type. duke@1: * @param pos The position for trees and diagnostics, if any duke@1: * @param c The class symbol of the enum duke@1: */ duke@1: private JCExpression enumBase(int pos, ClassSymbol c) { duke@1: JCExpression result = make.at(pos). duke@1: TypeApply(make.QualIdent(syms.enumSym), duke@1: List.of(make.Type(c.type))); duke@1: return result; duke@1: } duke@1: duke@1: /* *************************************************************************** duke@1: * tree building duke@1: ****************************************************************************/ duke@1: duke@1: /** Generate default constructor for given class. For classes different duke@1: * from java.lang.Object, this is: duke@1: * duke@1: * c(argtype_0 x_0, ..., argtype_n x_n) throws thrown { duke@1: * super(x_0, ..., x_n) duke@1: * } duke@1: * duke@1: * or, if based == true: duke@1: * duke@1: * c(argtype_0 x_0, ..., argtype_n x_n) throws thrown { duke@1: * x_0.super(x_1, ..., x_n) duke@1: * } duke@1: * duke@1: * @param make The tree factory. duke@1: * @param c The class owning the default constructor. duke@1: * @param argtypes The parameter types of the constructor. duke@1: * @param thrown The thrown exceptions of the constructor. duke@1: * @param based Is first parameter a this$n? duke@1: */ duke@1: JCTree DefaultConstructor(TreeMaker make, duke@1: ClassSymbol c, duke@1: List typarams, duke@1: List argtypes, duke@1: List thrown, duke@1: long flags, duke@1: boolean based) { duke@1: List params = make.Params(argtypes, syms.noSymbol); duke@1: List stats = List.nil(); duke@1: if (c.type != syms.objectType) duke@1: stats = stats.prepend(SuperCall(make, typarams, params, based)); duke@1: if ((c.flags() & ENUM) != 0 && duke@1: (types.supertype(c.type).tsym == syms.enumSym || duke@1: target.compilerBootstrap(c))) { duke@1: // constructors of true enums are private duke@1: flags = (flags & ~AccessFlags) | PRIVATE | GENERATEDCONSTR; duke@1: } else duke@1: flags |= (c.flags() & AccessFlags) | GENERATEDCONSTR; jjg@113: if (c.name.isEmpty()) flags |= ANONCONSTR; duke@1: JCTree result = make.MethodDef( duke@1: make.Modifiers(flags), duke@1: names.init, duke@1: null, duke@1: make.TypeParams(typarams), duke@1: params, duke@1: make.Types(thrown), duke@1: make.Block(0, stats), duke@1: null); duke@1: return result; duke@1: } duke@1: duke@1: /** Generate call to superclass constructor. This is: duke@1: * duke@1: * super(id_0, ..., id_n) duke@1: * duke@1: * or, if based == true duke@1: * duke@1: * id_0.super(id_1,...,id_n) duke@1: * duke@1: * where id_0, ..., id_n are the names of the given parameters. duke@1: * duke@1: * @param make The tree factory duke@1: * @param params The parameters that need to be passed to super duke@1: * @param typarams The type parameters that need to be passed to super duke@1: * @param based Is first parameter a this$n? duke@1: */ duke@1: JCExpressionStatement SuperCall(TreeMaker make, duke@1: List typarams, duke@1: List params, duke@1: boolean based) { duke@1: JCExpression meth; duke@1: if (based) { duke@1: meth = make.Select(make.Ident(params.head), names._super); duke@1: params = params.tail; duke@1: } else { duke@1: meth = make.Ident(names._super); duke@1: } duke@1: List typeargs = typarams.nonEmpty() ? make.Types(typarams) : null; duke@1: return make.Exec(make.Apply(typeargs, meth, make.Idents(params))); duke@1: } duke@1: }