aoqi@0: /* aoqi@0: * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.tools.javac.comp; aoqi@0: aoqi@0: import java.util.HashMap; aoqi@0: import java.util.HashSet; aoqi@0: import java.util.LinkedHashMap; aoqi@0: import java.util.Map; aoqi@0: import java.util.Set; aoqi@0: aoqi@0: import javax.tools.JavaFileObject; aoqi@0: aoqi@0: import com.sun.tools.javac.code.*; aoqi@0: import com.sun.tools.javac.jvm.*; aoqi@0: import com.sun.tools.javac.tree.*; aoqi@0: import com.sun.tools.javac.util.*; aoqi@0: aoqi@0: import com.sun.tools.javac.code.Type.*; aoqi@0: import com.sun.tools.javac.code.Symbol.*; aoqi@0: import com.sun.tools.javac.tree.JCTree.*; aoqi@0: aoqi@0: import static com.sun.tools.javac.code.Flags.*; aoqi@0: import static com.sun.tools.javac.code.Flags.ANNOTATION; aoqi@0: import static com.sun.tools.javac.code.Kinds.*; aoqi@0: import static com.sun.tools.javac.code.TypeTag.CLASS; aoqi@0: import static com.sun.tools.javac.code.TypeTag.ERROR; aoqi@0: import static com.sun.tools.javac.code.TypeTag.TYPEVAR; aoqi@0: import static com.sun.tools.javac.tree.JCTree.Tag.*; aoqi@0: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; aoqi@0: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; aoqi@0: aoqi@0: /** This is the second phase of Enter, in which classes are completed aoqi@0: * by entering their members into the class scope using aoqi@0: * MemberEnter.complete(). See Enter for an overview. aoqi@0: * aoqi@0: *

This is NOT part of any supported API. aoqi@0: * If you write code that depends on this, you do so at your own risk. aoqi@0: * This code and its internal interfaces are subject to change or aoqi@0: * deletion without notice. aoqi@0: */ aoqi@0: public class MemberEnter extends JCTree.Visitor implements Completer { aoqi@0: protected static final Context.Key memberEnterKey = aoqi@0: new Context.Key(); aoqi@0: aoqi@0: /** A switch to determine whether we check for package/class conflicts aoqi@0: */ aoqi@0: final static boolean checkClash = true; aoqi@0: aoqi@0: private final Names names; aoqi@0: private final Enter enter; aoqi@0: private final Log log; aoqi@0: private final Check chk; aoqi@0: private final Attr attr; aoqi@0: private final Symtab syms; aoqi@0: private final TreeMaker make; aoqi@0: private final ClassReader reader; aoqi@0: private final Todo todo; aoqi@0: private final Annotate annotate; aoqi@0: private final TypeAnnotations typeAnnotations; aoqi@0: private final Types types; aoqi@0: private final JCDiagnostic.Factory diags; aoqi@0: private final Source source; aoqi@0: private final Target target; aoqi@0: private final DeferredLintHandler deferredLintHandler; aoqi@0: private final Lint lint; aoqi@0: private final TypeEnvs typeEnvs; aoqi@0: aoqi@0: public static MemberEnter instance(Context context) { aoqi@0: MemberEnter instance = context.get(memberEnterKey); aoqi@0: if (instance == null) aoqi@0: instance = new MemberEnter(context); aoqi@0: return instance; aoqi@0: } aoqi@0: aoqi@0: protected MemberEnter(Context context) { aoqi@0: context.put(memberEnterKey, this); aoqi@0: names = Names.instance(context); aoqi@0: enter = Enter.instance(context); aoqi@0: log = Log.instance(context); aoqi@0: chk = Check.instance(context); aoqi@0: attr = Attr.instance(context); aoqi@0: syms = Symtab.instance(context); aoqi@0: make = TreeMaker.instance(context); aoqi@0: reader = ClassReader.instance(context); aoqi@0: todo = Todo.instance(context); aoqi@0: annotate = Annotate.instance(context); aoqi@0: typeAnnotations = TypeAnnotations.instance(context); aoqi@0: types = Types.instance(context); aoqi@0: diags = JCDiagnostic.Factory.instance(context); aoqi@0: source = Source.instance(context); aoqi@0: target = Target.instance(context); aoqi@0: deferredLintHandler = DeferredLintHandler.instance(context); aoqi@0: lint = Lint.instance(context); aoqi@0: typeEnvs = TypeEnvs.instance(context); aoqi@0: allowTypeAnnos = source.allowTypeAnnotations(); aoqi@0: allowRepeatedAnnos = source.allowRepeatedAnnotations(); aoqi@0: } aoqi@0: aoqi@0: /** Switch: support type annotations. aoqi@0: */ aoqi@0: boolean allowTypeAnnos; aoqi@0: aoqi@0: boolean allowRepeatedAnnos; aoqi@0: aoqi@0: /** A queue for classes whose members still need to be entered into the aoqi@0: * symbol table. aoqi@0: */ aoqi@0: ListBuffer> halfcompleted = new ListBuffer>(); aoqi@0: aoqi@0: /** Set to true only when the first of a set of classes is aoqi@0: * processed from the half completed queue. aoqi@0: */ aoqi@0: boolean isFirst = true; aoqi@0: aoqi@0: /** A flag to disable completion from time to time during member aoqi@0: * enter, as we only need to look up types. This avoids aoqi@0: * unnecessarily deep recursion. aoqi@0: */ aoqi@0: boolean completionEnabled = true; aoqi@0: aoqi@0: /* ---------- Processing import clauses ---------------- aoqi@0: */ aoqi@0: aoqi@0: /** Import all classes of a class or package on demand. aoqi@0: * @param pos Position to be used for error reporting. aoqi@0: * @param tsym The class or package the members of which are imported. aoqi@0: * @param env The env in which the imported classes will be entered. aoqi@0: */ aoqi@0: private void importAll(int pos, aoqi@0: final TypeSymbol tsym, aoqi@0: Env env) { aoqi@0: // Check that packages imported from exist (JLS ???). aoqi@0: if (tsym.kind == PCK && tsym.members().elems == null && !tsym.exists()) { aoqi@0: // If we can't find java.lang, exit immediately. aoqi@0: if (((PackageSymbol)tsym).fullname.equals(names.java_lang)) { aoqi@0: JCDiagnostic msg = diags.fragment("fatal.err.no.java.lang"); aoqi@0: throw new FatalError(msg); aoqi@0: } else { aoqi@0: log.error(DiagnosticFlag.RESOLVE_ERROR, pos, "doesnt.exist", tsym); aoqi@0: } aoqi@0: } aoqi@0: env.toplevel.starImportScope.importAll(tsym.members()); aoqi@0: } aoqi@0: aoqi@0: /** Import all static members of a class or package on demand. aoqi@0: * @param pos Position to be used for error reporting. aoqi@0: * @param tsym The class or package the members of which are imported. aoqi@0: * @param env The env in which the imported classes will be entered. aoqi@0: */ aoqi@0: private void importStaticAll(int pos, aoqi@0: final TypeSymbol tsym, aoqi@0: Env env) { aoqi@0: final JavaFileObject sourcefile = env.toplevel.sourcefile; aoqi@0: final Scope toScope = env.toplevel.starImportScope; aoqi@0: final PackageSymbol packge = env.toplevel.packge; aoqi@0: final TypeSymbol origin = tsym; aoqi@0: aoqi@0: // enter imported types immediately aoqi@0: new Object() { aoqi@0: Set processed = new HashSet(); aoqi@0: void importFrom(TypeSymbol tsym) { aoqi@0: if (tsym == null || !processed.add(tsym)) aoqi@0: return; aoqi@0: aoqi@0: // also import inherited names aoqi@0: importFrom(types.supertype(tsym.type).tsym); aoqi@0: for (Type t : types.interfaces(tsym.type)) aoqi@0: importFrom(t.tsym); aoqi@0: aoqi@0: final Scope fromScope = tsym.members(); aoqi@0: for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) { aoqi@0: Symbol sym = e.sym; aoqi@0: if (sym.kind == TYP && aoqi@0: (sym.flags() & STATIC) != 0 && aoqi@0: staticImportAccessible(sym, packge) && aoqi@0: sym.isMemberOf(origin, types) && aoqi@0: !toScope.includes(sym)) aoqi@0: toScope.enter(sym, fromScope, origin.members(), true); aoqi@0: } aoqi@0: } aoqi@0: }.importFrom(tsym); aoqi@0: aoqi@0: // enter non-types before annotations that might use them aoqi@0: annotate.earlier(new Annotate.Worker() { aoqi@0: Set processed = new HashSet(); aoqi@0: aoqi@0: public String toString() { aoqi@0: return "import static " + tsym + ".*" + " in " + sourcefile; aoqi@0: } aoqi@0: void importFrom(TypeSymbol tsym) { aoqi@0: if (tsym == null || !processed.add(tsym)) aoqi@0: return; aoqi@0: aoqi@0: // also import inherited names aoqi@0: importFrom(types.supertype(tsym.type).tsym); aoqi@0: for (Type t : types.interfaces(tsym.type)) aoqi@0: importFrom(t.tsym); aoqi@0: aoqi@0: final Scope fromScope = tsym.members(); aoqi@0: for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) { aoqi@0: Symbol sym = e.sym; aoqi@0: if (sym.isStatic() && sym.kind != TYP && aoqi@0: staticImportAccessible(sym, packge) && aoqi@0: !toScope.includes(sym) && aoqi@0: sym.isMemberOf(origin, types)) { aoqi@0: toScope.enter(sym, fromScope, origin.members(), true); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: public void run() { aoqi@0: importFrom(tsym); aoqi@0: } aoqi@0: }); aoqi@0: } aoqi@0: aoqi@0: // is the sym accessible everywhere in packge? aoqi@0: boolean staticImportAccessible(Symbol sym, PackageSymbol packge) { aoqi@0: int flags = (int)(sym.flags() & AccessFlags); aoqi@0: switch (flags) { aoqi@0: default: aoqi@0: case PUBLIC: aoqi@0: return true; aoqi@0: case PRIVATE: aoqi@0: return false; aoqi@0: case 0: aoqi@0: case PROTECTED: aoqi@0: return sym.packge() == packge; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** Import statics types of a given name. Non-types are handled in Attr. aoqi@0: * @param pos Position to be used for error reporting. aoqi@0: * @param tsym The class from which the name is imported. aoqi@0: * @param name The (simple) name being imported. aoqi@0: * @param env The environment containing the named import aoqi@0: * scope to add to. aoqi@0: */ aoqi@0: private void importNamedStatic(final DiagnosticPosition pos, aoqi@0: final TypeSymbol tsym, aoqi@0: final Name name, aoqi@0: final Env env) { aoqi@0: if (tsym.kind != TYP) { aoqi@0: log.error(DiagnosticFlag.RECOVERABLE, pos, "static.imp.only.classes.and.interfaces"); aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: final Scope toScope = env.toplevel.namedImportScope; aoqi@0: final PackageSymbol packge = env.toplevel.packge; aoqi@0: final TypeSymbol origin = tsym; aoqi@0: aoqi@0: // enter imported types immediately aoqi@0: new Object() { aoqi@0: Set processed = new HashSet(); aoqi@0: void importFrom(TypeSymbol tsym) { aoqi@0: if (tsym == null || !processed.add(tsym)) aoqi@0: return; aoqi@0: aoqi@0: // also import inherited names aoqi@0: importFrom(types.supertype(tsym.type).tsym); aoqi@0: for (Type t : types.interfaces(tsym.type)) aoqi@0: importFrom(t.tsym); aoqi@0: aoqi@0: for (Scope.Entry e = tsym.members().lookup(name); aoqi@0: e.scope != null; aoqi@0: e = e.next()) { aoqi@0: Symbol sym = e.sym; aoqi@0: if (sym.isStatic() && aoqi@0: sym.kind == TYP && aoqi@0: staticImportAccessible(sym, packge) && aoqi@0: sym.isMemberOf(origin, types) && aoqi@0: chk.checkUniqueStaticImport(pos, sym, toScope)) aoqi@0: toScope.enter(sym, sym.owner.members(), origin.members(), true); aoqi@0: } aoqi@0: } aoqi@0: }.importFrom(tsym); aoqi@0: aoqi@0: // enter non-types before annotations that might use them aoqi@0: annotate.earlier(new Annotate.Worker() { aoqi@0: Set processed = new HashSet(); aoqi@0: boolean found = false; aoqi@0: aoqi@0: public String toString() { aoqi@0: return "import static " + tsym + "." + name; aoqi@0: } aoqi@0: void importFrom(TypeSymbol tsym) { aoqi@0: if (tsym == null || !processed.add(tsym)) aoqi@0: return; aoqi@0: aoqi@0: // also import inherited names aoqi@0: importFrom(types.supertype(tsym.type).tsym); aoqi@0: for (Type t : types.interfaces(tsym.type)) aoqi@0: importFrom(t.tsym); aoqi@0: aoqi@0: for (Scope.Entry e = tsym.members().lookup(name); aoqi@0: e.scope != null; aoqi@0: e = e.next()) { aoqi@0: Symbol sym = e.sym; aoqi@0: if (sym.isStatic() && aoqi@0: staticImportAccessible(sym, packge) && aoqi@0: sym.isMemberOf(origin, types)) { aoqi@0: found = true; aoqi@0: if (sym.kind != TYP) { aoqi@0: toScope.enter(sym, sym.owner.members(), origin.members(), true); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: public void run() { aoqi@0: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); aoqi@0: try { aoqi@0: importFrom(tsym); aoqi@0: if (!found) { aoqi@0: log.error(pos, "cant.resolve.location", aoqi@0: KindName.STATIC, aoqi@0: name, List.nil(), List.nil(), aoqi@0: Kinds.typeKindName(tsym.type), aoqi@0: tsym.type); aoqi@0: } aoqi@0: } finally { aoqi@0: log.useSource(prev); aoqi@0: } aoqi@0: } aoqi@0: }); aoqi@0: } aoqi@0: /** Import given class. aoqi@0: * @param pos Position to be used for error reporting. aoqi@0: * @param tsym The class to be imported. aoqi@0: * @param env The environment containing the named import aoqi@0: * scope to add to. aoqi@0: */ aoqi@0: private void importNamed(DiagnosticPosition pos, Symbol tsym, Env env) { aoqi@0: if (tsym.kind == TYP && aoqi@0: chk.checkUniqueImport(pos, tsym, env.toplevel.namedImportScope)) aoqi@0: env.toplevel.namedImportScope.enter(tsym, tsym.owner.members()); aoqi@0: } aoqi@0: aoqi@0: /** Construct method type from method signature. aoqi@0: * @param typarams The method's type parameters. aoqi@0: * @param params The method's value parameters. aoqi@0: * @param res The method's result type, aoqi@0: * null if it is a constructor. aoqi@0: * @param recvparam The method's receiver parameter, aoqi@0: * null if none given; TODO: or already set here? aoqi@0: * @param thrown The method's thrown exceptions. aoqi@0: * @param env The method's (local) environment. aoqi@0: */ aoqi@0: Type signature(MethodSymbol msym, aoqi@0: List typarams, aoqi@0: List params, aoqi@0: JCTree res, aoqi@0: JCVariableDecl recvparam, aoqi@0: List thrown, aoqi@0: Env env) { aoqi@0: aoqi@0: // Enter and attribute type parameters. aoqi@0: List tvars = enter.classEnter(typarams, env); aoqi@0: attr.attribTypeVariables(typarams, env); aoqi@0: aoqi@0: // Enter and attribute value parameters. aoqi@0: ListBuffer argbuf = new ListBuffer(); aoqi@0: for (List l = params; l.nonEmpty(); l = l.tail) { aoqi@0: memberEnter(l.head, env); aoqi@0: argbuf.append(l.head.vartype.type); aoqi@0: } aoqi@0: aoqi@0: // Attribute result type, if one is given. aoqi@0: Type restype = res == null ? syms.voidType : attr.attribType(res, env); aoqi@0: aoqi@0: // Attribute receiver type, if one is given. aoqi@0: Type recvtype; aoqi@0: if (recvparam!=null) { aoqi@0: memberEnter(recvparam, env); aoqi@0: recvtype = recvparam.vartype.type; aoqi@0: } else { aoqi@0: recvtype = null; aoqi@0: } aoqi@0: aoqi@0: // Attribute thrown exceptions. aoqi@0: ListBuffer thrownbuf = new ListBuffer(); aoqi@0: for (List l = thrown; l.nonEmpty(); l = l.tail) { aoqi@0: Type exc = attr.attribType(l.head, env); aoqi@0: if (!exc.hasTag(TYPEVAR)) { aoqi@0: exc = chk.checkClassType(l.head.pos(), exc); aoqi@0: } else if (exc.tsym.owner == msym) { aoqi@0: //mark inference variables in 'throws' clause aoqi@0: exc.tsym.flags_field |= THROWS; aoqi@0: } aoqi@0: thrownbuf.append(exc); aoqi@0: } aoqi@0: MethodType mtype = new MethodType(argbuf.toList(), aoqi@0: restype, aoqi@0: thrownbuf.toList(), aoqi@0: syms.methodClass); aoqi@0: mtype.recvtype = recvtype; aoqi@0: aoqi@0: return tvars.isEmpty() ? mtype : new ForAll(tvars, mtype); aoqi@0: } aoqi@0: aoqi@0: /* ******************************************************************** aoqi@0: * Visitor methods for member enter aoqi@0: *********************************************************************/ aoqi@0: aoqi@0: /** Visitor argument: the current environment aoqi@0: */ aoqi@0: protected Env env; aoqi@0: aoqi@0: /** Enter field and method definitions and process import aoqi@0: * clauses, catching any completion failure exceptions. aoqi@0: */ aoqi@0: protected void memberEnter(JCTree tree, Env env) { aoqi@0: Env prevEnv = this.env; aoqi@0: try { aoqi@0: this.env = env; aoqi@0: tree.accept(this); aoqi@0: } catch (CompletionFailure ex) { aoqi@0: chk.completionError(tree.pos(), ex); aoqi@0: } finally { aoqi@0: this.env = prevEnv; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** Enter members from a list of trees. aoqi@0: */ aoqi@0: void memberEnter(List trees, Env env) { aoqi@0: for (List l = trees; l.nonEmpty(); l = l.tail) aoqi@0: memberEnter(l.head, env); aoqi@0: } aoqi@0: aoqi@0: /** Enter members for a class. aoqi@0: */ aoqi@0: void finishClass(JCClassDecl tree, Env env) { aoqi@0: if ((tree.mods.flags & Flags.ENUM) != 0 && aoqi@0: (types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) { aoqi@0: addEnumMembers(tree, env); aoqi@0: } aoqi@0: memberEnter(tree.defs, env); aoqi@0: } aoqi@0: aoqi@0: /** Add the implicit members for an enum type aoqi@0: * to the symbol table. aoqi@0: */ aoqi@0: private void addEnumMembers(JCClassDecl tree, Env env) { aoqi@0: JCExpression valuesType = make.Type(new ArrayType(tree.sym.type, syms.arrayClass)); aoqi@0: aoqi@0: // public static T[] values() { return ???; } aoqi@0: JCMethodDecl values = make. aoqi@0: MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), aoqi@0: names.values, aoqi@0: valuesType, aoqi@0: List.nil(), aoqi@0: List.nil(), aoqi@0: List.nil(), // thrown aoqi@0: null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), aoqi@0: null); aoqi@0: memberEnter(values, env); aoqi@0: aoqi@0: // public static T valueOf(String name) { return ???; } aoqi@0: JCMethodDecl valueOf = make. aoqi@0: MethodDef(make.Modifiers(Flags.PUBLIC|Flags.STATIC), aoqi@0: names.valueOf, aoqi@0: make.Type(tree.sym.type), aoqi@0: List.nil(), aoqi@0: List.of(make.VarDef(make.Modifiers(Flags.PARAMETER | aoqi@0: Flags.MANDATED), aoqi@0: names.fromString("name"), aoqi@0: make.Type(syms.stringType), null)), aoqi@0: List.nil(), // thrown aoqi@0: null, //make.Block(0, Tree.emptyList.prepend(make.Return(make.Ident(names._null)))), aoqi@0: null); aoqi@0: memberEnter(valueOf, env); aoqi@0: } aoqi@0: aoqi@0: public void visitTopLevel(JCCompilationUnit tree) { aoqi@0: if (tree.starImportScope.elems != null) { aoqi@0: // we must have already processed this toplevel aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: // check that no class exists with same fully qualified name as aoqi@0: // toplevel package aoqi@0: if (checkClash && tree.pid != null) { aoqi@0: Symbol p = tree.packge; aoqi@0: while (p.owner != syms.rootPackage) { aoqi@0: p.owner.complete(); // enter all class members of p aoqi@0: if (syms.classes.get(p.getQualifiedName()) != null) { aoqi@0: log.error(tree.pos, aoqi@0: "pkg.clashes.with.class.of.same.name", aoqi@0: p); aoqi@0: } aoqi@0: p = p.owner; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // process package annotations aoqi@0: annotateLater(tree.packageAnnotations, env, tree.packge, null); aoqi@0: aoqi@0: DiagnosticPosition prevLintPos = deferredLintHandler.immediate(); aoqi@0: Lint prevLint = chk.setLint(lint); aoqi@0: aoqi@0: try { aoqi@0: // Import-on-demand java.lang. aoqi@0: importAll(tree.pos, reader.enterPackage(names.java_lang), env); aoqi@0: aoqi@0: // Process all import clauses. aoqi@0: memberEnter(tree.defs, env); aoqi@0: } finally { aoqi@0: chk.setLint(prevLint); aoqi@0: deferredLintHandler.setPos(prevLintPos); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: // process the non-static imports and the static imports of types. aoqi@0: public void visitImport(JCImport tree) { aoqi@0: JCFieldAccess imp = (JCFieldAccess)tree.qualid; aoqi@0: Name name = TreeInfo.name(imp); aoqi@0: aoqi@0: // Create a local environment pointing to this tree to disable aoqi@0: // effects of other imports in Resolve.findGlobalType aoqi@0: Env localEnv = env.dup(tree); aoqi@0: aoqi@0: TypeSymbol p = attr.attribImportQualifier(tree, localEnv).tsym; aoqi@0: if (name == names.asterisk) { aoqi@0: // Import on demand. aoqi@0: chk.checkCanonical(imp.selected); aoqi@0: if (tree.staticImport) aoqi@0: importStaticAll(tree.pos, p, env); aoqi@0: else aoqi@0: importAll(tree.pos, p, env); aoqi@0: } else { aoqi@0: // Named type import. aoqi@0: if (tree.staticImport) { aoqi@0: importNamedStatic(tree.pos(), p, name, localEnv); aoqi@0: chk.checkCanonical(imp.selected); aoqi@0: } else { aoqi@0: TypeSymbol c = attribImportType(imp, localEnv).tsym; aoqi@0: chk.checkCanonical(imp); aoqi@0: importNamed(tree.pos(), c, env); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void visitMethodDef(JCMethodDecl tree) { aoqi@0: Scope enclScope = enter.enterScope(env); aoqi@0: MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner); aoqi@0: m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree); aoqi@0: tree.sym = m; aoqi@0: aoqi@0: //if this is a default method, add the DEFAULT flag to the enclosing interface aoqi@0: if ((tree.mods.flags & DEFAULT) != 0) { aoqi@0: m.enclClass().flags_field |= DEFAULT; aoqi@0: } aoqi@0: aoqi@0: Env localEnv = methodEnv(tree, env); aoqi@0: jfranck@2596: DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos()); aoqi@0: try { jfranck@2596: // Compute the method type jfranck@2596: m.type = signature(m, tree.typarams, tree.params, jfranck@2596: tree.restype, tree.recvparam, jfranck@2596: tree.thrown, jfranck@2596: localEnv); jfranck@2596: } finally { jfranck@2596: deferredLintHandler.setPos(prevLintPos); jfranck@2596: } aoqi@0: jfranck@2596: if (types.isSignaturePolymorphic(m)) { jfranck@2596: m.flags_field |= SIGNATURE_POLYMORPHIC; jfranck@2596: } aoqi@0: jfranck@2596: // Set m.params jfranck@2596: ListBuffer params = new ListBuffer(); jfranck@2596: JCVariableDecl lastParam = null; jfranck@2596: for (List l = tree.params; l.nonEmpty(); l = l.tail) { jfranck@2596: JCVariableDecl param = lastParam = l.head; jfranck@2596: params.append(Assert.checkNonNull(param.sym)); jfranck@2596: } jfranck@2596: m.params = params.toList(); aoqi@0: jfranck@2596: // mark the method varargs, if necessary jfranck@2596: if (lastParam != null && (lastParam.mods.flags & Flags.VARARGS) != 0) jfranck@2596: m.flags_field |= Flags.VARARGS; aoqi@0: jfranck@2596: localEnv.info.scope.leave(); jfranck@2596: if (chk.checkUnique(tree.pos(), m, enclScope)) { jfranck@2596: enclScope.enter(m); jfranck@2596: } aoqi@0: jfranck@2596: annotateLater(tree.mods.annotations, localEnv, m, tree.pos()); jfranck@2596: // Visit the signature of the method. Note that jfranck@2596: // TypeAnnotate doesn't descend into the body. jfranck@2596: typeAnnotate(tree, localEnv, m, tree.pos()); aoqi@0: jfranck@2596: if (tree.defaultValue != null) jfranck@2596: annotateDefaultValueLater(tree.defaultValue, localEnv, m); aoqi@0: } aoqi@0: aoqi@0: /** Create a fresh environment for method bodies. aoqi@0: * @param tree The method definition. aoqi@0: * @param env The environment current outside of the method definition. aoqi@0: */ aoqi@0: Env methodEnv(JCMethodDecl tree, Env env) { aoqi@0: Env localEnv = aoqi@0: env.dup(tree, env.info.dup(env.info.scope.dupUnshared())); aoqi@0: localEnv.enclMethod = tree; aoqi@0: localEnv.info.scope.owner = tree.sym; aoqi@0: if (tree.sym.type != null) { aoqi@0: //when this is called in the enter stage, there's no type to be set aoqi@0: localEnv.info.returnResult = attr.new ResultInfo(VAL, tree.sym.type.getReturnType()); aoqi@0: } aoqi@0: if ((tree.mods.flags & STATIC) != 0) localEnv.info.staticLevel++; aoqi@0: return localEnv; aoqi@0: } aoqi@0: aoqi@0: public void visitVarDef(JCVariableDecl tree) { aoqi@0: Env localEnv = env; aoqi@0: if ((tree.mods.flags & STATIC) != 0 || aoqi@0: (env.info.scope.owner.flags() & INTERFACE) != 0) { aoqi@0: localEnv = env.dup(tree, env.info.dup()); aoqi@0: localEnv.info.staticLevel++; aoqi@0: } aoqi@0: DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos()); aoqi@0: try { jfranck@2596: if (TreeInfo.isEnumInit(tree)) { jfranck@2596: attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype); jfranck@2596: } else { jfranck@2596: attr.attribType(tree.vartype, localEnv); jfranck@2596: if (TreeInfo.isReceiverParam(tree)) jfranck@2596: checkReceiver(tree, localEnv); aoqi@0: } jfranck@2596: } finally { jfranck@2596: deferredLintHandler.setPos(prevLintPos); jfranck@2596: } aoqi@0: jfranck@2596: if ((tree.mods.flags & VARARGS) != 0) { jfranck@2596: //if we are entering a varargs parameter, we need to jfranck@2596: //replace its type (a plain array type) with the more jfranck@2596: //precise VarargsType --- we need to do it this way jfranck@2596: //because varargs is represented in the tree as a jfranck@2596: //modifier on the parameter declaration, and not as a jfranck@2596: //distinct type of array node. jfranck@2596: ArrayType atype = (ArrayType)tree.vartype.type.unannotatedType(); jfranck@2596: tree.vartype.type = atype.makeVarargs(); jfranck@2596: } jfranck@2596: Scope enclScope = enter.enterScope(env); jfranck@2596: VarSymbol v = jfranck@2596: new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner); jfranck@2596: v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree); jfranck@2596: tree.sym = v; jfranck@2596: if (tree.init != null) { jfranck@2596: v.flags_field |= HASINIT; jfranck@2596: if ((v.flags_field & FINAL) != 0 && jfranck@2596: needsLazyConstValue(tree.init)) { jfranck@2596: Env initEnv = getInitEnv(tree, env); jfranck@2596: initEnv.info.enclVar = v; jfranck@2596: v.setLazyConstValue(initEnv(tree, initEnv), attr, tree); aoqi@0: } aoqi@0: } jfranck@2596: if (chk.checkUnique(tree.pos(), v, enclScope)) { jfranck@2596: chk.checkTransparentVar(tree.pos(), v, enclScope); jfranck@2596: enclScope.enter(v); jfranck@2596: } jfranck@2596: annotateLater(tree.mods.annotations, localEnv, v, tree.pos()); jfranck@2596: typeAnnotate(tree.vartype, env, v, tree.pos()); jfranck@2596: v.pos = tree.pos; aoqi@0: } aoqi@0: // where aoqi@0: void checkType(JCTree tree, Type type, String diag) { aoqi@0: if (!tree.type.isErroneous() && !types.isSameType(tree.type, type)) { aoqi@0: log.error(tree, diag, type, tree.type); aoqi@0: } aoqi@0: } aoqi@0: void checkReceiver(JCVariableDecl tree, Env localEnv) { aoqi@0: attr.attribExpr(tree.nameexpr, localEnv); aoqi@0: MethodSymbol m = localEnv.enclMethod.sym; aoqi@0: if (m.isConstructor()) { aoqi@0: Type outertype = m.owner.owner.type; aoqi@0: if (outertype.hasTag(TypeTag.METHOD)) { aoqi@0: // we have a local inner class aoqi@0: outertype = m.owner.owner.owner.type; aoqi@0: } aoqi@0: if (outertype.hasTag(TypeTag.CLASS)) { aoqi@0: checkType(tree.vartype, outertype, "incorrect.constructor.receiver.type"); aoqi@0: checkType(tree.nameexpr, outertype, "incorrect.constructor.receiver.name"); aoqi@0: } else { aoqi@0: log.error(tree, "receiver.parameter.not.applicable.constructor.toplevel.class"); aoqi@0: } aoqi@0: } else { aoqi@0: checkType(tree.vartype, m.owner.type, "incorrect.receiver.type"); aoqi@0: checkType(tree.nameexpr, m.owner.type, "incorrect.receiver.name"); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public boolean needsLazyConstValue(JCTree tree) { aoqi@0: InitTreeVisitor initTreeVisitor = new InitTreeVisitor(); aoqi@0: tree.accept(initTreeVisitor); aoqi@0: return initTreeVisitor.result; aoqi@0: } aoqi@0: aoqi@0: /** Visitor class for expressions which might be constant expressions. aoqi@0: */ aoqi@0: static class InitTreeVisitor extends JCTree.Visitor { aoqi@0: aoqi@0: private boolean result = true; aoqi@0: aoqi@0: @Override aoqi@0: public void visitTree(JCTree tree) {} aoqi@0: aoqi@0: @Override aoqi@0: public void visitNewClass(JCNewClass that) { aoqi@0: result = false; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitNewArray(JCNewArray that) { aoqi@0: result = false; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitLambda(JCLambda that) { aoqi@0: result = false; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitReference(JCMemberReference that) { aoqi@0: result = false; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitApply(JCMethodInvocation that) { aoqi@0: result = false; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitSelect(JCFieldAccess tree) { aoqi@0: tree.selected.accept(this); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitConditional(JCConditional tree) { aoqi@0: tree.cond.accept(this); aoqi@0: tree.truepart.accept(this); aoqi@0: tree.falsepart.accept(this); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitParens(JCParens tree) { aoqi@0: tree.expr.accept(this); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitTypeCast(JCTypeCast tree) { aoqi@0: tree.expr.accept(this); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** Create a fresh environment for a variable's initializer. aoqi@0: * If the variable is a field, the owner of the environment's scope aoqi@0: * is be the variable itself, otherwise the owner is the method aoqi@0: * enclosing the variable definition. aoqi@0: * aoqi@0: * @param tree The variable definition. aoqi@0: * @param env The environment current outside of the variable definition. aoqi@0: */ aoqi@0: Env initEnv(JCVariableDecl tree, Env env) { aoqi@0: Env localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup())); aoqi@0: if (tree.sym.owner.kind == TYP) { aoqi@0: localEnv.info.scope = env.info.scope.dupUnshared(); aoqi@0: localEnv.info.scope.owner = tree.sym; aoqi@0: } aoqi@0: if ((tree.mods.flags & STATIC) != 0 || aoqi@0: ((env.enclClass.sym.flags() & INTERFACE) != 0 && env.enclMethod == null)) aoqi@0: localEnv.info.staticLevel++; aoqi@0: return localEnv; aoqi@0: } aoqi@0: aoqi@0: /** Default member enter visitor method: do nothing aoqi@0: */ aoqi@0: public void visitTree(JCTree tree) { aoqi@0: } aoqi@0: aoqi@0: public void visitErroneous(JCErroneous tree) { aoqi@0: if (tree.errs != null) aoqi@0: memberEnter(tree.errs, env); aoqi@0: } aoqi@0: aoqi@0: public Env getMethodEnv(JCMethodDecl tree, Env env) { aoqi@0: Env mEnv = methodEnv(tree, env); aoqi@0: mEnv.info.lint = mEnv.info.lint.augment(tree.sym); aoqi@0: for (List l = tree.typarams; l.nonEmpty(); l = l.tail) aoqi@0: mEnv.info.scope.enterIfAbsent(l.head.type.tsym); aoqi@0: for (List l = tree.params; l.nonEmpty(); l = l.tail) aoqi@0: mEnv.info.scope.enterIfAbsent(l.head.sym); aoqi@0: return mEnv; aoqi@0: } aoqi@0: aoqi@0: public Env getInitEnv(JCVariableDecl tree, Env env) { aoqi@0: Env iEnv = initEnv(tree, env); aoqi@0: return iEnv; aoqi@0: } aoqi@0: aoqi@0: /* ******************************************************************** aoqi@0: * Type completion aoqi@0: *********************************************************************/ aoqi@0: aoqi@0: Type attribImportType(JCTree tree, Env env) { aoqi@0: Assert.check(completionEnabled); aoqi@0: try { aoqi@0: // To prevent deep recursion, suppress completion of some aoqi@0: // types. aoqi@0: completionEnabled = false; aoqi@0: return attr.attribType(tree, env); aoqi@0: } finally { aoqi@0: completionEnabled = true; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /* ******************************************************************** aoqi@0: * Annotation processing aoqi@0: *********************************************************************/ aoqi@0: aoqi@0: /** Queue annotations for later processing. */ aoqi@0: void annotateLater(final List annotations, aoqi@0: final Env localEnv, aoqi@0: final Symbol s, aoqi@0: final DiagnosticPosition deferPos) { aoqi@0: if (annotations.isEmpty()) { aoqi@0: return; aoqi@0: } aoqi@0: if (s.kind != PCK) { aoqi@0: s.resetAnnotations(); // mark Annotations as incomplete for now aoqi@0: } aoqi@0: annotate.normal(new Annotate.Worker() { aoqi@0: @Override aoqi@0: public String toString() { aoqi@0: return "annotate " + annotations + " onto " + s + " in " + s.owner; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void run() { aoqi@0: Assert.check(s.kind == PCK || s.annotationsPendingCompletion()); aoqi@0: JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); aoqi@0: DiagnosticPosition prevLintPos = aoqi@0: deferPos != null aoqi@0: ? deferredLintHandler.setPos(deferPos) aoqi@0: : deferredLintHandler.immediate(); aoqi@0: Lint prevLint = deferPos != null ? null : chk.setLint(lint); aoqi@0: try { aoqi@0: if (s.hasAnnotations() && aoqi@0: annotations.nonEmpty()) aoqi@0: log.error(annotations.head.pos, aoqi@0: "already.annotated", aoqi@0: kindName(s), s); aoqi@0: actualEnterAnnotations(annotations, localEnv, s); aoqi@0: } finally { aoqi@0: if (prevLint != null) aoqi@0: chk.setLint(prevLint); aoqi@0: deferredLintHandler.setPos(prevLintPos); aoqi@0: log.useSource(prev); aoqi@0: } aoqi@0: } aoqi@0: }); aoqi@0: aoqi@0: annotate.validate(new Annotate.Worker() { //validate annotations aoqi@0: @Override aoqi@0: public void run() { aoqi@0: JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); aoqi@0: try { aoqi@0: chk.validateAnnotations(annotations, s); aoqi@0: } finally { aoqi@0: log.useSource(prev); aoqi@0: } aoqi@0: } aoqi@0: }); aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Check if a list of annotations contains a reference to aoqi@0: * java.lang.Deprecated. aoqi@0: **/ aoqi@0: private boolean hasDeprecatedAnnotation(List annotations) { aoqi@0: for (List al = annotations; !al.isEmpty(); al = al.tail) { aoqi@0: JCAnnotation a = al.head; aoqi@0: if (a.annotationType.type == syms.deprecatedType && a.args.isEmpty()) aoqi@0: return true; aoqi@0: } aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: /** Enter a set of annotations. */ aoqi@0: private void actualEnterAnnotations(List annotations, aoqi@0: Env env, aoqi@0: Symbol s) { aoqi@0: Map> annotated = aoqi@0: new LinkedHashMap>(); aoqi@0: Map pos = aoqi@0: new HashMap(); aoqi@0: aoqi@0: for (List al = annotations; !al.isEmpty(); al = al.tail) { aoqi@0: JCAnnotation a = al.head; aoqi@0: Attribute.Compound c = annotate.enterAnnotation(a, aoqi@0: syms.annotationType, aoqi@0: env); aoqi@0: if (c == null) { aoqi@0: continue; aoqi@0: } aoqi@0: aoqi@0: if (annotated.containsKey(a.type.tsym)) { aoqi@0: if (!allowRepeatedAnnos) { aoqi@0: log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); aoqi@0: allowRepeatedAnnos = true; aoqi@0: } aoqi@0: ListBuffer l = annotated.get(a.type.tsym); aoqi@0: l = l.append(c); aoqi@0: annotated.put(a.type.tsym, l); aoqi@0: pos.put(c, a.pos()); aoqi@0: } else { aoqi@0: annotated.put(a.type.tsym, ListBuffer.of(c)); aoqi@0: pos.put(c, a.pos()); aoqi@0: } aoqi@0: aoqi@0: // Note: @Deprecated has no effect on local variables and parameters aoqi@0: if (!c.type.isErroneous() aoqi@0: && s.owner.kind != MTH aoqi@0: && types.isSameType(c.type, syms.deprecatedType)) { aoqi@0: s.flags_field |= Flags.DEPRECATED; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: s.setDeclarationAttributesWithCompletion( aoqi@0: annotate.new AnnotateRepeatedContext(env, annotated, pos, log, false)); aoqi@0: } aoqi@0: aoqi@0: /** Queue processing of an attribute default value. */ aoqi@0: void annotateDefaultValueLater(final JCExpression defaultValue, aoqi@0: final Env localEnv, aoqi@0: final MethodSymbol m) { aoqi@0: annotate.normal(new Annotate.Worker() { aoqi@0: @Override aoqi@0: public String toString() { aoqi@0: return "annotate " + m.owner + "." + aoqi@0: m + " default " + defaultValue; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void run() { aoqi@0: JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); aoqi@0: try { aoqi@0: enterDefaultValue(defaultValue, localEnv, m); aoqi@0: } finally { aoqi@0: log.useSource(prev); aoqi@0: } aoqi@0: } aoqi@0: }); aoqi@0: annotate.validate(new Annotate.Worker() { //validate annotations aoqi@0: @Override aoqi@0: public void run() { aoqi@0: JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile); aoqi@0: try { aoqi@0: // if default value is an annotation, check it is a well-formed aoqi@0: // annotation value (e.g. no duplicate values, no missing values, etc.) aoqi@0: chk.validateAnnotationTree(defaultValue); aoqi@0: } finally { aoqi@0: log.useSource(prev); aoqi@0: } aoqi@0: } aoqi@0: }); aoqi@0: } aoqi@0: aoqi@0: /** Enter a default value for an attribute method. */ aoqi@0: private void enterDefaultValue(final JCExpression defaultValue, aoqi@0: final Env localEnv, aoqi@0: final MethodSymbol m) { aoqi@0: m.defaultValue = annotate.enterAttributeValue(m.type.getReturnType(), aoqi@0: defaultValue, aoqi@0: localEnv); aoqi@0: } aoqi@0: aoqi@0: /* ******************************************************************** aoqi@0: * Source completer aoqi@0: *********************************************************************/ aoqi@0: aoqi@0: /** Complete entering a class. aoqi@0: * @param sym The symbol of the class to be completed. aoqi@0: */ aoqi@0: public void complete(Symbol sym) throws CompletionFailure { aoqi@0: // Suppress some (recursive) MemberEnter invocations aoqi@0: if (!completionEnabled) { aoqi@0: // Re-install same completer for next time around and return. aoqi@0: Assert.check((sym.flags() & Flags.COMPOUND) == 0); aoqi@0: sym.completer = this; aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: ClassSymbol c = (ClassSymbol)sym; aoqi@0: ClassType ct = (ClassType)c.type; aoqi@0: Env env = typeEnvs.get(c); aoqi@0: JCClassDecl tree = (JCClassDecl)env.tree; aoqi@0: boolean wasFirst = isFirst; aoqi@0: isFirst = false; jfranck@2596: try { jfranck@2596: annotate.enterStart(); aoqi@0: jfranck@2596: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); jfranck@2596: DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos()); jfranck@2596: try { jfranck@2596: // Save class environment for later member enter (2) processing. jfranck@2596: halfcompleted.append(env); aoqi@0: jfranck@2596: // Mark class as not yet attributed. jfranck@2596: c.flags_field |= UNATTRIBUTED; aoqi@0: jfranck@2596: // If this is a toplevel-class, make sure any preceding import jfranck@2596: // clauses have been seen. jfranck@2596: if (c.owner.kind == PCK) { jfranck@2596: memberEnter(env.toplevel, env.enclosing(TOPLEVEL)); jfranck@2596: todo.append(env); jfranck@2596: } jfranck@2596: jfranck@2596: if (c.owner.kind == TYP) jfranck@2596: c.owner.complete(); jfranck@2596: jfranck@2596: // create an environment for evaluating the base clauses jfranck@2596: Env baseEnv = baseEnv(tree, env); jfranck@2596: jfranck@2596: if (tree.extending != null) jfranck@2596: typeAnnotate(tree.extending, baseEnv, sym, tree.pos()); jfranck@2596: for (JCExpression impl : tree.implementing) jfranck@2596: typeAnnotate(impl, baseEnv, sym, tree.pos()); jfranck@2596: annotate.flush(); jfranck@2596: jfranck@2596: // Determine supertype. jfranck@2596: Type supertype = jfranck@2596: (tree.extending != null) jfranck@2596: ? attr.attribBase(tree.extending, baseEnv, true, false, true) jfranck@2596: : ((tree.mods.flags & Flags.ENUM) != 0) jfranck@2596: ? attr.attribBase(enumBase(tree.pos, c), baseEnv, jfranck@2596: true, false, false) jfranck@2596: : (c.fullname == names.java_lang_Object) jfranck@2596: ? Type.noType jfranck@2596: : syms.objectType; jfranck@2596: ct.supertype_field = modelMissingTypes(supertype, tree.extending, false); jfranck@2596: jfranck@2596: // Determine interfaces. jfranck@2596: ListBuffer interfaces = new ListBuffer(); jfranck@2596: ListBuffer all_interfaces = null; // lazy init jfranck@2596: Set interfaceSet = new HashSet(); jfranck@2596: List interfaceTrees = tree.implementing; jfranck@2596: for (JCExpression iface : interfaceTrees) { jfranck@2596: Type i = attr.attribBase(iface, baseEnv, false, true, true); jfranck@2596: if (i.hasTag(CLASS)) { jfranck@2596: interfaces.append(i); jfranck@2596: if (all_interfaces != null) all_interfaces.append(i); jfranck@2596: chk.checkNotRepeated(iface.pos(), types.erasure(i), interfaceSet); jfranck@2596: } else { jfranck@2596: if (all_interfaces == null) jfranck@2596: all_interfaces = new ListBuffer().appendList(interfaces); jfranck@2596: all_interfaces.append(modelMissingTypes(i, iface, true)); jfranck@2596: } jfranck@2596: } jfranck@2596: if ((c.flags_field & ANNOTATION) != 0) { jfranck@2596: ct.interfaces_field = List.of(syms.annotationType); jfranck@2596: ct.all_interfaces_field = ct.interfaces_field; jfranck@2596: } else { jfranck@2596: ct.interfaces_field = interfaces.toList(); jfranck@2596: ct.all_interfaces_field = (all_interfaces == null) jfranck@2596: ? ct.interfaces_field : all_interfaces.toList(); jfranck@2596: } jfranck@2596: jfranck@2596: if (c.fullname == names.java_lang_Object) { jfranck@2596: if (tree.extending != null) { jfranck@2596: chk.checkNonCyclic(tree.extending.pos(), jfranck@2596: supertype); jfranck@2596: ct.supertype_field = Type.noType; jfranck@2596: } jfranck@2596: else if (tree.implementing.nonEmpty()) { jfranck@2596: chk.checkNonCyclic(tree.implementing.head.pos(), jfranck@2596: ct.interfaces_field.head); jfranck@2596: ct.interfaces_field = List.nil(); jfranck@2596: } jfranck@2596: } jfranck@2596: jfranck@2596: // Annotations. jfranck@2596: // In general, we cannot fully process annotations yet, but we jfranck@2596: // can attribute the annotation types and then check to see if the jfranck@2596: // @Deprecated annotation is present. jfranck@2596: attr.attribAnnotationTypes(tree.mods.annotations, baseEnv); jfranck@2596: if (hasDeprecatedAnnotation(tree.mods.annotations)) jfranck@2596: c.flags_field |= DEPRECATED; jfranck@2596: annotateLater(tree.mods.annotations, baseEnv, c, tree.pos()); jfranck@2596: // class type parameters use baseEnv but everything uses env jfranck@2596: jfranck@2596: chk.checkNonCyclicDecl(tree); jfranck@2596: jfranck@2596: attr.attribTypeVariables(tree.typarams, baseEnv); jfranck@2596: // Do this here, where we have the symbol. jfranck@2596: for (JCTypeParameter tp : tree.typarams) jfranck@2596: typeAnnotate(tp, baseEnv, sym, tree.pos()); jfranck@2596: jfranck@2596: // Add default constructor if needed. jfranck@2596: if ((c.flags() & INTERFACE) == 0 && jfranck@2596: !TreeInfo.hasConstructors(tree.defs)) { jfranck@2596: List argtypes = List.nil(); jfranck@2596: List typarams = List.nil(); jfranck@2596: List thrown = List.nil(); jfranck@2596: long ctorFlags = 0; jfranck@2596: boolean based = false; jfranck@2596: boolean addConstructor = true; jfranck@2596: JCNewClass nc = null; jfranck@2596: if (c.name.isEmpty()) { jfranck@2596: nc = (JCNewClass)env.next.tree; jfranck@2596: if (nc.constructor != null) { jfranck@2596: addConstructor = nc.constructor.kind != ERR; jfranck@2596: Type superConstrType = types.memberType(c.type, jfranck@2596: nc.constructor); jfranck@2596: argtypes = superConstrType.getParameterTypes(); jfranck@2596: typarams = superConstrType.getTypeArguments(); jfranck@2596: ctorFlags = nc.constructor.flags() & VARARGS; jfranck@2596: if (nc.encl != null) { jfranck@2596: argtypes = argtypes.prepend(nc.encl.type); jfranck@2596: based = true; jfranck@2596: } jfranck@2596: thrown = superConstrType.getThrownTypes(); jfranck@2596: } jfranck@2596: } jfranck@2596: if (addConstructor) { jfranck@2596: MethodSymbol basedConstructor = nc != null ? jfranck@2596: (MethodSymbol)nc.constructor : null; jfranck@2596: JCTree constrDef = DefaultConstructor(make.at(tree.pos), c, jfranck@2596: basedConstructor, jfranck@2596: typarams, argtypes, thrown, jfranck@2596: ctorFlags, based); jfranck@2596: tree.defs = tree.defs.prepend(constrDef); jfranck@2596: } jfranck@2596: } jfranck@2596: jfranck@2596: // enter symbols for 'this' into current scope. jfranck@2596: VarSymbol thisSym = jfranck@2596: new VarSymbol(FINAL | HASINIT, names._this, c.type, c); jfranck@2596: thisSym.pos = Position.FIRSTPOS; jfranck@2596: env.info.scope.enter(thisSym); jfranck@2596: // if this is a class, enter symbol for 'super' into current scope. jfranck@2596: if ((c.flags_field & INTERFACE) == 0 && jfranck@2596: ct.supertype_field.hasTag(CLASS)) { jfranck@2596: VarSymbol superSym = jfranck@2596: new VarSymbol(FINAL | HASINIT, names._super, jfranck@2596: ct.supertype_field, c); jfranck@2596: superSym.pos = Position.FIRSTPOS; jfranck@2596: env.info.scope.enter(superSym); jfranck@2596: } jfranck@2596: jfranck@2596: // check that no package exists with same fully qualified name, jfranck@2596: // but admit classes in the unnamed package which have the same jfranck@2596: // name as a top-level package. jfranck@2596: if (checkClash && jfranck@2596: c.owner.kind == PCK && c.owner != syms.unnamedPackage && jfranck@2596: reader.packageExists(c.fullname)) { jfranck@2596: log.error(tree.pos, "clash.with.pkg.of.same.name", Kinds.kindName(sym), c); jfranck@2596: } jfranck@2596: if (c.owner.kind == PCK && (c.flags_field & PUBLIC) == 0 && jfranck@2596: !env.toplevel.sourcefile.isNameCompatible(c.name.toString(),JavaFileObject.Kind.SOURCE)) { jfranck@2596: c.flags_field |= AUXILIARY; jfranck@2596: } jfranck@2596: } catch (CompletionFailure ex) { jfranck@2596: chk.completionError(tree.pos(), ex); jfranck@2596: } finally { jfranck@2596: deferredLintHandler.setPos(prevLintPos); jfranck@2596: log.useSource(prev); aoqi@0: } aoqi@0: jfranck@2596: // Enter all member fields and methods of a set of half completed jfranck@2596: // classes in a second phase. jfranck@2596: if (wasFirst) { jfranck@2596: try { jfranck@2596: while (halfcompleted.nonEmpty()) { jfranck@2596: Env toFinish = halfcompleted.next(); jfranck@2596: finish(toFinish); jfranck@2596: if (allowTypeAnnos) { jfranck@2596: typeAnnotations.organizeTypeAnnotationsSignatures(toFinish, (JCClassDecl)toFinish.tree); jfranck@2596: typeAnnotations.validateTypeAnnotationsSignatures(toFinish, (JCClassDecl)toFinish.tree); jfranck@2596: } jfranck@2596: } jfranck@2596: } finally { jfranck@2596: isFirst = true; aoqi@0: } aoqi@0: } aoqi@0: } finally { jfranck@2596: annotate.enterDone(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /* aoqi@0: * If the symbol is non-null, attach the type annotation to it. aoqi@0: */ aoqi@0: private void actualEnterTypeAnnotations(final List annotations, aoqi@0: final Env env, aoqi@0: final Symbol s) { aoqi@0: Map> annotated = aoqi@0: new LinkedHashMap>(); aoqi@0: Map pos = aoqi@0: new HashMap(); aoqi@0: aoqi@0: for (List al = annotations; !al.isEmpty(); al = al.tail) { aoqi@0: JCAnnotation a = al.head; aoqi@0: Attribute.TypeCompound tc = annotate.enterTypeAnnotation(a, aoqi@0: syms.annotationType, aoqi@0: env); aoqi@0: if (tc == null) { aoqi@0: continue; aoqi@0: } aoqi@0: aoqi@0: if (annotated.containsKey(a.type.tsym)) { aoqi@0: if (source.allowRepeatedAnnotations()) { aoqi@0: ListBuffer l = annotated.get(a.type.tsym); aoqi@0: l = l.append(tc); aoqi@0: annotated.put(a.type.tsym, l); aoqi@0: pos.put(tc, a.pos()); aoqi@0: } else { aoqi@0: log.error(a.pos(), "repeatable.annotations.not.supported.in.source"); aoqi@0: } aoqi@0: } else { aoqi@0: annotated.put(a.type.tsym, ListBuffer.of(tc)); aoqi@0: pos.put(tc, a.pos()); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if (s != null) { aoqi@0: s.appendTypeAttributesWithCompletion( aoqi@0: annotate.new AnnotateRepeatedContext(env, annotated, pos, log, true)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: public void typeAnnotate(final JCTree tree, final Env env, final Symbol sym, DiagnosticPosition deferPos) { aoqi@0: if (allowTypeAnnos) { aoqi@0: tree.accept(new TypeAnnotate(env, sym, deferPos)); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * We need to use a TreeScanner, because it is not enough to visit the top-level aoqi@0: * annotations. We also need to visit type arguments, etc. aoqi@0: */ aoqi@0: private class TypeAnnotate extends TreeScanner { aoqi@0: private Env env; aoqi@0: private Symbol sym; aoqi@0: private DiagnosticPosition deferPos; aoqi@0: aoqi@0: public TypeAnnotate(final Env env, final Symbol sym, DiagnosticPosition deferPos) { aoqi@0: this.env = env; aoqi@0: this.sym = sym; aoqi@0: this.deferPos = deferPos; aoqi@0: } aoqi@0: aoqi@0: void annotateTypeLater(final List annotations) { aoqi@0: if (annotations.isEmpty()) { aoqi@0: return; aoqi@0: } aoqi@0: aoqi@0: final DiagnosticPosition deferPos = this.deferPos; aoqi@0: aoqi@0: annotate.normal(new Annotate.Worker() { aoqi@0: @Override aoqi@0: public String toString() { aoqi@0: return "type annotate " + annotations + " onto " + sym + " in " + sym.owner; aoqi@0: } aoqi@0: @Override aoqi@0: public void run() { aoqi@0: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); aoqi@0: DiagnosticPosition prevLintPos = null; aoqi@0: aoqi@0: if (deferPos != null) { aoqi@0: prevLintPos = deferredLintHandler.setPos(deferPos); aoqi@0: } aoqi@0: try { aoqi@0: actualEnterTypeAnnotations(annotations, env, sym); aoqi@0: } finally { aoqi@0: if (prevLintPos != null) aoqi@0: deferredLintHandler.setPos(prevLintPos); aoqi@0: log.useSource(prev); aoqi@0: } aoqi@0: } aoqi@0: }); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitAnnotatedType(final JCAnnotatedType tree) { aoqi@0: annotateTypeLater(tree.annotations); aoqi@0: super.visitAnnotatedType(tree); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitTypeParameter(final JCTypeParameter tree) { aoqi@0: annotateTypeLater(tree.annotations); aoqi@0: super.visitTypeParameter(tree); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitNewArray(final JCNewArray tree) { aoqi@0: annotateTypeLater(tree.annotations); aoqi@0: for (List dimAnnos : tree.dimAnnotations) aoqi@0: annotateTypeLater(dimAnnos); aoqi@0: super.visitNewArray(tree); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitMethodDef(final JCMethodDecl tree) { aoqi@0: scan(tree.mods); aoqi@0: scan(tree.restype); aoqi@0: scan(tree.typarams); aoqi@0: scan(tree.recvparam); aoqi@0: scan(tree.params); aoqi@0: scan(tree.thrown); aoqi@0: scan(tree.defaultValue); aoqi@0: // Do not annotate the body, just the signature. aoqi@0: // scan(tree.body); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitVarDef(final JCVariableDecl tree) { aoqi@0: DiagnosticPosition prevPos = deferPos; aoqi@0: deferPos = tree.pos(); aoqi@0: try { aoqi@0: if (sym != null && sym.kind == Kinds.VAR) { aoqi@0: // Don't visit a parameter once when the sym is the method aoqi@0: // and once when the sym is the parameter. aoqi@0: scan(tree.mods); aoqi@0: scan(tree.vartype); aoqi@0: } aoqi@0: scan(tree.init); aoqi@0: } finally { aoqi@0: deferPos = prevPos; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitClassDef(JCClassDecl tree) { aoqi@0: // We can only hit a classdef if it is declared within aoqi@0: // a method. Ignore it - the class will be visited aoqi@0: // separately later. aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitNewClass(JCNewClass tree) { aoqi@0: if (tree.def == null) { aoqi@0: // For an anonymous class instantiation the class aoqi@0: // will be visited separately. aoqi@0: super.visitNewClass(tree); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: private Env baseEnv(JCClassDecl tree, Env env) { aoqi@0: Scope baseScope = new Scope(tree.sym); aoqi@0: //import already entered local classes into base scope aoqi@0: for (Scope.Entry e = env.outer.info.scope.elems ; e != null ; e = e.sibling) { aoqi@0: if (e.sym.isLocal()) { aoqi@0: baseScope.enter(e.sym); aoqi@0: } aoqi@0: } aoqi@0: //import current type-parameters into base scope aoqi@0: if (tree.typarams != null) aoqi@0: for (List typarams = tree.typarams; aoqi@0: typarams.nonEmpty(); aoqi@0: typarams = typarams.tail) aoqi@0: baseScope.enter(typarams.head.type.tsym); aoqi@0: Env outer = env.outer; // the base clause can't see members of this class aoqi@0: Env localEnv = outer.dup(tree, outer.info.dup(baseScope)); aoqi@0: localEnv.baseClause = true; aoqi@0: localEnv.outer = outer; aoqi@0: localEnv.info.isSelfCall = false; aoqi@0: return localEnv; aoqi@0: } aoqi@0: aoqi@0: /** Enter member fields and methods of a class aoqi@0: * @param env the environment current for the class block. aoqi@0: */ aoqi@0: private void finish(Env env) { aoqi@0: JavaFileObject prev = log.useSource(env.toplevel.sourcefile); aoqi@0: try { aoqi@0: JCClassDecl tree = (JCClassDecl)env.tree; aoqi@0: finishClass(tree, env); aoqi@0: } finally { aoqi@0: log.useSource(prev); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** Generate a base clause for an enum type. aoqi@0: * @param pos The position for trees and diagnostics, if any aoqi@0: * @param c The class symbol of the enum aoqi@0: */ aoqi@0: private JCExpression enumBase(int pos, ClassSymbol c) { aoqi@0: JCExpression result = make.at(pos). aoqi@0: TypeApply(make.QualIdent(syms.enumSym), aoqi@0: List.of(make.Type(c.type))); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: Type modelMissingTypes(Type t, final JCExpression tree, final boolean interfaceExpected) { aoqi@0: if (!t.hasTag(ERROR)) aoqi@0: return t; aoqi@0: aoqi@0: return new ErrorType(t.getOriginalType(), t.tsym) { aoqi@0: private Type modelType; aoqi@0: aoqi@0: @Override aoqi@0: public Type getModelType() { aoqi@0: if (modelType == null) aoqi@0: modelType = new Synthesizer(getOriginalType(), interfaceExpected).visit(tree); aoqi@0: return modelType; aoqi@0: } aoqi@0: }; aoqi@0: } aoqi@0: // where aoqi@0: private class Synthesizer extends JCTree.Visitor { aoqi@0: Type originalType; aoqi@0: boolean interfaceExpected; aoqi@0: List synthesizedSymbols = List.nil(); aoqi@0: Type result; aoqi@0: aoqi@0: Synthesizer(Type originalType, boolean interfaceExpected) { aoqi@0: this.originalType = originalType; aoqi@0: this.interfaceExpected = interfaceExpected; aoqi@0: } aoqi@0: aoqi@0: Type visit(JCTree tree) { aoqi@0: tree.accept(this); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: List visit(List trees) { aoqi@0: ListBuffer lb = new ListBuffer(); aoqi@0: for (JCTree t: trees) aoqi@0: lb.append(visit(t)); aoqi@0: return lb.toList(); aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitTree(JCTree tree) { aoqi@0: result = syms.errType; aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitIdent(JCIdent tree) { aoqi@0: if (!tree.type.hasTag(ERROR)) { aoqi@0: result = tree.type; aoqi@0: } else { aoqi@0: result = synthesizeClass(tree.name, syms.unnamedPackage).type; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitSelect(JCFieldAccess tree) { aoqi@0: if (!tree.type.hasTag(ERROR)) { aoqi@0: result = tree.type; aoqi@0: } else { aoqi@0: Type selectedType; aoqi@0: boolean prev = interfaceExpected; aoqi@0: try { aoqi@0: interfaceExpected = false; aoqi@0: selectedType = visit(tree.selected); aoqi@0: } finally { aoqi@0: interfaceExpected = prev; aoqi@0: } aoqi@0: ClassSymbol c = synthesizeClass(tree.name, selectedType.tsym); aoqi@0: result = c.type; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: @Override aoqi@0: public void visitTypeApply(JCTypeApply tree) { aoqi@0: if (!tree.type.hasTag(ERROR)) { aoqi@0: result = tree.type; aoqi@0: } else { aoqi@0: ClassType clazzType = (ClassType) visit(tree.clazz); aoqi@0: if (synthesizedSymbols.contains(clazzType.tsym)) aoqi@0: synthesizeTyparams((ClassSymbol) clazzType.tsym, tree.arguments.size()); aoqi@0: final List actuals = visit(tree.arguments); aoqi@0: result = new ErrorType(tree.type, clazzType.tsym) { aoqi@0: @Override aoqi@0: public List getTypeArguments() { aoqi@0: return actuals; aoqi@0: } aoqi@0: }; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: ClassSymbol synthesizeClass(Name name, Symbol owner) { aoqi@0: int flags = interfaceExpected ? INTERFACE : 0; aoqi@0: ClassSymbol c = new ClassSymbol(flags, name, owner); aoqi@0: c.members_field = new Scope.ErrorScope(c); aoqi@0: c.type = new ErrorType(originalType, c) { aoqi@0: @Override aoqi@0: public List getTypeArguments() { aoqi@0: return typarams_field; aoqi@0: } aoqi@0: }; aoqi@0: synthesizedSymbols = synthesizedSymbols.prepend(c); aoqi@0: return c; aoqi@0: } aoqi@0: aoqi@0: void synthesizeTyparams(ClassSymbol sym, int n) { aoqi@0: ClassType ct = (ClassType) sym.type; aoqi@0: Assert.check(ct.typarams_field.isEmpty()); aoqi@0: if (n == 1) { aoqi@0: TypeVar v = new TypeVar(names.fromString("T"), sym, syms.botType); aoqi@0: ct.typarams_field = ct.typarams_field.prepend(v); aoqi@0: } else { aoqi@0: for (int i = n; i > 0; i--) { aoqi@0: TypeVar v = new TypeVar(names.fromString("T" + i), sym, syms.botType); aoqi@0: ct.typarams_field = ct.typarams_field.prepend(v); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: aoqi@0: /* *************************************************************************** aoqi@0: * tree building aoqi@0: ****************************************************************************/ aoqi@0: aoqi@0: /** Generate default constructor for given class. For classes different aoqi@0: * from java.lang.Object, this is: aoqi@0: * aoqi@0: * c(argtype_0 x_0, ..., argtype_n x_n) throws thrown { aoqi@0: * super(x_0, ..., x_n) aoqi@0: * } aoqi@0: * aoqi@0: * or, if based == true: aoqi@0: * aoqi@0: * c(argtype_0 x_0, ..., argtype_n x_n) throws thrown { aoqi@0: * x_0.super(x_1, ..., x_n) aoqi@0: * } aoqi@0: * aoqi@0: * @param make The tree factory. aoqi@0: * @param c The class owning the default constructor. aoqi@0: * @param argtypes The parameter types of the constructor. aoqi@0: * @param thrown The thrown exceptions of the constructor. aoqi@0: * @param based Is first parameter a this$n? aoqi@0: */ aoqi@0: JCTree DefaultConstructor(TreeMaker make, aoqi@0: ClassSymbol c, aoqi@0: MethodSymbol baseInit, aoqi@0: List typarams, aoqi@0: List argtypes, aoqi@0: List thrown, aoqi@0: long flags, aoqi@0: boolean based) { aoqi@0: JCTree result; aoqi@0: if ((c.flags() & ENUM) != 0 && aoqi@0: (types.supertype(c.type).tsym == syms.enumSym)) { aoqi@0: // constructors of true enums are private aoqi@0: flags = (flags & ~AccessFlags) | PRIVATE | GENERATEDCONSTR; aoqi@0: } else aoqi@0: flags |= (c.flags() & AccessFlags) | GENERATEDCONSTR; aoqi@0: if (c.name.isEmpty()) { aoqi@0: flags |= ANONCONSTR; aoqi@0: } aoqi@0: Type mType = new MethodType(argtypes, null, thrown, c); aoqi@0: Type initType = typarams.nonEmpty() ? aoqi@0: new ForAll(typarams, mType) : aoqi@0: mType; aoqi@0: MethodSymbol init = new MethodSymbol(flags, names.init, aoqi@0: initType, c); aoqi@0: init.params = createDefaultConstructorParams(make, baseInit, init, aoqi@0: argtypes, based); aoqi@0: List params = make.Params(argtypes, init); aoqi@0: List stats = List.nil(); aoqi@0: if (c.type != syms.objectType) { aoqi@0: stats = stats.prepend(SuperCall(make, typarams, params, based)); aoqi@0: } aoqi@0: result = make.MethodDef(init, make.Block(0, stats)); aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: private List createDefaultConstructorParams( aoqi@0: TreeMaker make, aoqi@0: MethodSymbol baseInit, aoqi@0: MethodSymbol init, aoqi@0: List argtypes, aoqi@0: boolean based) { aoqi@0: List initParams = null; aoqi@0: List argTypesList = argtypes; aoqi@0: if (based) { aoqi@0: /* In this case argtypes will have an extra type, compared to baseInit, aoqi@0: * corresponding to the type of the enclosing instance i.e.: aoqi@0: * aoqi@0: * Inner i = outer.new Inner(1){} aoqi@0: * aoqi@0: * in the above example argtypes will be (Outer, int) and baseInit aoqi@0: * will have parameter's types (int). So in this case we have to add aoqi@0: * first the extra type in argtypes and then get the names of the aoqi@0: * parameters from baseInit. aoqi@0: */ aoqi@0: initParams = List.nil(); aoqi@0: VarSymbol param = new VarSymbol(PARAMETER, make.paramName(0), argtypes.head, init); aoqi@0: initParams = initParams.append(param); aoqi@0: argTypesList = argTypesList.tail; aoqi@0: } aoqi@0: if (baseInit != null && baseInit.params != null && aoqi@0: baseInit.params.nonEmpty() && argTypesList.nonEmpty()) { aoqi@0: initParams = (initParams == null) ? List.nil() : initParams; aoqi@0: List baseInitParams = baseInit.params; aoqi@0: while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) { aoqi@0: VarSymbol param = new VarSymbol(baseInitParams.head.flags() | PARAMETER, aoqi@0: baseInitParams.head.name, argTypesList.head, init); aoqi@0: initParams = initParams.append(param); aoqi@0: baseInitParams = baseInitParams.tail; aoqi@0: argTypesList = argTypesList.tail; aoqi@0: } aoqi@0: } aoqi@0: return initParams; aoqi@0: } aoqi@0: aoqi@0: /** Generate call to superclass constructor. This is: aoqi@0: * aoqi@0: * super(id_0, ..., id_n) aoqi@0: * aoqi@0: * or, if based == true aoqi@0: * aoqi@0: * id_0.super(id_1,...,id_n) aoqi@0: * aoqi@0: * where id_0, ..., id_n are the names of the given parameters. aoqi@0: * aoqi@0: * @param make The tree factory aoqi@0: * @param params The parameters that need to be passed to super aoqi@0: * @param typarams The type parameters that need to be passed to super aoqi@0: * @param based Is first parameter a this$n? aoqi@0: */ aoqi@0: JCExpressionStatement SuperCall(TreeMaker make, aoqi@0: List typarams, aoqi@0: List params, aoqi@0: boolean based) { aoqi@0: JCExpression meth; aoqi@0: if (based) { aoqi@0: meth = make.Select(make.Ident(params.head), names._super); aoqi@0: params = params.tail; aoqi@0: } else { aoqi@0: meth = make.Ident(names._super); aoqi@0: } aoqi@0: List typeargs = typarams.nonEmpty() ? make.Types(typarams) : null; aoqi@0: return make.Exec(make.Apply(typeargs, meth, make.Idents(params))); aoqi@0: } aoqi@0: }