--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.comp;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.tree.*;
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Type.*;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.tree.JCTree.*;
+
+import static com.sun.tools.javac.code.Flags.*;
+import static com.sun.tools.javac.code.Kinds.*;
+import static com.sun.tools.javac.code.Kinds.Kind.*;
+import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
+
+/** Resolves field, method and constructor header, and constructs corresponding Symbols.
+ *
+ * <p><b>This is NOT part of any supported API.
+ * If you write code that depends on this, you do so at your own risk.
+ * This code and its internal interfaces are subject to change or
+ * deletion without notice.</b>
+ */
+public class MemberEnter extends JCTree.Visitor {
+ protected static final Context.Key<MemberEnter> memberEnterKey = new Context.Key<>();
+
+ private final Enter enter;
+ private final Log log;
+ private final Check chk;
+ private final Attr attr;
+ private final Symtab syms;
+ private final Annotate annotate;
+ private final Types types;
+ private final DeferredLintHandler deferredLintHandler;
+
+ public static MemberEnter instance(Context context) {
+ MemberEnter instance = context.get(memberEnterKey);
+ if (instance == null)
+ instance = new MemberEnter(context);
+ return instance;
+ }
+
+ protected MemberEnter(Context context) {
+ context.put(memberEnterKey, this);
+ enter = Enter.instance(context);
+ log = Log.instance(context);
+ chk = Check.instance(context);
+ attr = Attr.instance(context);
+ syms = Symtab.instance(context);
+ annotate = Annotate.instance(context);
+ types = Types.instance(context);
+ deferredLintHandler = DeferredLintHandler.instance(context);
+ }
+
+ /** Construct method type from method signature.
+ * @param typarams The method's type parameters.
+ * @param params The method's value parameters.
+ * @param res The method's result type,
+ * null if it is a constructor.
+ * @param recvparam The method's receiver parameter,
+ * null if none given; TODO: or already set here?
+ * @param thrown The method's thrown exceptions.
+ * @param env The method's (local) environment.
+ */
+ Type signature(MethodSymbol msym,
+ List<JCTypeParameter> typarams,
+ List<JCVariableDecl> params,
+ JCTree res,
+ JCVariableDecl recvparam,
+ List<JCExpression> thrown,
+ Env<AttrContext> env) {
+
+ // Enter and attribute type parameters.
+ List<Type> tvars = enter.classEnter(typarams, env);
+ attr.attribTypeVariables(typarams, env);
+
+ // Enter and attribute value parameters.
+ ListBuffer<Type> argbuf = new ListBuffer<>();
+ for (List<JCVariableDecl> l = params; l.nonEmpty(); l = l.tail) {
+ memberEnter(l.head, env);
+ argbuf.append(l.head.vartype.type);
+ }
+
+ // Attribute result type, if one is given.
+ Type restype = res == null ? syms.voidType : attr.attribType(res, env);
+
+ // Attribute receiver type, if one is given.
+ Type recvtype;
+ if (recvparam!=null) {
+ memberEnter(recvparam, env);
+ recvtype = recvparam.vartype.type;
+ } else {
+ recvtype = null;
+ }
+
+ // Attribute thrown exceptions.
+ ListBuffer<Type> thrownbuf = new ListBuffer<>();
+ for (List<JCExpression> l = thrown; l.nonEmpty(); l = l.tail) {
+ Type exc = attr.attribType(l.head, env);
+ if (!exc.hasTag(TYPEVAR)) {
+ exc = chk.checkClassType(l.head.pos(), exc);
+ } else if (exc.tsym.owner == msym) {
+ //mark inference variables in 'throws' clause
+ exc.tsym.flags_field |= THROWS;
+ }
+ thrownbuf.append(exc);
+ }
+ MethodType mtype = new MethodType(argbuf.toList(),
+ restype,
+ thrownbuf.toList(),
+ syms.methodClass);
+ mtype.recvtype = recvtype;
+
+ return tvars.isEmpty() ? mtype : new ForAll(tvars, mtype);
+ }
+
+/* ********************************************************************
+ * Visitor methods for member enter
+ *********************************************************************/
+
+ /** Visitor argument: the current environment
+ */
+ protected Env<AttrContext> env;
+
+ /** Enter field and method definitions and process import
+ * clauses, catching any completion failure exceptions.
+ */
+ protected void memberEnter(JCTree tree, Env<AttrContext> env) {
+ Env<AttrContext> prevEnv = this.env;
+ try {
+ this.env = env;
+ tree.accept(this);
+ } catch (CompletionFailure ex) {
+ chk.completionError(tree.pos(), ex);
+ } finally {
+ this.env = prevEnv;
+ }
+ }
+
+ /** Enter members from a list of trees.
+ */
+ void memberEnter(List<? extends JCTree> trees, Env<AttrContext> env) {
+ for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
+ memberEnter(l.head, env);
+ }
+
+ public void visitMethodDef(JCMethodDecl tree) {
+ WriteableScope enclScope = enter.enterScope(env);
+ MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
+ m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
+ tree.sym = m;
+
+ //if this is a default method, add the DEFAULT flag to the enclosing interface
+ if ((tree.mods.flags & DEFAULT) != 0) {
+ m.enclClass().flags_field |= DEFAULT;
+ }
+
+ Env<AttrContext> localEnv = methodEnv(tree, env);
+ DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
+ try {
+ // Compute the method type
+ m.type = signature(m, tree.typarams, tree.params,
+ tree.restype, tree.recvparam,
+ tree.thrown,
+ localEnv);
+ } finally {
+ deferredLintHandler.setPos(prevLintPos);
+ }
+
+ if (types.isSignaturePolymorphic(m)) {
+ m.flags_field |= SIGNATURE_POLYMORPHIC;
+ }
+
+ // Set m.params
+ ListBuffer<VarSymbol> params = new ListBuffer<>();
+ JCVariableDecl lastParam = null;
+ for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
+ JCVariableDecl param = lastParam = l.head;
+ params.append(Assert.checkNonNull(param.sym));
+ }
+ m.params = params.toList();
+
+ // mark the method varargs, if necessary
+ if (lastParam != null && (lastParam.mods.flags & Flags.VARARGS) != 0)
+ m.flags_field |= Flags.VARARGS;
+
+ localEnv.info.scope.leave();
+ if (chk.checkUnique(tree.pos(), m, enclScope)) {
+ enclScope.enter(m);
+ }
+
+ annotate.annotateLater(tree.mods.annotations, localEnv, m, tree.pos());
+ // Visit the signature of the method. Note that
+ // TypeAnnotate doesn't descend into the body.
+ annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m, tree.pos());
+
+ if (tree.defaultValue != null) {
+ m.defaultValue = annotate.unfinishedDefaultValue(); // set it to temporary sentinel for now
+ annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree.pos());
+ }
+ }
+
+ /** Create a fresh environment for method bodies.
+ * @param tree The method definition.
+ * @param env The environment current outside of the method definition.
+ */
+ Env<AttrContext> methodEnv(JCMethodDecl tree, Env<AttrContext> env) {
+ Env<AttrContext> localEnv =
+ env.dup(tree, env.info.dup(env.info.scope.dupUnshared(tree.sym)));
+ localEnv.enclMethod = tree;
+ if (tree.sym.type != null) {
+ //when this is called in the enter stage, there's no type to be set
+ localEnv.info.returnResult = attr.new ResultInfo(KindSelector.VAL,
+ tree.sym.type.getReturnType());
+ }
+ if ((tree.mods.flags & STATIC) != 0) localEnv.info.staticLevel++;
+ return localEnv;
+ }
+
+ public void visitVarDef(JCVariableDecl tree) {
+ Env<AttrContext> localEnv = env;
+ if ((tree.mods.flags & STATIC) != 0 ||
+ (env.info.scope.owner.flags() & INTERFACE) != 0) {
+ localEnv = env.dup(tree, env.info.dup());
+ localEnv.info.staticLevel++;
+ }
+ DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
+
+ try {
+ if (TreeInfo.isEnumInit(tree)) {
+ attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
+ } else {
+ attr.attribType(tree.vartype, localEnv);
+ if (TreeInfo.isReceiverParam(tree))
+ checkReceiver(tree, localEnv);
+ }
+ } finally {
+ deferredLintHandler.setPos(prevLintPos);
+ }
+
+ if ((tree.mods.flags & VARARGS) != 0) {
+ //if we are entering a varargs parameter, we need to
+ //replace its type (a plain array type) with the more
+ //precise VarargsType --- we need to do it this way
+ //because varargs is represented in the tree as a
+ //modifier on the parameter declaration, and not as a
+ //distinct type of array node.
+ ArrayType atype = (ArrayType)tree.vartype.type;
+ tree.vartype.type = atype.makeVarargs();
+ }
+ WriteableScope enclScope = enter.enterScope(env);
+ VarSymbol v =
+ new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
+ v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
+ tree.sym = v;
+ if (tree.init != null) {
+ v.flags_field |= HASINIT;
+ if ((v.flags_field & FINAL) != 0 &&
+ needsLazyConstValue(tree.init)) {
+ Env<AttrContext> initEnv = getInitEnv(tree, env);
+ initEnv.info.enclVar = v;
+ v.setLazyConstValue(initEnv(tree, initEnv), attr, tree);
+ }
+ }
+ if (chk.checkUnique(tree.pos(), v, enclScope)) {
+ chk.checkTransparentVar(tree.pos(), v, enclScope);
+ enclScope.enter(v);
+ }
+
+ annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
+ annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
+
+ v.pos = tree.pos;
+ }
+ // where
+ void checkType(JCTree tree, Type type, String diag) {
+ if (!tree.type.isErroneous() && !types.isSameType(tree.type, type)) {
+ log.error(tree, diag, type, tree.type);
+ }
+ }
+ void checkReceiver(JCVariableDecl tree, Env<AttrContext> localEnv) {
+ attr.attribExpr(tree.nameexpr, localEnv);
+ MethodSymbol m = localEnv.enclMethod.sym;
+ if (m.isConstructor()) {
+ Type outertype = m.owner.owner.type;
+ if (outertype.hasTag(TypeTag.METHOD)) {
+ // we have a local inner class
+ outertype = m.owner.owner.owner.type;
+ }
+ if (outertype.hasTag(TypeTag.CLASS)) {
+ checkType(tree.vartype, outertype, "incorrect.constructor.receiver.type");
+ checkType(tree.nameexpr, outertype, "incorrect.constructor.receiver.name");
+ } else {
+ log.error(tree, Errors.ReceiverParameterNotApplicableConstructorToplevelClass);
+ }
+ } else {
+ checkType(tree.vartype, m.owner.type, "incorrect.receiver.type");
+ checkType(tree.nameexpr, m.owner.type, "incorrect.receiver.name");
+ }
+ }
+
+ public boolean needsLazyConstValue(JCTree tree) {
+ InitTreeVisitor initTreeVisitor = new InitTreeVisitor();
+ tree.accept(initTreeVisitor);
+ return initTreeVisitor.result;
+ }
+
+ /** Visitor class for expressions which might be constant expressions,
+ * as per JLS 15.28 (Constant Expressions).
+ */
+ static class InitTreeVisitor extends JCTree.Visitor {
+
+ private static final Set<Tag> ALLOWED_OPERATORS =
+ EnumSet.of(Tag.POS, Tag.NEG, Tag.NOT, Tag.COMPL, Tag.PLUS, Tag.MINUS,
+ Tag.MUL, Tag.DIV, Tag.MOD, Tag.SL, Tag.SR, Tag.USR,
+ Tag.LT, Tag.LE, Tag.GT, Tag.GE, Tag.EQ, Tag.NE,
+ Tag.BITAND, Tag.BITXOR, Tag.BITOR, Tag.AND, Tag.OR);
+
+ boolean result = true;
+
+ @Override
+ public void visitTree(JCTree tree) {
+ result = false;
+ }
+
+ @Override
+ public void visitLiteral(JCLiteral that) {}
+
+ @Override
+ public void visitTypeCast(JCTypeCast tree) {
+ tree.expr.accept(this);
+ }
+
+ @Override
+ public void visitUnary(JCUnary that) {
+ if (!ALLOWED_OPERATORS.contains(that.getTag())) {
+ result = false;
+ return ;
+ }
+ that.arg.accept(this);
+ }
+
+ @Override
+ public void visitBinary(JCBinary that) {
+ if (!ALLOWED_OPERATORS.contains(that.getTag())) {
+ result = false;
+ return ;
+ }
+ that.lhs.accept(this);
+ that.rhs.accept(this);
+ }
+
+ @Override
+ public void visitConditional(JCConditional tree) {
+ tree.cond.accept(this);
+ tree.truepart.accept(this);
+ tree.falsepart.accept(this);
+ }
+
+ @Override
+ public void visitParens(JCParens tree) {
+ tree.expr.accept(this);
+ }
+
+ @Override
+ public void visitIdent(JCIdent that) {}
+
+ @Override
+ public void visitSelect(JCFieldAccess tree) {
+ tree.selected.accept(this);
+ }
+ }
+
+ /** Create a fresh environment for a variable's initializer.
+ * If the variable is a field, the owner of the environment's scope
+ * is be the variable itself, otherwise the owner is the method
+ * enclosing the variable definition.
+ *
+ * @param tree The variable definition.
+ * @param env The environment current outside of the variable definition.
+ */
+ Env<AttrContext> initEnv(JCVariableDecl tree, Env<AttrContext> env) {
+ Env<AttrContext> localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup()));
+ if (tree.sym.owner.kind == TYP) {
+ localEnv.info.scope = env.info.scope.dupUnshared(tree.sym);
+ }
+ if ((tree.mods.flags & STATIC) != 0 ||
+ ((env.enclClass.sym.flags() & INTERFACE) != 0 && env.enclMethod == null))
+ localEnv.info.staticLevel++;
+ return localEnv;
+ }
+
+ /** Default member enter visitor method: do nothing
+ */
+ public void visitTree(JCTree tree) {
+ }
+
+ public void visitErroneous(JCErroneous tree) {
+ if (tree.errs != null)
+ memberEnter(tree.errs, env);
+ }
+
+ public Env<AttrContext> getMethodEnv(JCMethodDecl tree, Env<AttrContext> env) {
+ Env<AttrContext> mEnv = methodEnv(tree, env);
+ mEnv.info.lint = mEnv.info.lint.augment(tree.sym);
+ for (List<JCTypeParameter> l = tree.typarams; l.nonEmpty(); l = l.tail)
+ mEnv.info.scope.enterIfAbsent(l.head.type.tsym);
+ for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail)
+ mEnv.info.scope.enterIfAbsent(l.head.sym);
+ return mEnv;
+ }
+
+ public Env<AttrContext> getInitEnv(JCVariableDecl tree, Env<AttrContext> env) {
+ Env<AttrContext> iEnv = initEnv(tree, env);
+ return iEnv;
+ }
+}