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