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