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         if (tree.init != null) {
 291             v.flags_field |= HASINIT;
 292             if ((v.flags_field & FINAL) != 0 &&
 293                 needsLazyConstValue(tree.init)) {
 294                 Env<AttrContext> initEnv = getInitEnv(tree, env);
 295                 initEnv.info.enclVar = v;
 296                 v.setLazyConstValue(initEnv(tree, initEnv), attr, tree);
 297             }
 298         }
 299         if (chk.checkUnique(tree.pos(), v, enclScope)) {
 300             chk.checkTransparentVar(tree.pos(), v, enclScope);
 301             enclScope.enter(v);
 302         }
 303 
 304         annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
 305         if (!tree.isImplicitlyTyped()) {
 306             annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
 307         }
 308 
 309         v.pos = tree.pos;
 310     }
 311     // where
 312     void checkType(JCTree tree, Type type, Error errorKey) {
 313         if (!tree.type.isErroneous() && !types.isSameType(tree.type, type)) {
 314             log.error(tree, errorKey);
 315         }
 316     }
 317     void checkReceiver(JCVariableDecl tree, Env<AttrContext> localEnv) {
 318         attr.attribExpr(tree.nameexpr, localEnv);
 319         MethodSymbol m = localEnv.enclMethod.sym;
 320         if (m.isConstructor()) {
 321             Type outertype = m.owner.owner.type;
 322             if (outertype.hasTag(TypeTag.METHOD)) {
 323                 // we have a local inner class
 324                 outertype = m.owner.owner.owner.type;
 325             }
 326             if (outertype.hasTag(TypeTag.CLASS)) {
 327                 checkType(tree.vartype, outertype, Errors.IncorrectConstructorReceiverType(outertype, tree.vartype.type));
 328                 checkType(tree.nameexpr, outertype, Errors.IncorrectConstructorReceiverName(outertype, tree.nameexpr.type));
 329             } else {
 330                 log.error(tree, Errors.ReceiverParameterNotApplicableConstructorToplevelClass);
 331             }
 332         } else {
 333             checkType(tree.vartype, m.owner.type, Errors.IncorrectReceiverType(m.owner.type, tree.vartype.type));
 334             checkType(tree.nameexpr, m.owner.type, Errors.IncorrectReceiverName(m.owner.type, tree.nameexpr.type));
 335         }
 336     }
 337 
 338     public boolean needsLazyConstValue(JCTree tree) {
 339         InitTreeVisitor initTreeVisitor = new InitTreeVisitor();
 340         tree.accept(initTreeVisitor);
 341         return initTreeVisitor.result;
 342     }
 343 
 344     /** Visitor class for expressions which might be constant expressions,
 345      *  as per JLS 15.28 (Constant Expressions).
 346      */
 347     static class InitTreeVisitor extends JCTree.Visitor {
 348 
 349         private static final Set<Tag> ALLOWED_OPERATORS =
 350                 EnumSet.of(Tag.POS, Tag.NEG, Tag.NOT, Tag.COMPL, Tag.PLUS, Tag.MINUS,
 351                            Tag.MUL, Tag.DIV, Tag.MOD, Tag.SL, Tag.SR, Tag.USR,
 352                            Tag.LT, Tag.LE, Tag.GT, Tag.GE, Tag.EQ, Tag.NE,
 353                            Tag.BITAND, Tag.BITXOR, Tag.BITOR, Tag.AND, Tag.OR);
 354 
 355         boolean result = true;
 356 
 357         @Override
 358         public void visitTree(JCTree tree) {
 359             result = false;
 360         }
 361 
 362         @Override
 363         public void visitLiteral(JCLiteral that) {}
 364 
 365         @Override
 366         public void visitTypeCast(JCTypeCast tree) {
 367             tree.expr.accept(this);
 368         }
 369 
 370         @Override
 371         public void visitUnary(JCUnary that) {
 372             if (!ALLOWED_OPERATORS.contains(that.getTag())) {
 373                 result = false;
 374                 return ;
 375             }
 376             that.arg.accept(this);
 377         }
 378 
 379         @Override
 380         public void visitBinary(JCBinary that) {
 381             if (!ALLOWED_OPERATORS.contains(that.getTag())) {
 382                 result = false;
 383                 return ;
 384             }
 385             that.lhs.accept(this);
 386             that.rhs.accept(this);
 387         }
 388 
 389         @Override
 390         public void visitConditional(JCConditional tree) {
 391             tree.cond.accept(this);
 392             tree.truepart.accept(this);
 393             tree.falsepart.accept(this);
 394         }
 395 
 396         @Override
 397         public void visitParens(JCParens tree) {
 398             tree.expr.accept(this);
 399         }
 400 
 401         @Override
 402         public void visitIdent(JCIdent that) {}
 403 
 404         @Override
 405         public void visitSelect(JCFieldAccess tree) {
 406             tree.selected.accept(this);
 407         }
 408     }
 409 
 410     /** Create a fresh environment for a variable's initializer.
 411      *  If the variable is a field, the owner of the environment's scope
 412      *  is be the variable itself, otherwise the owner is the method
 413      *  enclosing the variable definition.
 414      *
 415      *  @param tree     The variable definition.
 416      *  @param env      The environment current outside of the variable definition.
 417      */
 418     Env<AttrContext> initEnv(JCVariableDecl tree, Env<AttrContext> env) {
 419         Env<AttrContext> localEnv = env.dupto(new AttrContextEnv(tree, env.info.dup()));
 420         if (tree.sym.owner.kind == TYP) {
 421             localEnv.info.scope = env.info.scope.dupUnshared(tree.sym);
 422         }
 423         if ((tree.mods.flags & STATIC) != 0 ||
 424                 ((env.enclClass.sym.flags() & INTERFACE) != 0 && env.enclMethod == null))
 425             localEnv.info.staticLevel++;
 426         return localEnv;
 427     }
 428 
 429     /** Default member enter visitor method: do nothing
 430      */
 431     public void visitTree(JCTree tree) {
 432     }
 433 
 434     public void visitErroneous(JCErroneous tree) {
 435         if (tree.errs != null)
 436             memberEnter(tree.errs, env);
 437     }
 438 
 439     public Env<AttrContext> getMethodEnv(JCMethodDecl tree, Env<AttrContext> env) {
 440         Env<AttrContext> mEnv = methodEnv(tree, env);
 441         mEnv.info.lint = mEnv.info.lint.augment(tree.sym);
 442         for (List<JCTypeParameter> l = tree.typarams; l.nonEmpty(); l = l.tail)
 443             mEnv.info.scope.enterIfAbsent(l.head.type.tsym);
 444         for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail)
 445             mEnv.info.scope.enterIfAbsent(l.head.sym);
 446         return mEnv;
 447     }
 448 
 449     public Env<AttrContext> getInitEnv(JCVariableDecl tree, Env<AttrContext> env) {
 450         Env<AttrContext> iEnv = initEnv(tree, env);
 451         return iEnv;
 452     }
 453 }