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