duke@1: /* jjg@1521: * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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 ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle 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: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.comp; duke@1: jjg@1521: import java.util.HashMap; jjg@1521: import java.util.HashSet; jjg@1521: import java.util.LinkedHashMap; jjg@1521: import java.util.Map; duke@1: import java.util.Set; jjg@1521: 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: 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.*; jjg@1127: import static com.sun.tools.javac.code.Flags.ANNOTATION; duke@1: import static com.sun.tools.javac.code.Kinds.*; jjg@1374: import static com.sun.tools.javac.code.TypeTag.CLASS; jjg@1374: import static com.sun.tools.javac.code.TypeTag.ERROR; jjg@1374: import static com.sun.tools.javac.code.TypeTag.TYPEVAR; jjg@1127: import static com.sun.tools.javac.tree.JCTree.Tag.*; jjh@1188: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; 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: * jjg@581: *

This is NOT part of any supported API. jjg@581: * If 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; jfranck@1313: private final Source source; duke@1: private final Target target; mcimadamore@852: private final DeferredLintHandler deferredLintHandler; 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); jfranck@1313: source = Source.instance(context); duke@1: target = Target.instance(context); mcimadamore@852: deferredLintHandler = DeferredLintHandler.instance(context); 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. jjg@1358: * @param env The env in which the imported classes will be 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 { jjh@1188: log.error(DiagnosticFlag.RESOLVE_ERROR, pos, "doesnt.exist", tsym); duke@1: } duke@1: } jjg@767: env.toplevel.starImportScope.importAll(tsym.members()); 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. jjg@1358: * @param env The env in which the imported classes will be 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) { jjh@1270: log.error(DiagnosticFlag.RECOVERABLE, 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. jjg@1521: * @param recvparam The method's receiver parameter, jjg@1521: * null if none given; TODO: or already set here? 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, jjg@1521: JCVariableDecl recvparam, 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: jjg@1521: // Attribute receiver type, if one is given. jjg@1521: Type recvtype; jjg@1521: if (recvparam!=null) { jjg@1521: memberEnter(recvparam, env); jjg@1521: recvtype = recvparam.vartype.type; jjg@1521: } else { jjg@1521: recvtype = null; jjg@1521: } jjg@1521: 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); jjg@1374: if (!exc.hasTag(TYPEVAR)) duke@1: exc = chk.checkClassType(l.head.pos(), exc); duke@1: thrownbuf.append(exc); duke@1: } jjg@1521: MethodType mtype = new MethodType(argbuf.toList(), duke@1: restype, duke@1: thrownbuf.toList(), duke@1: syms.methodClass); jjg@1521: mtype.recvtype = recvtype; jjg@1521: 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(), mcimadamore@1565: List.of(make.VarDef(make.Modifiers(Flags.PARAMETER | mcimadamore@1565: Flags.MANDATED), 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: 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) { mcimadamore@1220: JCFieldAccess imp = (JCFieldAccess)tree.qualid; duke@1: Name name = TreeInfo.name(imp); 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: mcimadamore@1220: TypeSymbol p = attr.attribImportQualifier(tree, localEnv).tsym; duke@1: if (name == names.asterisk) { duke@1: // Import on demand. mcimadamore@1220: chk.checkCanonical(imp.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); mcimadamore@1220: chk.checkCanonical(imp.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; mcimadamore@1393: mcimadamore@1393: //if this is a default method, add the DEFAULT flag to the enclosing interface mcimadamore@1393: if ((tree.mods.flags & DEFAULT) != 0) { mcimadamore@1393: m.enclClass().flags_field |= DEFAULT; mcimadamore@1393: } mcimadamore@1393: duke@1: Env localEnv = methodEnv(tree, env); duke@1: mcimadamore@852: DeferredLintHandler prevLintHandler = mcimadamore@852: chk.setDeferredLintHandler(deferredLintHandler.setPos(tree.pos())); mcimadamore@852: try { mcimadamore@852: // Compute the method type mcimadamore@852: m.type = signature(tree.typarams, tree.params, jjg@1521: tree.restype, tree.recvparam, jjg@1521: tree.thrown, mcimadamore@852: localEnv); mcimadamore@852: } finally { mcimadamore@852: chk.setDeferredLintHandler(prevLintHandler); mcimadamore@852: } 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; jjg@816: params.append(Assert.checkNonNull(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); jjg@1521: // Visit the signature of the method. Note that jjg@1521: // TypeAnnotate doesn't descend into the body. jjg@1521: typeAnnotate(tree, localEnv, m); jjg@1521: 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; mcimadamore@1347: if (tree.sym.type != null) { mcimadamore@1347: //when this is called in the enter stage, there's no type to be set mcimadamore@1347: localEnv.info.returnResult = attr.new ResultInfo(VAL, tree.sym.type.getReturnType()); mcimadamore@1347: } 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: } mcimadamore@852: DeferredLintHandler prevLintHandler = mcimadamore@852: chk.setDeferredLintHandler(deferredLintHandler.setPos(tree.pos())); mcimadamore@852: try { mcimadamore@1269: if (TreeInfo.isEnumInit(tree)) { mcimadamore@1269: attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype); mcimadamore@1269: } else { jjg@1755: // Make sure type annotations are processed. jjg@1755: // But we don't have a symbol to attach them to yet - use null. jjg@1755: typeAnnotate(tree.vartype, env, null); mcimadamore@1269: attr.attribType(tree.vartype, localEnv); jjg@1755: if (tree.nameexpr != null) { jjg@1755: attr.attribExpr(tree.nameexpr, localEnv); jjg@1755: MethodSymbol m = localEnv.enclMethod.sym; jjg@1755: if (m.isConstructor()) { jjg@1755: Type outertype = m.owner.owner.type; jjg@1755: if (outertype.hasTag(TypeTag.CLASS)) { jjg@1755: checkType(tree.vartype, outertype, "incorrect.constructor.receiver.type"); jjg@1755: checkType(tree.nameexpr, outertype, "incorrect.constructor.receiver.name"); jjg@1755: } else { jjg@1755: log.error(tree, "receiver.parameter.not.applicable.constructor.toplevel.class"); jjg@1755: } jjg@1755: } else { jjg@1755: checkType(tree.vartype, m.owner.type, "incorrect.receiver.type"); jjg@1755: checkType(tree.nameexpr, m.owner.type, "incorrect.receiver.name"); jjg@1755: } jjg@1755: } mcimadamore@1269: } mcimadamore@852: } finally { mcimadamore@852: chk.setDeferredLintHandler(prevLintHandler); mcimadamore@852: } mcimadamore@852: mcimadamore@795: if ((tree.mods.flags & VARARGS) != 0) { mcimadamore@795: //if we are entering a varargs parameter, we need to replace its type mcimadamore@795: //(a plain array type) with the more precise VarargsType --- we need mcimadamore@795: //to do it this way because varargs is represented in the tree as a modifier mcimadamore@795: //on the parameter declaration, and not as a distinct type of array node. jjg@1521: ArrayType atype = (ArrayType)tree.vartype.type.unannotatedType(); mcimadamore@795: tree.vartype.type = atype.makeVarargs(); mcimadamore@795: } 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@1348: if ((v.flags_field & FINAL) != 0 && mcimadamore@1348: !tree.init.hasTag(NEWCLASS) && mcimadamore@1348: !tree.init.hasTag(LAMBDA)) { mcimadamore@94: Env initEnv = getInitEnv(tree, env); mcimadamore@94: initEnv.info.enclVar = v; jjg@841: v.setLazyConstValue(initEnv(tree, initEnv), 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); jjg@1755: typeAnnotate(tree.vartype, env, v); jjg@1521: annotate.flush(); duke@1: v.pos = tree.pos; duke@1: } jjg@1755: // where jjg@1755: void checkType(JCTree tree, Type type, String diag) { jjg@1755: if (!tree.type.isErroneous() && !types.isSameType(tree.type, type)) { jjg@1755: log.error(tree, diag, type, tree.type); jjg@1755: } jjg@1755: } 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) { mcimadamore@1348: localEnv.info.scope = env.info.scope.dupUnshared(); duke@1: localEnv.info.scope.owner = tree.sym; duke@1: } duke@1: if ((tree.mods.flags & STATIC) != 0 || mcimadamore@1393: ((env.enclClass.sym.flags() & INTERFACE) != 0 && env.enclMethod == null)) 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: public void visitErroneous(JCErroneous tree) { jjg@711: if (tree.errs != null) jjg@711: memberEnter(tree.errs, env); duke@1: } duke@1: duke@1: public Env getMethodEnv(JCMethodDecl tree, Env env) { duke@1: Env mEnv = methodEnv(tree, env); jfranck@1313: mEnv.info.lint = mEnv.info.lint.augment(tree.sym.annotations, 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) { jjg@816: Assert.check(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) { jfranck@1313: if (annotations.isEmpty()) { jfranck@1313: return; jfranck@1313: } jfranck@1313: if (s.kind != PCK) { jfranck@1313: s.annotations.reset(); // mark Annotations as incomplete for now jfranck@1313: } jfranck@1313: annotate.normal(new Annotate.Annotator() { jfranck@1313: @Override duke@1: public String toString() { duke@1: return "annotate " + annotations + " onto " + s + " in " + s.owner; duke@1: } jfranck@1313: jfranck@1313: @Override duke@1: public void enterAnnotation() { jfranck@1313: Assert.check(s.kind == PCK || s.annotations.pendingCompletion()); duke@1: JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); duke@1: try { jfranck@1313: if (!s.annotations.isEmpty() && duke@1: annotations.nonEmpty()) duke@1: log.error(annotations.head.pos, duke@1: "already.annotated", mcimadamore@80: kindName(s), s); jjg@1521: actualEnterAnnotations(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) { jfranck@1313: for (List al = annotations; !al.isEmpty(); 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: /** Enter a set of annotations. */ jjg@1521: private void actualEnterAnnotations(List annotations, duke@1: Env env, duke@1: Symbol s) { jfranck@1313: Map> annotated = jfranck@1313: new LinkedHashMap>(); jfranck@1313: Map pos = jfranck@1313: new HashMap(); jfranck@1313: jfranck@1313: for (List al = annotations; !al.isEmpty(); al = al.tail) { duke@1: JCAnnotation a = al.head; duke@1: Attribute.Compound c = annotate.enterAnnotation(a, duke@1: syms.annotationType, duke@1: env); jfranck@1313: if (c == null) { jfranck@1313: continue; jfranck@1313: } jfranck@1313: jfranck@1313: if (annotated.containsKey(a.type.tsym)) { jfranck@1313: if (source.allowRepeatedAnnotations()) { jfranck@1313: ListBuffer l = annotated.get(a.type.tsym); jfranck@1313: l = l.append(c); jfranck@1313: annotated.put(a.type.tsym, l); jfranck@1313: pos.put(c, a.pos()); jfranck@1313: } else { jfranck@1313: log.error(a.pos(), "duplicate.annotation"); jfranck@1313: } jfranck@1313: } else { jfranck@1313: annotated.put(a.type.tsym, ListBuffer.of(c)); jfranck@1313: pos.put(c, a.pos()); jfranck@1313: } jfranck@1313: duke@1: // Note: @Deprecated has no effect on local variables and parameters duke@1: if (!c.type.isErroneous() duke@1: && s.owner.kind != MTH jfranck@1313: && types.isSameType(c.type, syms.deprecatedType)) { duke@1: s.flags_field |= Flags.DEPRECATED; jjg@1521: } jfranck@1313: } jfranck@1313: jjg@1521: s.annotations.setDeclarationAttributesWithCompletion( jjg@1521: annotate.new AnnotateRepeatedContext(env, annotated, pos, log, false)); 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) { jfranck@1313: annotate.normal(new Annotate.Annotator() { jfranck@1313: @Override duke@1: public String toString() { duke@1: return "annotate " + m.owner + "." + duke@1: m + " default " + defaultValue; duke@1: } jfranck@1313: jfranck@1313: @Override 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. jjg@816: Assert.check((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) { jjg@1127: memberEnter(env.toplevel, env.enclosing(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: jjg@1521: if (tree.extending != null) jjg@1521: typeAnnotate(tree.extending, baseEnv, sym); jjg@1521: for (JCExpression impl : tree.implementing) jjg@1521: typeAnnotate(impl, baseEnv, sym); jjg@1521: annotate.flush(); jjg@1521: duke@1: // Determine supertype. duke@1: Type supertype = duke@1: (tree.extending != null) duke@1: ? attr.attribBase(tree.extending, baseEnv, true, false, true) darcy@1646: : ((tree.mods.flags & Flags.ENUM) != 0) 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; jjg@904: ct.supertype_field = modelMissingTypes(supertype, tree.extending, false); duke@1: duke@1: // Determine interfaces. duke@1: ListBuffer interfaces = new ListBuffer(); jjg@904: ListBuffer all_interfaces = null; // lazy init duke@1: Set interfaceSet = new HashSet(); duke@1: List interfaceTrees = tree.implementing; duke@1: for (JCExpression iface : interfaceTrees) { duke@1: Type i = attr.attribBase(iface, baseEnv, false, true, true); jjg@1374: if (i.hasTag(CLASS)) { duke@1: interfaces.append(i); jjg@904: if (all_interfaces != null) all_interfaces.append(i); duke@1: chk.checkNotRepeated(iface.pos(), types.erasure(i), interfaceSet); jjg@904: } else { jjg@904: if (all_interfaces == null) jjg@904: all_interfaces = new ListBuffer().appendList(interfaces); jjg@904: all_interfaces.append(modelMissingTypes(i, iface, true)); duke@1: } duke@1: } jjg@904: if ((c.flags_field & ANNOTATION) != 0) { duke@1: ct.interfaces_field = List.of(syms.annotationType); jjg@904: ct.all_interfaces_field = ct.interfaces_field; jjg@904: } else { duke@1: ct.interfaces_field = interfaces.toList(); jjg@904: ct.all_interfaces_field = (all_interfaces == null) jjg@904: ? ct.interfaces_field : all_interfaces.toList(); jjg@904: } 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); jjg@1521: // class type parameters use baseEnv but everything uses env duke@1: mcimadamore@690: chk.checkNonCyclicDecl(tree); mcimadamore@8: duke@1: attr.attribTypeVariables(tree.typarams, baseEnv); jjg@1521: // Do this here, where we have the symbol. jjg@1521: for (JCTypeParameter tp : tree.typarams) jjg@1521: typeAnnotate(tp, baseEnv, sym); jjg@1521: annotate.flush(); 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; mcimadamore@1341: boolean addConstructor = true; vromero@1791: JCNewClass nc = null; jjg@113: if (c.name.isEmpty()) { vromero@1791: nc = (JCNewClass)env.next.tree; duke@1: if (nc.constructor != null) { mcimadamore@1341: addConstructor = nc.constructor.kind != ERR; 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: } mcimadamore@1341: if (addConstructor) { vromero@1791: MethodSymbol basedConstructor = nc != null ? vromero@1791: (MethodSymbol)nc.constructor : null; mcimadamore@1341: JCTree constrDef = DefaultConstructor(make.at(tree.pos), c, vromero@1791: basedConstructor, mcimadamore@1341: typarams, argtypes, thrown, mcimadamore@1341: ctorFlags, based); mcimadamore@1341: tree.defs = tree.defs.prepend(constrDef); mcimadamore@1341: } duke@1: } duke@1: mcimadamore@1393: // enter symbols for 'this' into current scope. mcimadamore@1393: VarSymbol thisSym = mcimadamore@1393: new VarSymbol(FINAL | HASINIT, names._this, c.type, c); mcimadamore@1393: thisSym.pos = Position.FIRSTPOS; mcimadamore@1393: env.info.scope.enter(thisSym); mcimadamore@1393: // if this is a class, enter symbol for 'super' into current scope. mcimadamore@1393: if ((c.flags_field & INTERFACE) == 0 && mcimadamore@1393: ct.supertype_field.hasTag(CLASS)) { mcimadamore@1393: VarSymbol superSym = mcimadamore@1393: new VarSymbol(FINAL | HASINIT, names._super, mcimadamore@1393: ct.supertype_field, c); mcimadamore@1393: superSym.pos = Position.FIRSTPOS; mcimadamore@1393: env.info.scope.enter(superSym); 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 && ohrstrom@1384: reader.packageExists(c.fullname)) { ohrstrom@1384: log.error(tree.pos, "clash.with.pkg.of.same.name", Kinds.kindName(sym), c); ohrstrom@1384: } ohrstrom@1384: if (c.owner.kind == PCK && (c.flags_field & PUBLIC) == 0 && ohrstrom@1384: !env.toplevel.sourcefile.isNameCompatible(c.name.toString(),JavaFileObject.Kind.SOURCE)) { ohrstrom@1384: c.flags_field |= AUXILIARY; ohrstrom@1384: } 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: } jjg@1521: } jjg@1755: TypeAnnotations.organizeTypeAnnotationsSignatures(syms, names, log, tree, annotate); jjg@1521: } duke@1: jjg@1755: /* jjg@1755: * If the symbol is non-null, attach the type annotation to it. jjg@1755: */ jjg@1521: private void actualEnterTypeAnnotations(final List annotations, jjg@1521: final Env env, jjg@1521: final Symbol s) { jjg@1521: Map> annotated = jjg@1521: new LinkedHashMap>(); jjg@1521: Map pos = jjg@1521: new HashMap(); jjg@1521: jjg@1521: for (List al = annotations; !al.isEmpty(); al = al.tail) { jjg@1521: JCAnnotation a = al.head; jjg@1521: Attribute.TypeCompound tc = annotate.enterTypeAnnotation(a, jjg@1521: syms.annotationType, jjg@1521: env); jjg@1521: if (tc == null) { jjg@1521: continue; jjg@1521: } jjg@1521: jjg@1521: if (annotated.containsKey(a.type.tsym)) { jjg@1521: if (source.allowRepeatedAnnotations()) { jjg@1521: ListBuffer l = annotated.get(a.type.tsym); jjg@1521: l = l.append(tc); jjg@1521: annotated.put(a.type.tsym, l); jjg@1521: pos.put(tc, a.pos()); jjg@1521: } else { jjg@1521: log.error(a.pos(), "duplicate.annotation"); jjg@1521: } jjg@1521: } else { jjg@1521: annotated.put(a.type.tsym, ListBuffer.of(tc)); jjg@1521: pos.put(tc, a.pos()); jjg@1521: } jjg@1521: } jjg@1521: jjg@1755: if (s != null) { jjg@1755: s.annotations.appendTypeAttributesWithCompletion( jjg@1755: annotate.new AnnotateRepeatedContext(env, annotated, pos, log, true)); jjg@1755: } jjg@1521: } jjg@1521: jjg@1521: public void typeAnnotate(final JCTree tree, final Env env, final Symbol sym) { jjg@1521: tree.accept(new TypeAnnotate(env, sym)); jjg@1521: } jjg@1521: jjg@1521: /** jjg@1521: * We need to use a TreeScanner, because it is not enough to visit the top-level jjg@1521: * annotations. We also need to visit type arguments, etc. jjg@1521: */ jjg@1521: private class TypeAnnotate extends TreeScanner { jjg@1521: private Env env; jjg@1521: private Symbol sym; jjg@1521: jjg@1521: public TypeAnnotate(final Env env, final Symbol sym) { jjg@1521: this.env = env; jjg@1521: this.sym = sym; jjg@1521: } jjg@1521: jjg@1521: void annotateTypeLater(final List annotations) { jjg@1521: if (annotations.isEmpty()) { jjg@1521: return; jjg@1521: } jjg@1521: jjg@1521: annotate.normal(new Annotate.Annotator() { jjg@1521: @Override jjg@1521: public String toString() { jjg@1521: return "type annotate " + annotations + " onto " + sym + " in " + sym.owner; jjg@1521: } jjg@1521: @Override jjg@1521: public void enterAnnotation() { jjg@1521: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); jjg@1521: try { jjg@1521: actualEnterTypeAnnotations(annotations, env, sym); jjg@1521: } finally { jjg@1521: log.useSource(prev); jjg@1521: } jjg@1521: } jjg@1521: }); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public void visitAnnotatedType(final JCAnnotatedType tree) { jjg@1521: annotateTypeLater(tree.annotations); jjg@1521: super.visitAnnotatedType(tree); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public void visitTypeParameter(final JCTypeParameter tree) { jjg@1521: annotateTypeLater(tree.annotations); jjg@1521: super.visitTypeParameter(tree); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public void visitNewArray(final JCNewArray tree) { jjg@1521: annotateTypeLater(tree.annotations); jjg@1521: for (List dimAnnos : tree.dimAnnotations) jjg@1521: annotateTypeLater(dimAnnos); jjg@1521: super.visitNewArray(tree); jjg@1521: } jjg@1521: jjg@1521: @Override jjg@1521: public void visitMethodDef(final JCMethodDecl tree) { jjg@1521: scan(tree.mods); jjg@1521: scan(tree.restype); jjg@1521: scan(tree.typarams); jjg@1521: scan(tree.recvparam); jjg@1521: scan(tree.params); jjg@1521: scan(tree.thrown); jjg@1521: scan(tree.defaultValue); jjg@1521: // Do not annotate the body, just the signature. jjg@1521: // scan(tree.body); duke@1: } jjg@1755: jjg@1755: @Override jjg@1755: public void visitVarDef(final JCVariableDecl tree) { jjg@1755: if (sym != null && sym.kind == Kinds.VAR) { jjg@1755: // Don't visit a parameter once when the sym is the method jjg@1755: // and once when the sym is the parameter. jjg@1755: scan(tree.mods); jjg@1755: scan(tree.vartype); jjg@1755: } jjg@1755: scan(tree.init); jjg@1755: } jjg@1755: jjg@1755: @Override jjg@1755: public void visitClassDef(JCClassDecl tree) { jjg@1755: // We can only hit a classdef if it is declared within jjg@1755: // a method. Ignore it - the class will be visited jjg@1755: // separately later. jjg@1755: } jjg@1755: jjg@1755: @Override jjg@1755: public void visitNewClass(JCNewClass tree) { jjg@1755: if (tree.def == null) { jjg@1755: // For an anonymous class instantiation the class jjg@1755: // will be visited separately. jjg@1755: super.visitNewClass(tree); jjg@1755: } jjg@1755: } duke@1: } duke@1: jjg@1521: duke@1: private Env baseEnv(JCClassDecl tree, Env env) { mcimadamore@858: Scope baseScope = new Scope(tree.sym); mcimadamore@639: //import already entered local classes into base scope mcimadamore@639: for (Scope.Entry e = env.outer.info.scope.elems ; e != null ; e = e.sibling) { mcimadamore@639: if (e.sym.isLocal()) { mcimadamore@639: baseScope.enter(e.sym); mcimadamore@639: } mcimadamore@639: } mcimadamore@639: //import current type-parameters into base scope duke@1: if (tree.typarams != null) duke@1: for (List typarams = tree.typarams; duke@1: typarams.nonEmpty(); duke@1: typarams = typarams.tail) mcimadamore@639: baseScope.enter(typarams.head.type.tsym); duke@1: Env outer = env.outer; // the base clause can't see members of this class mcimadamore@639: Env localEnv = outer.dup(tree, outer.info.dup(baseScope)); 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: jjg@904: Type modelMissingTypes(Type t, final JCExpression tree, final boolean interfaceExpected) { jjg@1374: if (!t.hasTag(ERROR)) jjg@904: return t; jjg@904: jjg@904: return new ErrorType(((ErrorType) t).getOriginalType(), t.tsym) { jjg@904: private Type modelType; jjg@904: jjg@904: @Override jjg@904: public Type getModelType() { jjg@904: if (modelType == null) jjg@904: modelType = new Synthesizer(getOriginalType(), interfaceExpected).visit(tree); jjg@904: return modelType; jjg@904: } jjg@904: }; jjg@904: } jjg@904: // where jjg@904: private class Synthesizer extends JCTree.Visitor { jjg@904: Type originalType; jjg@904: boolean interfaceExpected; jjg@904: List synthesizedSymbols = List.nil(); jjg@904: Type result; jjg@904: jjg@904: Synthesizer(Type originalType, boolean interfaceExpected) { jjg@904: this.originalType = originalType; jjg@904: this.interfaceExpected = interfaceExpected; jjg@904: } jjg@904: jjg@904: Type visit(JCTree tree) { jjg@904: tree.accept(this); jjg@904: return result; jjg@904: } jjg@904: jjg@904: List visit(List trees) { jjg@904: ListBuffer lb = new ListBuffer(); jjg@904: for (JCTree t: trees) jjg@904: lb.append(visit(t)); jjg@904: return lb.toList(); jjg@904: } jjg@904: jjg@904: @Override jjg@904: public void visitTree(JCTree tree) { jjg@904: result = syms.errType; jjg@904: } jjg@904: jjg@904: @Override jjg@904: public void visitIdent(JCIdent tree) { jjg@1374: if (!tree.type.hasTag(ERROR)) { jjg@904: result = tree.type; jjg@904: } else { jjg@904: result = synthesizeClass(tree.name, syms.unnamedPackage).type; jjg@904: } jjg@904: } jjg@904: jjg@904: @Override jjg@904: public void visitSelect(JCFieldAccess tree) { jjg@1374: if (!tree.type.hasTag(ERROR)) { jjg@904: result = tree.type; jjg@904: } else { jjg@904: Type selectedType; jjg@904: boolean prev = interfaceExpected; jjg@904: try { jjg@904: interfaceExpected = false; jjg@904: selectedType = visit(tree.selected); jjg@904: } finally { jjg@904: interfaceExpected = prev; jjg@904: } jjg@904: ClassSymbol c = synthesizeClass(tree.name, selectedType.tsym); jjg@904: result = c.type; jjg@904: } jjg@904: } jjg@904: jjg@904: @Override jjg@904: public void visitTypeApply(JCTypeApply tree) { jjg@1374: if (!tree.type.hasTag(ERROR)) { jjg@904: result = tree.type; jjg@904: } else { jjg@904: ClassType clazzType = (ClassType) visit(tree.clazz); jjg@904: if (synthesizedSymbols.contains(clazzType.tsym)) jjg@904: synthesizeTyparams((ClassSymbol) clazzType.tsym, tree.arguments.size()); jjg@904: final List actuals = visit(tree.arguments); jjg@904: result = new ErrorType(tree.type, clazzType.tsym) { jjg@904: @Override jjg@904: public List getTypeArguments() { jjg@904: return actuals; jjg@904: } jjg@904: }; jjg@904: } jjg@904: } jjg@904: jjg@904: ClassSymbol synthesizeClass(Name name, Symbol owner) { jjg@904: int flags = interfaceExpected ? INTERFACE : 0; jjg@904: ClassSymbol c = new ClassSymbol(flags, name, owner); jjg@904: c.members_field = new Scope.ErrorScope(c); jjg@904: c.type = new ErrorType(originalType, c) { jjg@904: @Override jjg@904: public List getTypeArguments() { jjg@904: return typarams_field; jjg@904: } jjg@904: }; jjg@904: synthesizedSymbols = synthesizedSymbols.prepend(c); jjg@904: return c; jjg@904: } jjg@904: jjg@904: void synthesizeTyparams(ClassSymbol sym, int n) { jjg@904: ClassType ct = (ClassType) sym.type; jjg@904: Assert.check(ct.typarams_field.isEmpty()); jjg@904: if (n == 1) { jjg@904: TypeVar v = new TypeVar(names.fromString("T"), sym, syms.botType); jjg@904: ct.typarams_field = ct.typarams_field.prepend(v); jjg@904: } else { jjg@904: for (int i = n; i > 0; i--) { jjg@904: TypeVar v = new TypeVar(names.fromString("T" + i), sym, syms.botType); jjg@904: ct.typarams_field = ct.typarams_field.prepend(v); jjg@904: } jjg@904: } jjg@904: } jjg@904: } jjg@904: jjg@904: 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, vromero@1791: MethodSymbol baseInit, duke@1: List typarams, duke@1: List argtypes, duke@1: List thrown, duke@1: long flags, duke@1: boolean based) { vromero@1791: JCTree result; duke@1: if ((c.flags() & ENUM) != 0 && darcy@1646: (types.supertype(c.type).tsym == syms.enumSym)) { 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; vromero@1791: if (c.name.isEmpty()) { vromero@1791: flags |= ANONCONSTR; vromero@1791: } vromero@1791: Type mType = new MethodType(argtypes, null, thrown, c); vromero@1791: Type initType = typarams.nonEmpty() ? vromero@1791: new ForAll(typarams, mType) : vromero@1791: mType; vromero@1791: MethodSymbol init = new MethodSymbol(flags, names.init, vromero@1791: initType, c); vromero@1791: init.params = createDefaultConstructorParams(make, baseInit, init, vromero@1791: argtypes, based); vromero@1791: List params = make.Params(argtypes, init); vromero@1791: List stats = List.nil(); vromero@1791: if (c.type != syms.objectType) { vromero@1791: stats = stats.prepend(SuperCall(make, typarams, params, based)); vromero@1791: } vromero@1791: result = make.MethodDef(init, make.Block(0, stats)); duke@1: return result; duke@1: } duke@1: vromero@1791: private List createDefaultConstructorParams( vromero@1791: TreeMaker make, vromero@1791: MethodSymbol baseInit, vromero@1791: MethodSymbol init, vromero@1791: List argtypes, vromero@1791: boolean based) { vromero@1791: List initParams = null; vromero@1791: List argTypesList = argtypes; vromero@1791: if (based) { vromero@1791: /* In this case argtypes will have an extra type, compared to baseInit, vromero@1791: * corresponding to the type of the enclosing instance i.e.: vromero@1791: * vromero@1791: * Inner i = outer.new Inner(1){} vromero@1791: * vromero@1791: * in the above example argtypes will be (Outer, int) and baseInit vromero@1791: * will have parameter's types (int). So in this case we have to add vromero@1791: * first the extra type in argtypes and then get the names of the vromero@1791: * parameters from baseInit. vromero@1791: */ vromero@1791: initParams = List.nil(); vromero@1791: VarSymbol param = new VarSymbol(0, make.paramName(0), argtypes.head, init); vromero@1791: initParams = initParams.append(param); vromero@1791: argTypesList = argTypesList.tail; vromero@1791: } vromero@1791: if (baseInit != null && baseInit.params != null && vromero@1791: baseInit.params.nonEmpty() && argTypesList.nonEmpty()) { vromero@1791: initParams = (initParams == null) ? List.nil() : initParams; vromero@1791: List baseInitParams = baseInit.params; vromero@1791: while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) { vromero@1791: VarSymbol param = new VarSymbol(baseInitParams.head.flags(), vromero@1791: baseInitParams.head.name, argTypesList.head, init); vromero@1791: initParams = initParams.append(param); vromero@1791: baseInitParams = baseInitParams.tail; vromero@1791: argTypesList = argTypesList.tail; vromero@1791: } vromero@1791: } vromero@1791: return initParams; vromero@1791: } vromero@1791: 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: }