MemberEnter.java revision 2800:1b58b3cc63bc
1139825Simp/*
21960Sdg * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
31960Sdg * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41960Sdg *
51960Sdg * This code is free software; you can redistribute it and/or modify it
61960Sdg * under the terms of the GNU General Public License version 2 only, as
71960Sdg * published by the Free Software Foundation.  Oracle designates this
81960Sdg * particular file as subject to the "Classpath" exception as provided
91960Sdg * by Oracle in the LICENSE file that accompanied this code.
101960Sdg *
111960Sdg * This code is distributed in the hope that it will be useful, but WITHOUT
121960Sdg * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131960Sdg * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141960Sdg * version 2 for more details (a copy is included in the LICENSE file that
151960Sdg * accompanied this code).
161960Sdg *
171960Sdg * You should have received a copy of the GNU General Public License version
181960Sdg * 2 along with this work; if not, write to the Free Software Foundation,
191960Sdg * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201960Sdg *
211960Sdg * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221960Sdg * or visit www.oracle.com if you need additional information or have any
231960Sdg * questions.
241960Sdg */
251960Sdg
261960Sdgpackage com.sun.tools.javac.comp;
271960Sdg
281960Sdgimport javax.tools.JavaFileObject;
291960Sdg
301960Sdgimport com.sun.tools.javac.code.*;
311960Sdgimport com.sun.tools.javac.code.Scope.WriteableScope;
321960Sdgimport com.sun.tools.javac.tree.*;
3350477Speterimport com.sun.tools.javac.util.*;
341960Sdgimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
351960Sdg
362165Spaulimport com.sun.tools.javac.code.Symbol.*;
3715493Sbdeimport com.sun.tools.javac.code.Type.*;
382165Spaulimport com.sun.tools.javac.tree.JCTree.*;
3933057Sbde
40177633Sdfrimport static com.sun.tools.javac.code.Flags.*;
41177633Sdfrimport static com.sun.tools.javac.code.Kinds.*;
4233057Sbdeimport static com.sun.tools.javac.code.Kinds.Kind.*;
4333057Sbdeimport static com.sun.tools.javac.code.TypeTag.TYPEVAR;
44177633Sdfr
4533057Sbde/** Resolves field, method and constructor header, and constructs corresponding Symbols.
461960Sdg *
47177633Sdfr *  <p><b>This is NOT part of any supported API.
48177633Sdfr *  If you write code that depends on this, you do so at your own risk.
49177633Sdfr *  This code and its internal interfaces are subject to change or
50177633Sdfr *  deletion without notice.</b>
51177633Sdfr */
52177633Sdfrpublic class MemberEnter extends JCTree.Visitor {
53177633Sdfr    protected static final Context.Key<MemberEnter> memberEnterKey = new Context.Key<>();
54177633Sdfr
55177633Sdfr    /** A switch to determine whether we check for package/class conflicts
56177633Sdfr     */
57177633Sdfr    final static boolean checkClash = true;
58177633Sdfr
59177633Sdfr    private final Enter enter;
60177633Sdfr    private final Log log;
611960Sdg    private final Check chk;
62177633Sdfr    private final Attr attr;
63177633Sdfr    private final Symtab syms;
64177633Sdfr    private final Annotate annotate;
65177633Sdfr    private final Types types;
66177633Sdfr    private final DeferredLintHandler deferredLintHandler;
67177633Sdfr
68177633Sdfr    public static MemberEnter instance(Context context) {
6922521Sdyson        MemberEnter instance = context.get(memberEnterKey);
70177633Sdfr        if (instance == null)
71177633Sdfr            instance = new MemberEnter(context);
72177633Sdfr        return instance;
73177633Sdfr    }
74177633Sdfr
75177633Sdfr    protected MemberEnter(Context context) {
76177633Sdfr        context.put(memberEnterKey, this);
77177633Sdfr        enter = Enter.instance(context);
78177633Sdfr        log = Log.instance(context);
79177633Sdfr        chk = Check.instance(context);
80177633Sdfr        attr = Attr.instance(context);
81177633Sdfr        syms = Symtab.instance(context);
82177633Sdfr        annotate = Annotate.instance(context);
83177633Sdfr        types = Types.instance(context);
84177633Sdfr        deferredLintHandler = DeferredLintHandler.instance(context);
85177633Sdfr    }
86177633Sdfr
87177633Sdfr    /** Construct method type from method signature.
88177633Sdfr     *  @param typarams    The method's type parameters.
89177633Sdfr     *  @param params      The method's value parameters.
90177633Sdfr     *  @param res             The method's result type,
91177633Sdfr     *                 null if it is a constructor.
92177633Sdfr     *  @param recvparam       The method's receiver parameter,
93177633Sdfr     *                 null if none given; TODO: or already set here?
94177633Sdfr     *  @param thrown      The method's thrown exceptions.
95177633Sdfr     *  @param env             The method's (local) environment.
96177633Sdfr     */
97177633Sdfr    Type signature(MethodSymbol msym,
98177633Sdfr                   List<JCTypeParameter> typarams,
99177633Sdfr                   List<JCVariableDecl> params,
100177633Sdfr                   JCTree res,
101177633Sdfr                   JCVariableDecl recvparam,
102177633Sdfr                   List<JCExpression> thrown,
103177633Sdfr                   Env<AttrContext> env) {
104177633Sdfr
105177633Sdfr        // Enter and attribute type parameters.
106177633Sdfr        List<Type> tvars = enter.classEnter(typarams, env);
1071960Sdg        attr.attribTypeVariables(typarams, env);
108177633Sdfr
109177633Sdfr        // Enter and attribute value parameters.
110177633Sdfr        ListBuffer<Type> argbuf = new ListBuffer<>();
111177633Sdfr        for (List<JCVariableDecl> l = params; l.nonEmpty(); l = l.tail) {
112177633Sdfr            memberEnter(l.head, env);
1131960Sdg            argbuf.append(l.head.vartype.type);
114177633Sdfr        }
1151960Sdg
11692719Salfred        // Attribute result type, if one is given.
117177633Sdfr        Type restype = res == null ? syms.voidType : attr.attribType(res, env);
118177633Sdfr
119177633Sdfr        // Attribute receiver type, if one is given.
1201960Sdg        Type recvtype;
12115493Sbde        if (recvparam!=null) {
122            memberEnter(recvparam, env);
123            recvtype = recvparam.vartype.type;
124        } else {
125            recvtype = null;
126        }
127
128        // Attribute thrown exceptions.
129        ListBuffer<Type> thrownbuf = new ListBuffer<>();
130        for (List<JCExpression> l = thrown; l.nonEmpty(); l = l.tail) {
131            Type exc = attr.attribType(l.head, env);
132            if (!exc.hasTag(TYPEVAR)) {
133                exc = chk.checkClassType(l.head.pos(), exc);
134            } else if (exc.tsym.owner == msym) {
135                //mark inference variables in 'throws' clause
136                exc.tsym.flags_field |= THROWS;
137            }
138            thrownbuf.append(exc);
139        }
140        MethodType mtype = new MethodType(argbuf.toList(),
141                                    restype,
142                                    thrownbuf.toList(),
143                                    syms.methodClass);
144        mtype.recvtype = recvtype;
145
146        return tvars.isEmpty() ? mtype : new ForAll(tvars, mtype);
147    }
148
149/* ********************************************************************
150 * Visitor methods for member enter
151 *********************************************************************/
152
153    /** Visitor argument: the current environment
154     */
155    protected Env<AttrContext> env;
156
157    /** Enter field and method definitions and process import
158     *  clauses, catching any completion failure exceptions.
159     */
160    protected void memberEnter(JCTree tree, Env<AttrContext> env) {
161        Env<AttrContext> prevEnv = this.env;
162        try {
163            this.env = env;
164            tree.accept(this);
165        }  catch (CompletionFailure ex) {
166            chk.completionError(tree.pos(), ex);
167        } finally {
168            this.env = prevEnv;
169        }
170    }
171
172    /** Enter members from a list of trees.
173     */
174    void memberEnter(List<? extends JCTree> trees, Env<AttrContext> env) {
175        for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
176            memberEnter(l.head, env);
177    }
178
179    public void visitMethodDef(JCMethodDecl tree) {
180        WriteableScope enclScope = enter.enterScope(env);
181        MethodSymbol m = new MethodSymbol(0, tree.name, null, enclScope.owner);
182        m.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, m, tree);
183        tree.sym = m;
184
185        //if this is a default method, add the DEFAULT flag to the enclosing interface
186        if ((tree.mods.flags & DEFAULT) != 0) {
187            m.enclClass().flags_field |= DEFAULT;
188        }
189
190        Env<AttrContext> localEnv = methodEnv(tree, env);
191        DiagnosticPosition prevLintPos = deferredLintHandler.setPos(tree.pos());
192        try {
193            // Compute the method type
194            m.type = signature(m, tree.typarams, tree.params,
195                               tree.restype, tree.recvparam,
196                               tree.thrown,
197                               localEnv);
198        } finally {
199            deferredLintHandler.setPos(prevLintPos);
200        }
201
202        if (types.isSignaturePolymorphic(m)) {
203            m.flags_field |= SIGNATURE_POLYMORPHIC;
204        }
205
206        // Set m.params
207        ListBuffer<VarSymbol> params = new ListBuffer<>();
208        JCVariableDecl lastParam = null;
209        for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
210            JCVariableDecl param = lastParam = l.head;
211            params.append(Assert.checkNonNull(param.sym));
212        }
213        m.params = params.toList();
214
215        // mark the method varargs, if necessary
216        if (lastParam != null && (lastParam.mods.flags & Flags.VARARGS) != 0)
217            m.flags_field |= Flags.VARARGS;
218
219        localEnv.info.scope.leave();
220        if (chk.checkUnique(tree.pos(), m, enclScope)) {
221        enclScope.enter(m);
222        }
223
224        annotate.annotateLater(tree.mods.annotations, localEnv, m, tree.pos());
225        // Visit the signature of the method. Note that
226        // TypeAnnotate doesn't descend into the body.
227        annotate.annotateTypeLater(tree, localEnv, m, tree.pos());
228
229        if (tree.defaultValue != null)
230            annotateDefaultValueLater(tree.defaultValue, localEnv, m, tree.pos());
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        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.annotateTypeLater(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     */
339    static class InitTreeVisitor extends JCTree.Visitor {
340
341        private boolean result = true;
342
343        @Override
344        public void visitTree(JCTree tree) {}
345
346        @Override
347        public void visitNewClass(JCNewClass that) {
348            result = false;
349        }
350
351        @Override
352        public void visitNewArray(JCNewArray that) {
353            result = false;
354        }
355
356        @Override
357        public void visitLambda(JCLambda that) {
358            result = false;
359        }
360
361        @Override
362        public void visitReference(JCMemberReference that) {
363            result = false;
364        }
365
366        @Override
367        public void visitApply(JCMethodInvocation that) {
368            result = false;
369        }
370
371        @Override
372        public void visitSelect(JCFieldAccess tree) {
373            tree.selected.accept(this);
374        }
375
376        @Override
377        public void visitConditional(JCConditional tree) {
378            tree.cond.accept(this);
379            tree.truepart.accept(this);
380            tree.falsepart.accept(this);
381        }
382
383        @Override
384        public void visitParens(JCParens tree) {
385            tree.expr.accept(this);
386        }
387
388        @Override
389        public void visitTypeCast(JCTypeCast tree) {
390            tree.expr.accept(this);
391        }
392    }
393
394    /** Create a fresh environment for a variable's initializer.
395     *  If the variable is a field, the owner of the environment's scope
396     *  is be the variable itself, otherwise the owner is the method
397     *  enclosing the variable definition.
398     *
399     *  @param tree     The variable definition.
400     *  @param env      The environment current outside of the variable definition.
401     */
402    Env<AttrContext> initEnv(JCVariableDecl tree, Env<AttrContext> env) {
403        Env<AttrContext> localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup()));
404        if (tree.sym.owner.kind == TYP) {
405            localEnv.info.scope = env.info.scope.dupUnshared(tree.sym);
406        }
407        if ((tree.mods.flags & STATIC) != 0 ||
408                ((env.enclClass.sym.flags() & INTERFACE) != 0 && env.enclMethod == null))
409            localEnv.info.staticLevel++;
410        return localEnv;
411    }
412
413    /** Default member enter visitor method: do nothing
414     */
415    public void visitTree(JCTree tree) {
416    }
417
418    public void visitErroneous(JCErroneous tree) {
419        if (tree.errs != null)
420            memberEnter(tree.errs, env);
421    }
422
423    public Env<AttrContext> getMethodEnv(JCMethodDecl tree, Env<AttrContext> env) {
424        Env<AttrContext> mEnv = methodEnv(tree, env);
425        mEnv.info.lint = mEnv.info.lint.augment(tree.sym);
426        for (List<JCTypeParameter> l = tree.typarams; l.nonEmpty(); l = l.tail)
427            mEnv.info.scope.enterIfAbsent(l.head.type.tsym);
428        for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail)
429            mEnv.info.scope.enterIfAbsent(l.head.sym);
430        return mEnv;
431    }
432
433    public Env<AttrContext> getInitEnv(JCVariableDecl tree, Env<AttrContext> env) {
434        Env<AttrContext> iEnv = initEnv(tree, env);
435        return iEnv;
436    }
437
438    /** Queue processing of an attribute default value. */
439    void annotateDefaultValueLater(final JCExpression defaultValue,
440                                   final Env<AttrContext> localEnv,
441                                   final MethodSymbol m,
442                                   final DiagnosticPosition deferPos) {
443        annotate.normal(new Annotate.Worker() {
444                @Override
445                public String toString() {
446                    return "annotate " + m.owner + "." +
447                        m + " default " + defaultValue;
448                }
449
450                @Override
451                public void run() {
452                    JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
453                    DiagnosticPosition prevLintPos = deferredLintHandler.setPos(deferPos);
454                    try {
455                        enterDefaultValue(defaultValue, localEnv, m);
456                    } finally {
457                        deferredLintHandler.setPos(prevLintPos);
458                        log.useSource(prev);
459                    }
460                }
461            });
462        annotate.validate(new Annotate.Worker() { //validate annotations
463            @Override
464            public void run() {
465                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
466                try {
467                    // if default value is an annotation, check it is a well-formed
468                    // annotation value (e.g. no duplicate values, no missing values, etc.)
469                    chk.validateAnnotationTree(defaultValue);
470                } finally {
471                    log.useSource(prev);
472                }
473            }
474        });
475    }
476
477    /** Enter a default value for an attribute method. */
478    private void enterDefaultValue(final JCExpression defaultValue,
479                                   final Env<AttrContext> localEnv,
480                                   final MethodSymbol m) {
481        m.defaultValue = annotate.enterAttributeValue(m.type.getReturnType(),
482                                                      defaultValue,
483                                                      localEnv);
484    }
485
486}
487