MemberEnter.java revision 2739:9d2192f36e53
1/*
2 * Copyright (c) 2003, 2014, 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 javax.tools.JavaFileObject;
29
30import com.sun.tools.javac.code.*;
31import com.sun.tools.javac.code.Scope.WriteableScope;
32import com.sun.tools.javac.tree.*;
33import com.sun.tools.javac.util.*;
34import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
35
36import com.sun.tools.javac.code.Symbol.*;
37import com.sun.tools.javac.code.Type.*;
38import com.sun.tools.javac.tree.JCTree.*;
39
40import static com.sun.tools.javac.code.Flags.*;
41import static com.sun.tools.javac.code.Kinds.*;
42import static com.sun.tools.javac.code.Kinds.Kind.*;
43import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
44
45/** Resolves field, method and constructor header, and constructs corresponding Symbols.
46 *
47 *  <p><b>This is NOT part of any supported API.
48 *  If you write code that depends on this, you do so at your own risk.
49 *  This code and its internal interfaces are subject to change or
50 *  deletion without notice.</b>
51 */
52public class MemberEnter extends JCTree.Visitor {
53    protected static final Context.Key<MemberEnter> memberEnterKey = new Context.Key<>();
54
55    /** A switch to determine whether we check for package/class conflicts
56     */
57    final static boolean checkClash = true;
58
59    private final Enter enter;
60    private final Log log;
61    private final Check chk;
62    private final Attr attr;
63    private final Symtab syms;
64    private final Annotate annotate;
65    private final Types types;
66    private final DeferredLintHandler deferredLintHandler;
67
68    public static MemberEnter instance(Context context) {
69        MemberEnter instance = context.get(memberEnterKey);
70        if (instance == null)
71            instance = new MemberEnter(context);
72        return instance;
73    }
74
75    protected MemberEnter(Context context) {
76        context.put(memberEnterKey, this);
77        enter = Enter.instance(context);
78        log = Log.instance(context);
79        chk = Check.instance(context);
80        attr = Attr.instance(context);
81        syms = Symtab.instance(context);
82        annotate = Annotate.instance(context);
83        types = Types.instance(context);
84        deferredLintHandler = DeferredLintHandler.instance(context);
85    }
86
87    /** Construct method type from method signature.
88     *  @param typarams    The method's type parameters.
89     *  @param params      The method's value parameters.
90     *  @param res             The method's result type,
91     *                 null if it is a constructor.
92     *  @param recvparam       The method's receiver parameter,
93     *                 null if none given; TODO: or already set here?
94     *  @param thrown      The method's thrown exceptions.
95     *  @param env             The method's (local) environment.
96     */
97    Type signature(MethodSymbol msym,
98                   List<JCTypeParameter> typarams,
99                   List<JCVariableDecl> params,
100                   JCTree res,
101                   JCVariableDecl recvparam,
102                   List<JCExpression> thrown,
103                   Env<AttrContext> env) {
104
105        // Enter and attribute type parameters.
106        List<Type> tvars = enter.classEnter(typarams, env);
107        attr.attribTypeVariables(typarams, env);
108
109        // Enter and attribute value parameters.
110        ListBuffer<Type> argbuf = new ListBuffer<>();
111        for (List<JCVariableDecl> l = params; l.nonEmpty(); l = l.tail) {
112            memberEnter(l.head, env);
113            argbuf.append(l.head.vartype.type);
114        }
115
116        // Attribute result type, if one is given.
117        Type restype = res == null ? syms.voidType : attr.attribType(res, env);
118
119        // Attribute receiver type, if one is given.
120        Type recvtype;
121        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);
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        annotate.normal(new Annotate.Worker() {
443                @Override
444                public String toString() {
445                    return "annotate " + m.owner + "." +
446                        m + " default " + defaultValue;
447                }
448
449                @Override
450                public void run() {
451                    JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
452                    try {
453                        enterDefaultValue(defaultValue, localEnv, m);
454                    } finally {
455                        log.useSource(prev);
456                    }
457                }
458            });
459        annotate.validate(new Annotate.Worker() { //validate annotations
460            @Override
461            public void run() {
462                JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
463                try {
464                    // if default value is an annotation, check it is a well-formed
465                    // annotation value (e.g. no duplicate values, no missing values, etc.)
466                    chk.validateAnnotationTree(defaultValue);
467                } finally {
468                    log.useSource(prev);
469                }
470            }
471        });
472    }
473
474    /** Enter a default value for an attribute method. */
475    private void enterDefaultValue(final JCExpression defaultValue,
476                                   final Env<AttrContext> localEnv,
477                                   final MethodSymbol m) {
478        m.defaultValue = annotate.enterAttributeValue(m.type.getReturnType(),
479                                                      defaultValue,
480                                                      localEnv);
481    }
482
483}
484