MemberEnter.java revision 4202:2bd34895dda2
1/*
2 * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.comp;
27
28import java.util.EnumSet;
29import java.util.Set;
30
31import com.sun.tools.javac.code.*;
32import com.sun.tools.javac.code.Scope.WriteableScope;
33import com.sun.tools.javac.tree.*;
34import com.sun.tools.javac.util.*;
35import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
36
37import com.sun.tools.javac.code.Symbol.*;
38import com.sun.tools.javac.code.Type.*;
39import com.sun.tools.javac.resources.CompilerProperties.Errors;
40import com.sun.tools.javac.tree.JCTree.*;
41
42import static com.sun.tools.javac.code.Flags.*;
43import static com.sun.tools.javac.code.Kinds.*;
44import static com.sun.tools.javac.code.Kinds.Kind.*;
45import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
46
47/** Resolves field, method and constructor header, and constructs corresponding Symbols.
48 *
49 *  <p><b>This is NOT part of any supported API.
50 *  If you write code that depends on this, you do so at your own risk.
51 *  This code and its internal interfaces are subject to change or
52 *  deletion without notice.</b>
53 */
54public class MemberEnter extends JCTree.Visitor {
55    protected static final Context.Key<MemberEnter> memberEnterKey = new Context.Key<>();
56
57    private final Enter enter;
58    private final Log log;
59    private final Check chk;
60    private final Attr attr;
61    private final Symtab syms;
62    private final Annotate annotate;
63    private final Types types;
64    private final DeferredLintHandler deferredLintHandler;
65
66    public static MemberEnter instance(Context context) {
67        MemberEnter instance = context.get(memberEnterKey);
68        if (instance == null)
69            instance = new MemberEnter(context);
70        return instance;
71    }
72
73    protected MemberEnter(Context context) {
74        context.put(memberEnterKey, this);
75        enter = Enter.instance(context);
76        log = Log.instance(context);
77        chk = Check.instance(context);
78        attr = Attr.instance(context);
79        syms = Symtab.instance(context);
80        annotate = Annotate.instance(context);
81        types = Types.instance(context);
82        deferredLintHandler = DeferredLintHandler.instance(context);
83    }
84
85    /** Construct method type from method signature.
86     *  @param typarams    The method's type parameters.
87     *  @param params      The method's value parameters.
88     *  @param res             The method's result type,
89     *                 null if it is a constructor.
90     *  @param recvparam       The method's receiver parameter,
91     *                 null if none given; TODO: or already set here?
92     *  @param thrown      The method's thrown exceptions.
93     *  @param env             The method's (local) environment.
94     */
95    Type signature(MethodSymbol msym,
96                   List<JCTypeParameter> typarams,
97                   List<JCVariableDecl> params,
98                   JCTree res,
99                   JCVariableDecl recvparam,
100                   List<JCExpression> thrown,
101                   Env<AttrContext> env) {
102
103        // Enter and attribute type parameters.
104        List<Type> tvars = enter.classEnter(typarams, env);
105        attr.attribTypeVariables(typarams, env);
106
107        // Enter and attribute value parameters.
108        ListBuffer<Type> argbuf = new ListBuffer<>();
109        for (List<JCVariableDecl> l = params; l.nonEmpty(); l = l.tail) {
110            memberEnter(l.head, env);
111            argbuf.append(l.head.vartype.type);
112        }
113
114        // Attribute result type, if one is given.
115        Type restype = res == null ? syms.voidType : attr.attribType(res, env);
116
117        // Attribute receiver type, if one is given.
118        Type recvtype;
119        if (recvparam!=null) {
120            memberEnter(recvparam, env);
121            recvtype = recvparam.vartype.type;
122        } else {
123            recvtype = null;
124        }
125
126        // Attribute thrown exceptions.
127        ListBuffer<Type> thrownbuf = new ListBuffer<>();
128        for (List<JCExpression> l = thrown; l.nonEmpty(); l = l.tail) {
129            Type exc = attr.attribType(l.head, env);
130            if (!exc.hasTag(TYPEVAR)) {
131                exc = chk.checkClassType(l.head.pos(), exc);
132            } else if (exc.tsym.owner == msym) {
133                //mark inference variables in 'throws' clause
134                exc.tsym.flags_field |= THROWS;
135            }
136            thrownbuf.append(exc);
137        }
138        MethodType mtype = new MethodType(argbuf.toList(),
139                                    restype,
140                                    thrownbuf.toList(),
141                                    syms.methodClass);
142        mtype.recvtype = recvtype;
143
144        return tvars.isEmpty() ? mtype : new ForAll(tvars, mtype);
145    }
146
147/* ********************************************************************
148 * Visitor methods for member enter
149 *********************************************************************/
150
151    /** Visitor argument: the current environment
152     */
153    protected Env<AttrContext> env;
154
155    /** Enter field and method definitions and process import
156     *  clauses, catching any completion failure exceptions.
157     */
158    protected void memberEnter(JCTree tree, Env<AttrContext> env) {
159        Env<AttrContext> prevEnv = this.env;
160        try {
161            this.env = env;
162            tree.accept(this);
163        }  catch (CompletionFailure ex) {
164            chk.completionError(tree.pos(), ex);
165        } finally {
166            this.env = prevEnv;
167        }
168    }
169
170    /** Enter members from a list of trees.
171     */
172    void memberEnter(List<? extends JCTree> trees, Env<AttrContext> env) {
173        for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
174            memberEnter(l.head, env);
175    }
176
177    public void visitMethodDef(JCMethodDecl tree) {
178        WriteableScope enclScope = enter.enterScope(env);
179        MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
180        m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
181        tree.sym = m;
182
183        //if this is a default method, add the DEFAULT flag to the enclosing interface
184        if ((tree.mods.flags & DEFAULT) != 0) {
185            m.enclClass().flags_field |= DEFAULT;
186        }
187
188        Env<AttrContext> localEnv = methodEnv(tree, env);
189        DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
190        try {
191            // Compute the method type
192            m.type = signature(m, tree.typarams, tree.params,
193                               tree.restype, tree.recvparam,
194                               tree.thrown,
195                               localEnv);
196        } finally {
197            deferredLintHandler.setPos(prevLintPos);
198        }
199
200        if (types.isSignaturePolymorphic(m)) {
201            m.flags_field |= SIGNATURE_POLYMORPHIC;
202        }
203
204        // Set m.params
205        ListBuffer<VarSymbol> params = new ListBuffer<>();
206        JCVariableDecl lastParam = null;
207        for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
208            JCVariableDecl param = lastParam = l.head;
209            params.append(Assert.checkNonNull(param.sym));
210        }
211        m.params = params.toList();
212
213        // mark the method varargs, if necessary
214        if (lastParam != null && (lastParam.mods.flags & Flags.VARARGS) != 0)
215            m.flags_field |= Flags.VARARGS;
216
217        localEnv.info.scope.leave();
218        if (chk.checkUnique(tree.pos(), m, enclScope)) {
219        enclScope.enter(m);
220        }
221
222        annotate.annotateLater(tree.mods.annotations, localEnv, m, tree.pos());
223        // Visit the signature of the method. Note that
224        // TypeAnnotate doesn't descend into the body.
225        annotate.queueScanTreeAndTypeAnnotate(tree, localEnv, m, tree.pos());
226
227        if (tree.defaultValue != null) {
228            m.defaultValue = annotate.unfinishedDefaultValue(); // set it to temporary sentinel for now
229            annotate.annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree.pos());
230        }
231    }
232
233    /** Create a fresh environment for method bodies.
234     *  @param tree     The method definition.
235     *  @param env      The environment current outside of the method definition.
236     */
237    Env<AttrContext> methodEnv(JCMethodDecl tree, Env<AttrContext> env) {
238        Env<AttrContext> localEnv =
239            env.dup(tree, env.info.dup(env.info.scope.dupUnshared(tree.sym)));
240        localEnv.enclMethod = tree;
241        if (tree.sym.type != null) {
242            //when this is called in the enter stage, there's no type to be set
243            localEnv.info.returnResult = attr.new ResultInfo(KindSelector.VAL,
244                                                             tree.sym.type.getReturnType());
245        }
246        if ((tree.mods.flags & STATIC) != 0) localEnv.info.staticLevel++;
247        return localEnv;
248    }
249
250    public void visitVarDef(JCVariableDecl tree) {
251        Env<AttrContext> localEnv = env;
252        if ((tree.mods.flags & STATIC) != 0 ||
253            (env.info.scope.owner.flags() & INTERFACE) != 0) {
254            localEnv = env.dup(tree, env.info.dup());
255            localEnv.info.staticLevel++;
256        }
257        DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
258
259        try {
260            if (TreeInfo.isEnumInit(tree)) {
261                attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
262            } else {
263                attr.attribType(tree.vartype, localEnv);
264                if (TreeInfo.isReceiverParam(tree))
265                    checkReceiver(tree, localEnv);
266            }
267        } finally {
268            deferredLintHandler.setPos(prevLintPos);
269        }
270
271        if ((tree.mods.flags & VARARGS) != 0) {
272            //if we are entering a varargs parameter, we need to
273            //replace its type (a plain array type) with the more
274            //precise VarargsType --- we need to do it this way
275            //because varargs is represented in the tree as a
276            //modifier on the parameter declaration, and not as a
277            //distinct type of array node.
278            ArrayType atype = (ArrayType)tree.vartype.type;
279            tree.vartype.type = atype.makeVarargs();
280        }
281        WriteableScope enclScope = enter.enterScope(env);
282        VarSymbol v =
283            new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
284        v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
285        tree.sym = v;
286        if (tree.init != null) {
287            v.flags_field |= HASINIT;
288            if ((v.flags_field & FINAL) != 0 &&
289                needsLazyConstValue(tree.init)) {
290                Env<AttrContext> initEnv = getInitEnv(tree, env);
291                initEnv.info.enclVar = v;
292                v.setLazyConstValue(initEnv(tree, initEnv), attr, tree);
293            }
294        }
295        if (chk.checkUnique(tree.pos(), v, enclScope)) {
296            chk.checkTransparentVar(tree.pos(), v, enclScope);
297            enclScope.enter(v);
298        }
299
300        annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
301        annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
302
303        v.pos = tree.pos;
304    }
305    // where
306    void checkType(JCTree tree, Type type, String diag) {
307        if (!tree.type.isErroneous() && !types.isSameType(tree.type, type)) {
308            log.error(tree, diag, type, tree.type);
309        }
310    }
311    void checkReceiver(JCVariableDecl tree, Env<AttrContext> localEnv) {
312        attr.attribExpr(tree.nameexpr, localEnv);
313        MethodSymbol m = localEnv.enclMethod.sym;
314        if (m.isConstructor()) {
315            Type outertype = m.owner.owner.type;
316            if (outertype.hasTag(TypeTag.METHOD)) {
317                // we have a local inner class
318                outertype = m.owner.owner.owner.type;
319            }
320            if (outertype.hasTag(TypeTag.CLASS)) {
321                checkType(tree.vartype, outertype, "incorrect.constructor.receiver.type");
322                checkType(tree.nameexpr, outertype, "incorrect.constructor.receiver.name");
323            } else {
324                log.error(tree, Errors.ReceiverParameterNotApplicableConstructorToplevelClass);
325            }
326        } else {
327            checkType(tree.vartype, m.owner.type, "incorrect.receiver.type");
328            checkType(tree.nameexpr, m.owner.type, "incorrect.receiver.name");
329        }
330    }
331
332    public boolean needsLazyConstValue(JCTree tree) {
333        InitTreeVisitor initTreeVisitor = new InitTreeVisitor();
334        tree.accept(initTreeVisitor);
335        return initTreeVisitor.result;
336    }
337
338    /** Visitor class for expressions which might be constant expressions,
339     *  as per JLS 15.28 (Constant Expressions).
340     */
341    static class InitTreeVisitor extends JCTree.Visitor {
342
343        private static final Set<Tag> ALLOWED_OPERATORS =
344                EnumSet.of(Tag.POS, Tag.NEG, Tag.NOT, Tag.COMPL, Tag.PLUS, Tag.MINUS,
345                           Tag.MUL, Tag.DIV, Tag.MOD, Tag.SL, Tag.SR, Tag.USR,
346                           Tag.LT, Tag.LE, Tag.GT, Tag.GE, Tag.EQ, Tag.NE,
347                           Tag.BITAND, Tag.BITXOR, Tag.BITOR, Tag.AND, Tag.OR);
348
349        boolean result = true;
350
351        @Override
352        public void visitTree(JCTree tree) {
353            result = false;
354        }
355
356        @Override
357        public void visitLiteral(JCLiteral that) {}
358
359        @Override
360        public void visitTypeCast(JCTypeCast tree) {
361            tree.expr.accept(this);
362        }
363
364        @Override
365        public void visitUnary(JCUnary that) {
366            if (!ALLOWED_OPERATORS.contains(that.getTag())) {
367                result = false;
368                return ;
369            }
370            that.arg.accept(this);
371        }
372
373        @Override
374        public void visitBinary(JCBinary that) {
375            if (!ALLOWED_OPERATORS.contains(that.getTag())) {
376                result = false;
377                return ;
378            }
379            that.lhs.accept(this);
380            that.rhs.accept(this);
381        }
382
383        @Override
384        public void visitConditional(JCConditional tree) {
385            tree.cond.accept(this);
386            tree.truepart.accept(this);
387            tree.falsepart.accept(this);
388        }
389
390        @Override
391        public void visitParens(JCParens tree) {
392            tree.expr.accept(this);
393        }
394
395        @Override
396        public void visitIdent(JCIdent that) {}
397
398        @Override
399        public void visitSelect(JCFieldAccess tree) {
400            tree.selected.accept(this);
401        }
402    }
403
404    /** Create a fresh environment for a variable's initializer.
405     *  If the variable is a field, the owner of the environment's scope
406     *  is be the variable itself, otherwise the owner is the method
407     *  enclosing the variable definition.
408     *
409     *  @param tree     The variable definition.
410     *  @param env      The environment current outside of the variable definition.
411     */
412    Env<AttrContext> initEnv(JCVariableDecl tree, Env<AttrContext> env) {
413        Env<AttrContext> localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup()));
414        if (tree.sym.owner.kind == TYP) {
415            localEnv.info.scope = env.info.scope.dupUnshared(tree.sym);
416        }
417        if ((tree.mods.flags & STATIC) != 0 ||
418                ((env.enclClass.sym.flags() & INTERFACE) != 0 && env.enclMethod == null))
419            localEnv.info.staticLevel++;
420        return localEnv;
421    }
422
423    /** Default member enter visitor method: do nothing
424     */
425    public void visitTree(JCTree tree) {
426    }
427
428    public void visitErroneous(JCErroneous tree) {
429        if (tree.errs != null)
430            memberEnter(tree.errs, env);
431    }
432
433    public Env<AttrContext> getMethodEnv(JCMethodDecl tree, Env<AttrContext> env) {
434        Env<AttrContext> mEnv = methodEnv(tree, env);
435        mEnv.info.lint = mEnv.info.lint.augment(tree.sym);
436        for (List<JCTypeParameter> l = tree.typarams; l.nonEmpty(); l = l.tail)
437            mEnv.info.scope.enterIfAbsent(l.head.type.tsym);
438        for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail)
439            mEnv.info.scope.enterIfAbsent(l.head.sym);
440        return mEnv;
441    }
442
443    public Env<AttrContext> getInitEnv(JCVariableDecl tree, Env<AttrContext> env) {
444        Env<AttrContext> iEnv = initEnv(tree, env);
445        return iEnv;
446    }
447}
448