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