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