1 /*
2 * Copyright (c) 1999, 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.*;
29 import java.util.function.BiConsumer;
30 import java.util.function.BiPredicate;
31 import java.util.function.Function;
32 import java.util.function.Predicate;
33 import java.util.function.Supplier;
34 import java.util.function.ToIntBiFunction;
35 import java.util.stream.Collectors;
36 import java.util.stream.StreamSupport;
37
38 import javax.lang.model.element.ElementKind;
39 import javax.lang.model.element.NestingKind;
40 import javax.tools.JavaFileManager;
41
42 import com.sun.source.tree.CaseTree;
43 import com.sun.tools.javac.code.*;
44 import com.sun.tools.javac.code.Attribute.Compound;
45 import com.sun.tools.javac.code.Directive.ExportsDirective;
46 import com.sun.tools.javac.code.Directive.RequiresDirective;
47 import com.sun.tools.javac.code.Source.Feature;
48 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
49 import com.sun.tools.javac.jvm.*;
50 import com.sun.tools.javac.resources.CompilerProperties;
51 import com.sun.tools.javac.resources.CompilerProperties.Errors;
52 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
53 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
54 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
55 import com.sun.tools.javac.tree.*;
56 import com.sun.tools.javac.util.*;
57 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
58 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
59 import com.sun.tools.javac.util.JCDiagnostic.Error;
60 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
61 import com.sun.tools.javac.util.JCDiagnostic.LintWarning;
62 import com.sun.tools.javac.util.List;
63
64 import com.sun.tools.javac.code.Lint;
65 import com.sun.tools.javac.code.Lint.LintCategory;
66 import com.sun.tools.javac.code.Scope.WriteableScope;
67 import com.sun.tools.javac.code.Type.*;
68 import com.sun.tools.javac.code.Symbol.*;
69 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
70 import com.sun.tools.javac.tree.JCTree.*;
71
72 import static com.sun.tools.javac.code.Flags.*;
73 import static com.sun.tools.javac.code.Flags.ANNOTATION;
74 import static com.sun.tools.javac.code.Flags.SYNCHRONIZED;
75 import static com.sun.tools.javac.code.Kinds.*;
76 import static com.sun.tools.javac.code.Kinds.Kind.*;
77 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
78 import static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE;
79 import static com.sun.tools.javac.code.TypeTag.*;
80 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
81
82 import static com.sun.tools.javac.tree.JCTree.Tag.*;
83 import javax.lang.model.element.Element;
84 import javax.lang.model.element.TypeElement;
85 import javax.lang.model.type.DeclaredType;
86 import javax.lang.model.util.ElementKindVisitor14;
87
88 /** Type checking helper class for the attribution phase.
89 *
90 * <p><b>This is NOT part of any supported API.
91 * If you write code that depends on this, you do so at your own risk.
92 * This code and its internal interfaces are subject to change or
93 * deletion without notice.</b>
94 */
95 public class Check {
96 protected static final Context.Key<Check> checkKey = new Context.Key<>();
97
98 // Flag bits indicating which item(s) chosen from a pair of items
99 private static final int FIRST = 0x01;
100 private static final int SECOND = 0x02;
101
102 private final Names names;
103 private final Log log;
104 private final Resolve rs;
105 private final Symtab syms;
106 private final Enter enter;
107 private final DeferredAttr deferredAttr;
108 private final Infer infer;
109 private final Types types;
110 private final TypeAnnotations typeAnnotations;
111 private final JCDiagnostic.Factory diags;
112 private final JavaFileManager fileManager;
113 private final Source source;
114 private final Target target;
115 private final Profile profile;
116 private final Preview preview;
117 private final boolean warnOnAnyAccessToMembers;
118
119 public boolean disablePreviewCheck;
120
121 // The set of lint options currently in effect. It is initialized
122 // from the context, and then is set/reset as needed by Attr as it
123 // visits all the various parts of the trees during attribution.
124 private Lint lint;
125
126 // The method being analyzed in Attr - it is set/reset as needed by
127 // Attr as it visits new method declarations.
128 private MethodSymbol method;
129
130 public static Check instance(Context context) {
131 Check instance = context.get(checkKey);
132 if (instance == null)
133 instance = new Check(context);
134 return instance;
135 }
136
137 @SuppressWarnings("this-escape")
138 protected Check(Context context) {
139 context.put(checkKey, this);
140
141 names = Names.instance(context);
142 log = Log.instance(context);
143 rs = Resolve.instance(context);
144 syms = Symtab.instance(context);
145 enter = Enter.instance(context);
146 deferredAttr = DeferredAttr.instance(context);
147 infer = Infer.instance(context);
148 types = Types.instance(context);
149 typeAnnotations = TypeAnnotations.instance(context);
150 diags = JCDiagnostic.Factory.instance(context);
151 Options options = Options.instance(context);
152 lint = Lint.instance(context);
153 fileManager = context.get(JavaFileManager.class);
154
155 source = Source.instance(context);
156 target = Target.instance(context);
157 warnOnAnyAccessToMembers = options.isSet("warnOnAccessToMembers");
158
159 disablePreviewCheck = false;
160
161 Target target = Target.instance(context);
162 syntheticNameChar = target.syntheticNameChar();
163
164 profile = Profile.instance(context);
165 preview = Preview.instance(context);
166
167 allowModules = Feature.MODULES.allowedInSource(source);
168 allowRecords = Feature.RECORDS.allowedInSource(source);
169 allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
170 }
171
172 /** Character for synthetic names
173 */
174 char syntheticNameChar;
175
176 /** A table mapping flat names of all compiled classes for each module in this run
177 * to their symbols; maintained from outside.
178 */
179 private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
180
181 /** Are modules allowed
182 */
183 private final boolean allowModules;
184
185 /** Are records allowed
186 */
187 private final boolean allowRecords;
188
189 /** Are sealed classes allowed
190 */
191 private final boolean allowSealed;
192
193 /** Whether to force suppression of deprecation and preview warnings.
194 * This happens when attributing import statements for JDK 9+.
195 * @see Feature#DEPRECATION_ON_IMPORT
196 */
197 private boolean importSuppression;
198
199 /* *************************************************************************
200 * Errors and Warnings
201 **************************************************************************/
202
203 Lint setLint(Lint newLint) {
204 Lint prev = lint;
205 lint = newLint;
206 return prev;
207 }
208
209 boolean setImportSuppression(boolean newImportSuppression) {
210 boolean prev = importSuppression;
211 importSuppression = newImportSuppression;
212 return prev;
213 }
214
215 MethodSymbol setMethod(MethodSymbol newMethod) {
216 MethodSymbol prev = method;
217 method = newMethod;
218 return prev;
219 }
220
221 /** Warn about deprecated symbol.
222 * @param pos Position to be used for error reporting.
223 * @param sym The deprecated symbol.
224 */
225 void warnDeprecated(DiagnosticPosition pos, Symbol sym) {
226 Assert.check(!importSuppression);
227 LintWarning warningKey = sym.isDeprecatedForRemoval() ?
228 (sym.kind == MDL ?
229 LintWarnings.HasBeenDeprecatedForRemovalModule(sym) :
230 LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location())) :
231 (sym.kind == MDL ?
232 LintWarnings.HasBeenDeprecatedModule(sym) :
233 LintWarnings.HasBeenDeprecated(sym, sym.location()));
234 log.warning(pos, warningKey);
235 }
236
237 /** Log a preview warning.
238 * @param pos Position to be used for error reporting.
239 * @param msg A Warning describing the problem.
240 */
241 public void warnPreviewAPI(DiagnosticPosition pos, LintWarning warnKey) {
242 if (!importSuppression)
243 log.warning(pos, warnKey);
244 }
245
246 /** Warn about unchecked operation.
247 * @param pos Position to be used for error reporting.
248 * @param msg A string describing the problem.
249 */
250 public void warnUnchecked(DiagnosticPosition pos, LintWarning warnKey) {
251 log.warning(pos, warnKey);
252 }
253
254 /** Report a failure to complete a class.
255 * @param pos Position to be used for error reporting.
256 * @param ex The failure to report.
257 */
258 public Type completionError(DiagnosticPosition pos, CompletionFailure ex) {
259 log.error(DiagnosticFlag.NON_DEFERRABLE, pos, Errors.CantAccess(ex.sym, ex.getDetailValue()));
260 return syms.errType;
261 }
262
263 /** Report an error that wrong type tag was found.
264 * @param pos Position to be used for error reporting.
265 * @param required An internationalized string describing the type tag
266 * required.
267 * @param found The type that was found.
268 */
269 Type typeTagError(DiagnosticPosition pos, JCDiagnostic required, Object found) {
270 // this error used to be raised by the parser,
271 // but has been delayed to this point:
272 if (found instanceof Type type && type.hasTag(VOID)) {
273 log.error(pos, Errors.IllegalStartOfType);
274 return syms.errType;
275 }
276 log.error(pos, Errors.TypeFoundReq(found, required));
277 return types.createErrorType(found instanceof Type type ? type : syms.errType);
278 }
279
280 /** Report duplicate declaration error.
281 */
282 void duplicateError(DiagnosticPosition pos, Symbol sym) {
283 if (!sym.type.isErroneous()) {
284 Symbol location = sym.location();
285 if (location.kind == MTH &&
286 ((MethodSymbol)location).isStaticOrInstanceInit()) {
287 log.error(pos,
288 Errors.AlreadyDefinedInClinit(kindName(sym),
289 sym,
290 kindName(sym.location()),
291 kindName(sym.location().enclClass()),
292 sym.location().enclClass()));
293 } else {
294 /* dont error if this is a duplicated parameter of a generated canonical constructor
295 * as we should have issued an error for the duplicated fields
296 */
297 if (location.kind != MTH ||
298 ((sym.owner.flags_field & GENERATEDCONSTR) == 0) ||
299 ((sym.owner.flags_field & RECORD) == 0)) {
300 log.error(pos,
301 Errors.AlreadyDefined(kindName(sym),
302 sym,
303 kindName(sym.location()),
304 sym.location()));
305 }
306 }
307 }
308 }
309
310 /** Report array/varargs duplicate declaration
311 */
312 void varargsDuplicateError(DiagnosticPosition pos, Symbol sym1, Symbol sym2) {
313 if (!sym1.type.isErroneous() && !sym2.type.isErroneous()) {
314 log.error(pos, Errors.ArrayAndVarargs(sym1, sym2, sym2.location()));
315 }
316 }
317
318 /* ************************************************************************
319 * duplicate declaration checking
320 *************************************************************************/
321
322 /** Check that variable does not hide variable with same name in
323 * immediately enclosing local scope.
324 * @param pos Position for error reporting.
325 * @param v The symbol.
326 * @param s The scope.
327 */
328 void checkTransparentVar(DiagnosticPosition pos, VarSymbol v, Scope s) {
329 for (Symbol sym : s.getSymbolsByName(v.name)) {
330 if (sym.owner != v.owner) break;
331 if (sym.kind == VAR &&
332 sym.owner.kind.matches(KindSelector.VAL_MTH) &&
333 v.name != names.error) {
334 duplicateError(pos, sym);
335 return;
336 }
337 }
338 }
339
340 /** Check that a class or interface does not hide a class or
341 * interface with same name in immediately enclosing local scope.
342 * @param pos Position for error reporting.
343 * @param c The symbol.
344 * @param s The scope.
345 */
346 void checkTransparentClass(DiagnosticPosition pos, ClassSymbol c, Scope s) {
347 for (Symbol sym : s.getSymbolsByName(c.name)) {
348 if (sym.owner != c.owner) break;
349 if (sym.kind == TYP && !sym.type.hasTag(TYPEVAR) &&
350 sym.owner.kind.matches(KindSelector.VAL_MTH) &&
351 c.name != names.error) {
352 duplicateError(pos, sym);
353 return;
354 }
355 }
356 }
357
358 /** Check that class does not have the same name as one of
359 * its enclosing classes, or as a class defined in its enclosing scope.
360 * return true if class is unique in its enclosing scope.
361 * @param pos Position for error reporting.
362 * @param name The class name.
363 * @param s The enclosing scope.
364 */
365 boolean checkUniqueClassName(DiagnosticPosition pos, Name name, Scope s) {
366 for (Symbol sym : s.getSymbolsByName(name, NON_RECURSIVE)) {
367 if (sym.kind == TYP && sym.name != names.error) {
368 duplicateError(pos, sym);
369 return false;
370 }
371 }
372 for (Symbol sym = s.owner; sym != null; sym = sym.owner) {
373 if (sym.kind == TYP && sym.name == name && sym.name != names.error &&
374 !sym.isImplicit()) {
375 duplicateError(pos, sym);
376 return true;
377 }
378 }
379 return true;
380 }
381
382 /* *************************************************************************
383 * Class name generation
384 **************************************************************************/
385
386
387 private Map<Pair<Name, Name>, Integer> localClassNameIndexes = new HashMap<>();
388
389 /** Return name of local class.
390 * This is of the form {@code <enclClass> $ n <classname> }
391 * where
392 * enclClass is the flat name of the enclosing class,
393 * classname is the simple name of the local class
394 */
395 public Name localClassName(ClassSymbol c) {
396 Name enclFlatname = c.owner.enclClass().flatname;
397 String enclFlatnameStr = enclFlatname.toString();
398 Pair<Name, Name> key = new Pair<>(enclFlatname, c.name);
399 Integer index = localClassNameIndexes.get(key);
400 for (int i = (index == null) ? 1 : index; ; i++) {
401 Name flatname = names.fromString(enclFlatnameStr
402 + syntheticNameChar + i + c.name);
403 if (getCompiled(c.packge().modle, flatname) == null) {
404 localClassNameIndexes.put(key, i + 1);
405 return flatname;
406 }
407 }
408 }
409
410 public void clearLocalClassNameIndexes(ClassSymbol c) {
411 if (c.owner != null && c.owner.kind != NIL) {
412 localClassNameIndexes.remove(new Pair<>(
413 c.owner.enclClass().flatname, c.name));
414 }
415 }
416
417 public void newRound() {
418 compiled.clear();
419 localClassNameIndexes.clear();
420 }
421
422 public void putCompiled(ClassSymbol csym) {
423 compiled.put(Pair.of(csym.packge().modle, csym.flatname), csym);
424 }
425
426 public ClassSymbol getCompiled(ClassSymbol csym) {
427 return compiled.get(Pair.of(csym.packge().modle, csym.flatname));
428 }
429
430 public ClassSymbol getCompiled(ModuleSymbol msym, Name flatname) {
431 return compiled.get(Pair.of(msym, flatname));
432 }
433
434 public void removeCompiled(ClassSymbol csym) {
435 compiled.remove(Pair.of(csym.packge().modle, csym.flatname));
436 }
437
438 /* *************************************************************************
439 * Type Checking
440 **************************************************************************/
441
442 /**
443 * A check context is an object that can be used to perform compatibility
444 * checks - depending on the check context, meaning of 'compatibility' might
445 * vary significantly.
446 */
447 public interface CheckContext {
448 /**
449 * Is type 'found' compatible with type 'req' in given context
450 */
451 boolean compatible(Type found, Type req, Warner warn);
452 /**
453 * Report a check error
454 */
455 void report(DiagnosticPosition pos, JCDiagnostic details);
456 /**
457 * Obtain a warner for this check context
458 */
459 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req);
460
461 public InferenceContext inferenceContext();
462
463 public DeferredAttr.DeferredAttrContext deferredAttrContext();
464 }
465
466 /**
467 * This class represent a check context that is nested within another check
468 * context - useful to check sub-expressions. The default behavior simply
469 * redirects all method calls to the enclosing check context leveraging
470 * the forwarding pattern.
471 */
472 static class NestedCheckContext implements CheckContext {
473 CheckContext enclosingContext;
474
475 NestedCheckContext(CheckContext enclosingContext) {
476 this.enclosingContext = enclosingContext;
477 }
478
479 public boolean compatible(Type found, Type req, Warner warn) {
480 return enclosingContext.compatible(found, req, warn);
481 }
482
483 public void report(DiagnosticPosition pos, JCDiagnostic details) {
484 enclosingContext.report(pos, details);
485 }
486
487 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
488 return enclosingContext.checkWarner(pos, found, req);
489 }
490
491 public InferenceContext inferenceContext() {
492 return enclosingContext.inferenceContext();
493 }
494
495 public DeferredAttrContext deferredAttrContext() {
496 return enclosingContext.deferredAttrContext();
497 }
498 }
499
500 /**
501 * Check context to be used when evaluating assignment/return statements
502 */
503 CheckContext basicHandler = new CheckContext() {
504 public void report(DiagnosticPosition pos, JCDiagnostic details) {
505 log.error(pos, Errors.ProbFoundReq(details));
506 }
507 public boolean compatible(Type found, Type req, Warner warn) {
508 return types.isAssignable(found, req, warn);
509 }
510
511 public Warner checkWarner(DiagnosticPosition pos, Type found, Type req) {
512 return convertWarner(pos, found, req);
513 }
514
515 public InferenceContext inferenceContext() {
516 return infer.emptyContext;
517 }
518
519 public DeferredAttrContext deferredAttrContext() {
520 return deferredAttr.emptyDeferredAttrContext;
521 }
522
523 @Override
524 public String toString() {
525 return "CheckContext: basicHandler";
526 }
527 };
528
529 /** Check that a given type is assignable to a given proto-type.
530 * If it is, return the type, otherwise return errType.
531 * @param pos Position to be used for error reporting.
532 * @param found The type that was found.
533 * @param req The type that was required.
534 */
535 public Type checkType(DiagnosticPosition pos, Type found, Type req) {
536 return checkType(pos, found, req, basicHandler);
537 }
538
539 Type checkType(final DiagnosticPosition pos, final Type found, final Type req, final CheckContext checkContext) {
540 final InferenceContext inferenceContext = checkContext.inferenceContext();
541 if (inferenceContext.free(req) || inferenceContext.free(found)) {
542 inferenceContext.addFreeTypeListener(List.of(req, found),
543 solvedContext -> checkType(pos, solvedContext.asInstType(found), solvedContext.asInstType(req), checkContext));
544 }
545 if (req.hasTag(ERROR))
546 return req;
547 if (req.hasTag(NONE))
548 return found;
549 if (checkContext.compatible(found, req, checkContext.checkWarner(pos, found, req))) {
550 return found;
551 } else {
552 if (found.isNumeric() && req.isNumeric()) {
553 checkContext.report(pos, diags.fragment(Fragments.PossibleLossOfPrecision(found, req)));
554 return types.createErrorType(found);
555 }
556 checkContext.report(pos, diags.fragment(Fragments.InconvertibleTypes(found, req)));
557 return types.createErrorType(found);
558 }
559 }
560
561 /** Check that a given type can be cast to a given target type.
562 * Return the result of the cast.
563 * @param pos Position to be used for error reporting.
564 * @param found The type that is being cast.
565 * @param req The target type of the cast.
566 */
567 Type checkCastable(DiagnosticPosition pos, Type found, Type req) {
568 return checkCastable(pos, found, req, basicHandler);
569 }
570 Type checkCastable(DiagnosticPosition pos, Type found, Type req, CheckContext checkContext) {
571 if (types.isCastable(found, req, castWarner(pos, found, req))) {
572 return req;
573 } else {
574 checkContext.report(pos, diags.fragment(Fragments.InconvertibleTypes(found, req)));
575 return types.createErrorType(found);
576 }
577 }
578
579 /** Check for redundant casts (i.e. where source type is a subtype of target type)
580 * The problem should only be reported for non-292 cast
581 */
582 public void checkRedundantCast(Env<AttrContext> env, final JCTypeCast tree) {
583 if (!tree.type.isErroneous()
584 && types.isSameType(tree.expr.type, tree.clazz.type)
585 && !(ignoreAnnotatedCasts && TreeInfo.containsTypeAnnotation(tree.clazz))
586 && !is292targetTypeCast(tree)) {
587 log.warning(tree.pos(), LintWarnings.RedundantCast(tree.clazz.type));
588 }
589 }
590 //where
591 private boolean is292targetTypeCast(JCTypeCast tree) {
592 boolean is292targetTypeCast = false;
593 JCExpression expr = TreeInfo.skipParens(tree.expr);
594 if (expr.hasTag(APPLY)) {
595 JCMethodInvocation apply = (JCMethodInvocation)expr;
596 Symbol sym = TreeInfo.symbol(apply.meth);
597 is292targetTypeCast = sym != null &&
598 sym.kind == MTH &&
599 (sym.flags() & HYPOTHETICAL) != 0;
600 }
601 return is292targetTypeCast;
602 }
603
604 private static final boolean ignoreAnnotatedCasts = true;
605
606 /** Check that a type is within some bounds.
607 *
608 * Used in TypeApply to verify that, e.g., X in {@code V<X>} is a valid
609 * type argument.
610 * @param a The type that should be bounded by bs.
611 * @param bound The bound.
612 */
613 private boolean checkExtends(Type a, Type bound) {
614 if (a.isUnbound()) {
615 return true;
616 } else if (!a.hasTag(WILDCARD)) {
617 a = types.cvarUpperBound(a);
618 return types.isSubtype(a, bound);
619 } else if (a.isExtendsBound()) {
620 return types.isCastable(bound, types.wildUpperBound(a), types.noWarnings);
621 } else if (a.isSuperBound()) {
622 return !types.notSoftSubtype(types.wildLowerBound(a), bound);
623 }
624 return true;
625 }
626
627 /** Check that type is different from 'void'.
628 * @param pos Position to be used for error reporting.
629 * @param t The type to be checked.
630 */
631 Type checkNonVoid(DiagnosticPosition pos, Type t) {
632 if (t.hasTag(VOID)) {
633 log.error(pos, Errors.VoidNotAllowedHere);
634 return types.createErrorType(t);
635 } else {
636 return t;
637 }
638 }
639
640 Type checkClassOrArrayType(DiagnosticPosition pos, Type t) {
641 if (!t.hasTag(CLASS) && !t.hasTag(ARRAY) && !t.hasTag(ERROR)) {
642 return typeTagError(pos,
643 diags.fragment(Fragments.TypeReqClassArray),
644 asTypeParam(t));
645 } else {
646 return t;
647 }
648 }
649
650 /** Check that type is a class or interface type.
651 * @param pos Position to be used for error reporting.
652 * @param t The type to be checked.
653 */
654 Type checkClassType(DiagnosticPosition pos, Type t) {
655 if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
656 return typeTagError(pos,
657 diags.fragment(Fragments.TypeReqClass),
658 asTypeParam(t));
659 } else {
660 return t;
661 }
662 }
663 //where
664 private Object asTypeParam(Type t) {
665 return (t.hasTag(TYPEVAR))
666 ? diags.fragment(Fragments.TypeParameter(t))
667 : t;
668 }
669
670 /** Check that type is a valid qualifier for a constructor reference expression
671 */
672 Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
673 t = checkClassOrArrayType(pos, t);
674 if (t.hasTag(CLASS)) {
675 if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
676 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
677 t = types.createErrorType(t);
678 } else if ((t.tsym.flags() & ENUM) != 0) {
679 log.error(pos, Errors.EnumCantBeInstantiated);
680 t = types.createErrorType(t);
681 } else {
682 t = checkClassType(pos, t, true);
683 }
684 } else if (t.hasTag(ARRAY)) {
685 if (!types.isReifiable(((ArrayType)t).elemtype)) {
686 log.error(pos, Errors.GenericArrayCreation);
687 t = types.createErrorType(t);
688 }
689 }
690 return t;
691 }
692
693 /** Check that type is a class or interface type.
694 * @param pos Position to be used for error reporting.
695 * @param t The type to be checked.
696 * @param noBounds True if type bounds are illegal here.
697 */
698 Type checkClassType(DiagnosticPosition pos, Type t, boolean noBounds) {
699 t = checkClassType(pos, t);
700 if (noBounds && t.isParameterized()) {
701 List<Type> args = t.getTypeArguments();
702 while (args.nonEmpty()) {
703 if (args.head.hasTag(WILDCARD))
704 return typeTagError(pos,
705 diags.fragment(Fragments.TypeReqExact),
706 args.head);
707 args = args.tail;
708 }
709 }
710 return t;
711 }
712
713 /** Check that type is a reference type, i.e. a class, interface or array type
714 * or a type variable.
715 * @param pos Position to be used for error reporting.
716 * @param t The type to be checked.
717 */
718 Type checkRefType(DiagnosticPosition pos, Type t) {
719 if (t.isReference())
720 return t;
721 else
722 return typeTagError(pos,
723 diags.fragment(Fragments.TypeReqRef),
724 t);
725 }
726
727 /** Check that each type is a reference type, i.e. a class, interface or array type
728 * or a type variable.
729 * @param trees Original trees, used for error reporting.
730 * @param types The types to be checked.
731 */
732 List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
733 List<JCExpression> tl = trees;
734 for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
735 l.head = checkRefType(tl.head.pos(), l.head);
736 tl = tl.tail;
737 }
738 return types;
739 }
740
741 /** Check that type is a null or reference type.
742 * @param pos Position to be used for error reporting.
743 * @param t The type to be checked.
744 */
745 Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
746 if (t.isReference() || t.hasTag(BOT))
747 return t;
748 else
749 return typeTagError(pos,
750 diags.fragment(Fragments.TypeReqRef),
751 t);
752 }
753
754 /** Check that flag set does not contain elements of two conflicting sets. s
755 * Return true if it doesn't.
756 * @param pos Position to be used for error reporting.
757 * @param flags The set of flags to be checked.
758 * @param set1 Conflicting flags set #1.
759 * @param set2 Conflicting flags set #2.
760 */
761 boolean checkDisjoint(DiagnosticPosition pos, long flags, long set1, long set2) {
762 if ((flags & set1) != 0 && (flags & set2) != 0) {
763 log.error(pos,
764 Errors.IllegalCombinationOfModifiers(asFlagSet(TreeInfo.firstFlag(flags & set1)),
765 asFlagSet(TreeInfo.firstFlag(flags & set2))));
766 return false;
767 } else
768 return true;
769 }
770
771 /** Check that usage of diamond operator is correct (i.e. diamond should not
772 * be used with non-generic classes or in anonymous class creation expressions)
773 */
774 Type checkDiamond(JCNewClass tree, Type t) {
775 if (!TreeInfo.isDiamond(tree) ||
776 t.isErroneous()) {
777 return checkClassType(tree.clazz.pos(), t, true);
778 } else {
779 if (tree.def != null && !Feature.DIAMOND_WITH_ANONYMOUS_CLASS_CREATION.allowedInSource(source)) {
780 log.error(DiagnosticFlag.SOURCE_LEVEL, tree.clazz.pos(),
781 Errors.CantApplyDiamond1(t, Feature.DIAMOND_WITH_ANONYMOUS_CLASS_CREATION.fragment(source.name)));
782 }
783 if (t.tsym.type.getTypeArguments().isEmpty()) {
784 log.error(tree.clazz.pos(),
785 Errors.CantApplyDiamond1(t,
786 Fragments.DiamondNonGeneric(t)));
787 return types.createErrorType(t);
788 } else if (tree.typeargs != null &&
789 tree.typeargs.nonEmpty()) {
790 log.error(tree.clazz.pos(),
791 Errors.CantApplyDiamond1(t,
792 Fragments.DiamondAndExplicitParams(t)));
793 return types.createErrorType(t);
794 } else {
795 return t;
796 }
797 }
798 }
799
800 /** Check that the type inferred using the diamond operator does not contain
801 * non-denotable types such as captured types or intersection types.
802 * @param t the type inferred using the diamond operator
803 * @return the (possibly empty) list of non-denotable types.
804 */
805 List<Type> checkDiamondDenotable(ClassType t) {
806 ListBuffer<Type> buf = new ListBuffer<>();
807 for (Type arg : t.allparams()) {
808 if (!checkDenotable(arg)) {
809 buf.append(arg);
810 }
811 }
812 return buf.toList();
813 }
814
815 public boolean checkDenotable(Type t) {
816 return denotableChecker.visit(t, null);
817 }
818 // where
819
820 /** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
821 * types. The visit methods return false as soon as a non-denotable type is encountered and true
822 * otherwise.
823 */
824 private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() {
825 @Override
826 public Boolean visitType(Type t, Void s) {
827 return true;
828 }
829 @Override
830 public Boolean visitClassType(ClassType t, Void s) {
831 if (t.isUnion() || t.isIntersection()) {
832 return false;
833 }
834 for (Type targ : t.allparams()) {
835 if (!visit(targ, s)) {
836 return false;
837 }
838 }
839 return true;
840 }
841
842 @Override
843 public Boolean visitTypeVar(TypeVar t, Void s) {
844 /* Any type variable mentioned in the inferred type must have been declared as a type parameter
845 (i.e cannot have been produced by inference (18.4))
846 */
847 return (t.tsym.flags() & SYNTHETIC) == 0;
848 }
849
850 @Override
851 public Boolean visitCapturedType(CapturedType t, Void s) {
852 /* Any type variable mentioned in the inferred type must have been declared as a type parameter
853 (i.e cannot have been produced by capture conversion (5.1.10))
854 */
855 return false;
856 }
857
858 @Override
859 public Boolean visitArrayType(ArrayType t, Void s) {
860 return visit(t.elemtype, s);
861 }
862
863 @Override
864 public Boolean visitWildcardType(WildcardType t, Void s) {
865 return visit(t.type, s);
866 }
867 };
868
869 void checkVarargsMethodDecl(Env<AttrContext> env, JCMethodDecl tree) {
870 MethodSymbol m = tree.sym;
871 boolean hasTrustMeAnno = m.attribute(syms.trustMeType.tsym) != null;
872 Type varargElemType = null;
873 if (m.isVarArgs()) {
874 varargElemType = types.elemtype(tree.params.last().type);
875 }
876 if (hasTrustMeAnno && !isTrustMeAllowedOnMethod(m)) {
877 if (varargElemType != null) {
878 JCDiagnostic msg = Feature.PRIVATE_SAFE_VARARGS.allowedInSource(source) ?
879 diags.fragment(Fragments.VarargsTrustmeOnVirtualVarargs(m)) :
880 diags.fragment(Fragments.VarargsTrustmeOnVirtualVarargsFinalOnly(m));
881 log.error(tree,
882 Errors.VarargsInvalidTrustmeAnno(syms.trustMeType.tsym,
883 msg));
884 } else {
885 log.error(tree,
886 Errors.VarargsInvalidTrustmeAnno(syms.trustMeType.tsym,
887 Fragments.VarargsTrustmeOnNonVarargsMeth(m)));
888 }
889 } else if (hasTrustMeAnno && varargElemType != null &&
890 types.isReifiable(varargElemType)) {
891 log.warning(tree.pos(), LintWarnings.VarargsRedundantTrustmeAnno(
892 syms.trustMeType.tsym,
893 diags.fragment(Fragments.VarargsTrustmeOnReifiableVarargs(varargElemType))));
894 }
895 else if (!hasTrustMeAnno && varargElemType != null &&
896 !types.isReifiable(varargElemType)) {
897 warnUnchecked(tree.params.head.pos(), LintWarnings.UncheckedVarargsNonReifiableType(varargElemType));
898 }
899 }
900 //where
901 private boolean isTrustMeAllowedOnMethod(Symbol s) {
902 return (s.flags() & VARARGS) != 0 &&
903 (s.isConstructor() ||
904 (s.flags() & (STATIC | FINAL |
905 (Feature.PRIVATE_SAFE_VARARGS.allowedInSource(source) ? PRIVATE : 0) )) != 0);
906 }
907
908 Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
909 //check that resulting type is not the null type
910 if (t.hasTag(BOT)) {
911 log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull));
912 return types.createErrorType(t);
913 } else if (t.hasTag(VOID)) {
914 log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferVoid));
915 return types.createErrorType(t);
916 }
917
918 //upward project the initializer type
919 return types.upward(t, types.captures(t)).baseType();
920 }
921
922 Type checkMethod(final Type mtype,
923 final Symbol sym,
924 final Env<AttrContext> env,
925 final List<JCExpression> argtrees,
926 final List<Type> argtypes,
927 final boolean useVarargs,
928 InferenceContext inferenceContext) {
929 // System.out.println("call : " + env.tree);
930 // System.out.println("method : " + owntype);
931 // System.out.println("actuals: " + argtypes);
932 if (inferenceContext.free(mtype)) {
933 inferenceContext.addFreeTypeListener(List.of(mtype),
934 solvedContext -> checkMethod(solvedContext.asInstType(mtype), sym, env, argtrees, argtypes, useVarargs, solvedContext));
935 return mtype;
936 }
937 Type owntype = mtype;
938 List<Type> formals = owntype.getParameterTypes();
939 List<Type> nonInferred = sym.type.getParameterTypes();
940 if (nonInferred.length() != formals.length()) nonInferred = formals;
941 Type last = useVarargs ? formals.last() : null;
942 if (sym.name == names.init && sym.owner == syms.enumSym) {
943 formals = formals.tail.tail;
944 nonInferred = nonInferred.tail.tail;
945 }
946 if ((sym.flags() & ANONCONSTR_BASED) != 0) {
947 formals = formals.tail;
948 nonInferred = nonInferred.tail;
949 }
950 List<JCExpression> args = argtrees;
951 if (args != null) {
952 //this is null when type-checking a method reference
953 while (formals.head != last) {
954 JCTree arg = args.head;
955 Warner warn = convertWarner(arg.pos(), arg.type, nonInferred.head);
956 assertConvertible(arg, arg.type, formals.head, warn);
957 args = args.tail;
958 formals = formals.tail;
959 nonInferred = nonInferred.tail;
960 }
961 if (useVarargs) {
962 Type varArg = types.elemtype(last);
963 while (args.tail != null) {
964 JCTree arg = args.head;
965 Warner warn = convertWarner(arg.pos(), arg.type, varArg);
966 assertConvertible(arg, arg.type, varArg, warn);
967 args = args.tail;
968 }
969 } else if ((sym.flags() & (VARARGS | SIGNATURE_POLYMORPHIC)) == VARARGS) {
970 // non-varargs call to varargs method
971 Type varParam = owntype.getParameterTypes().last();
972 Type lastArg = argtypes.last();
973 if (types.isSubtypeUnchecked(lastArg, types.elemtype(varParam)) &&
974 !types.isSameType(types.erasure(varParam), types.erasure(lastArg)))
975 log.warning(argtrees.last().pos(),
976 Warnings.InexactNonVarargsCall(types.elemtype(varParam),varParam));
977 }
978 }
979 if (useVarargs) {
980 Type argtype = owntype.getParameterTypes().last();
981 if (!types.isReifiable(argtype) &&
982 (sym.baseSymbol().attribute(syms.trustMeType.tsym) == null ||
983 !isTrustMeAllowedOnMethod(sym))) {
984 warnUnchecked(env.tree.pos(), LintWarnings.UncheckedGenericArrayCreation(argtype));
985 }
986 TreeInfo.setVarargsElement(env.tree, types.elemtype(argtype));
987 }
988 return owntype;
989 }
990 //where
991 private void assertConvertible(JCTree tree, Type actual, Type formal, Warner warn) {
992 if (types.isConvertible(actual, formal, warn))
993 return;
994
995 if (formal.isCompound()
996 && types.isSubtype(actual, types.supertype(formal))
997 && types.isSubtypeUnchecked(actual, types.interfaces(formal), warn))
998 return;
999 }
1000
1001 /**
1002 * Check that type 't' is a valid instantiation of a generic class
1003 * (see JLS 4.5)
1004 *
1005 * @param t class type to be checked
1006 * @return true if 't' is well-formed
1007 */
1008 public boolean checkValidGenericType(Type t) {
1009 return firstIncompatibleTypeArg(t) == null;
1010 }
1011 //WHERE
1012 private Type firstIncompatibleTypeArg(Type type) {
1013 List<Type> formals = type.tsym.type.allparams();
1014 List<Type> actuals = type.allparams();
1015 List<Type> args = type.getTypeArguments();
1016 List<Type> forms = type.tsym.type.getTypeArguments();
1017 ListBuffer<Type> bounds_buf = new ListBuffer<>();
1018
1019 // For matching pairs of actual argument types `a' and
1020 // formal type parameters with declared bound `b' ...
1021 while (args.nonEmpty() && forms.nonEmpty()) {
1022 // exact type arguments needs to know their
1023 // bounds (for upper and lower bound
1024 // calculations). So we create new bounds where
1025 // type-parameters are replaced with actuals argument types.
1026 bounds_buf.append(types.subst(forms.head.getUpperBound(), formals, actuals));
1027 args = args.tail;
1028 forms = forms.tail;
1029 }
1030
1031 args = type.getTypeArguments();
1032 List<Type> tvars_cap = types.substBounds(formals,
1033 formals,
1034 types.capture(type).allparams());
1035 while (args.nonEmpty() && tvars_cap.nonEmpty()) {
1036 // Let the actual arguments know their bound
1037 args.head.withTypeVar((TypeVar)tvars_cap.head);
1038 args = args.tail;
1039 tvars_cap = tvars_cap.tail;
1040 }
1041
1042 args = type.getTypeArguments();
1043 List<Type> bounds = bounds_buf.toList();
1044
1045 while (args.nonEmpty() && bounds.nonEmpty()) {
1046 Type actual = args.head;
1047 if (!isTypeArgErroneous(actual) &&
1048 !bounds.head.isErroneous() &&
1049 !checkExtends(actual, bounds.head)) {
1050 return args.head;
1051 }
1052 args = args.tail;
1053 bounds = bounds.tail;
1054 }
1055
1056 args = type.getTypeArguments();
1057 bounds = bounds_buf.toList();
1058
1059 for (Type arg : types.capture(type).getTypeArguments()) {
1060 if (arg.hasTag(TYPEVAR) &&
1061 arg.getUpperBound().isErroneous() &&
1062 !bounds.head.isErroneous() &&
1063 !isTypeArgErroneous(args.head)) {
1064 return args.head;
1065 }
1066 bounds = bounds.tail;
1067 args = args.tail;
1068 }
1069
1070 return null;
1071 }
1072 //where
1073 boolean isTypeArgErroneous(Type t) {
1074 return isTypeArgErroneous.visit(t);
1075 }
1076
1077 Types.UnaryVisitor<Boolean> isTypeArgErroneous = new Types.UnaryVisitor<Boolean>() {
1078 public Boolean visitType(Type t, Void s) {
1079 return t.isErroneous();
1080 }
1081 @Override
1082 public Boolean visitTypeVar(TypeVar t, Void s) {
1083 return visit(t.getUpperBound());
1084 }
1085 @Override
1086 public Boolean visitCapturedType(CapturedType t, Void s) {
1087 return visit(t.getUpperBound()) ||
1088 visit(t.getLowerBound());
1089 }
1090 @Override
1091 public Boolean visitWildcardType(WildcardType t, Void s) {
1092 return visit(t.type);
1093 }
1094 };
1095
1096 /** Check that given modifiers are legal for given symbol and
1097 * return modifiers together with any implicit modifiers for that symbol.
1098 * Warning: we can't use flags() here since this method
1099 * is called during class enter, when flags() would cause a premature
1100 * completion.
1101 * @param flags The set of modifiers given in a definition.
1102 * @param sym The defined symbol.
1103 * @param tree The declaration
1104 */
1105 long checkFlags(long flags, Symbol sym, JCTree tree) {
1106 final DiagnosticPosition pos = tree.pos();
1107 long mask;
1108 long implicit = 0;
1109
1110 switch (sym.kind) {
1111 case VAR:
1112 if (TreeInfo.isReceiverParam(tree))
1113 mask = ReceiverParamFlags;
1114 else if (sym.owner.kind != TYP)
1115 mask = LocalVarFlags;
1116 else if ((sym.owner.flags_field & INTERFACE) != 0)
1117 mask = implicit = InterfaceVarFlags;
1118 else
1119 mask = VarFlags;
1120 break;
1121 case MTH:
1122 if (sym.name == names.init) {
1123 if ((sym.owner.flags_field & ENUM) != 0) {
1124 // enum constructors cannot be declared public or
1125 // protected and must be implicitly or explicitly
1126 // private
1127 implicit = PRIVATE;
1128 mask = PRIVATE;
1129 } else
1130 mask = ConstructorFlags;
1131 } else if ((sym.owner.flags_field & INTERFACE) != 0) {
1132 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1133 mask = AnnotationTypeElementMask;
1134 implicit = PUBLIC | ABSTRACT;
1135 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1136 mask = InterfaceMethodMask;
1137 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1138 if ((flags & DEFAULT) != 0) {
1139 implicit |= ABSTRACT;
1140 }
1141 } else {
1142 mask = implicit = InterfaceMethodFlags;
1143 }
1144 } else if ((sym.owner.flags_field & RECORD) != 0) {
1145 mask = RecordMethodFlags;
1146 } else {
1147 mask = MethodFlags;
1148 }
1149 if ((flags & STRICTFP) != 0) {
1150 log.warning(tree.pos(), LintWarnings.Strictfp);
1151 }
1152 // Imply STRICTFP if owner has STRICTFP set.
1153 if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1154 ((flags) & Flags.DEFAULT) != 0)
1155 implicit |= sym.owner.flags_field & STRICTFP;
1156 break;
1157 case TYP:
1158 if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1159 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1160 boolean implicitlyStatic = !sym.isAnonymous() &&
1161 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1162 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1163 // local statics are allowed only if records are allowed too
1164 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
1165 implicit = implicitlyStatic ? STATIC : implicit;
1166 } else if (sym.owner.kind == TYP) {
1167 // statics in inner classes are allowed only if records are allowed too
1168 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1169 if (sym.owner.owner.kind == PCK ||
1170 (sym.owner.flags_field & STATIC) != 0) {
1171 mask |= STATIC;
1172 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1173 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1174 }
1175 // Nested interfaces and enums are always STATIC (Spec ???)
1176 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1177 } else {
1178 mask = ExtendedClassFlags;
1179 }
1180 // Interfaces are always ABSTRACT
1181 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1182
1183 if ((flags & ENUM) != 0) {
1184 // enums can't be declared abstract, final, sealed or non-sealed
1185 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
1186 implicit |= implicitEnumFinalFlag(tree);
1187 }
1188 if ((flags & RECORD) != 0) {
1189 // records can't be declared abstract
1190 mask &= ~ABSTRACT;
1191 implicit |= FINAL;
1192 }
1193 if ((flags & STRICTFP) != 0) {
1194 log.warning(tree.pos(), LintWarnings.Strictfp);
1195 }
1196 // Imply STRICTFP if owner has STRICTFP set.
1197 implicit |= sym.owner.flags_field & STRICTFP;
1198 break;
1199 default:
1200 throw new AssertionError();
1201 }
1202 long illegal = flags & ExtendedStandardFlags & ~mask;
1203 if (illegal != 0) {
1204 if ((illegal & INTERFACE) != 0) {
1205 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1206 mask |= INTERFACE;
1207 }
1208 else {
1209 log.error(pos,
1210 Errors.ModNotAllowedHere(asFlagSet(illegal)));
1211 }
1212 }
1213 else if ((sym.kind == TYP ||
1214 // ISSUE: Disallowing abstract&private is no longer appropriate
1215 // in the presence of inner classes. Should it be deleted here?
1216 checkDisjoint(pos, flags,
1217 ABSTRACT,
1218 PRIVATE | STATIC | DEFAULT))
1219 &&
1220 checkDisjoint(pos, flags,
1221 STATIC | PRIVATE,
1222 DEFAULT)
1223 &&
1224 checkDisjoint(pos, flags,
1225 ABSTRACT | INTERFACE,
1226 FINAL | NATIVE | SYNCHRONIZED)
1227 &&
1228 checkDisjoint(pos, flags,
1229 PUBLIC,
1230 PRIVATE | PROTECTED)
1231 &&
1232 checkDisjoint(pos, flags,
1233 PRIVATE,
1234 PUBLIC | PROTECTED)
1235 &&
1236 checkDisjoint(pos, flags,
1237 FINAL,
1238 VOLATILE)
1239 &&
1240 (sym.kind == TYP ||
1241 checkDisjoint(pos, flags,
1242 ABSTRACT | NATIVE,
1243 STRICTFP))
1244 && checkDisjoint(pos, flags,
1245 FINAL,
1246 SEALED | NON_SEALED)
1247 && checkDisjoint(pos, flags,
1248 SEALED,
1249 FINAL | NON_SEALED)
1250 && checkDisjoint(pos, flags,
1251 SEALED,
1252 ANNOTATION)) {
1253 // skip
1254 }
1255 return flags & (mask | ~ExtendedStandardFlags) | implicit;
1256 }
1257
1258 /** Determine if this enum should be implicitly final.
1259 *
1260 * If the enum has no specialized enum constants, it is final.
1261 *
1262 * If the enum does have specialized enum constants, it is
1263 * <i>not</i> final.
1264 */
1265 private long implicitEnumFinalFlag(JCTree tree) {
1266 if (!tree.hasTag(CLASSDEF)) return 0;
1267 class SpecialTreeVisitor extends JCTree.Visitor {
1268 boolean specialized;
1269 SpecialTreeVisitor() {
1270 this.specialized = false;
1271 }
1272
1273 @Override
1274 public void visitTree(JCTree tree) { /* no-op */ }
1275
1276 @Override
1277 public void visitVarDef(JCVariableDecl tree) {
1278 if ((tree.mods.flags & ENUM) != 0) {
1279 if (tree.init instanceof JCNewClass newClass && newClass.def != null) {
1280 specialized = true;
1281 }
1282 }
1283 }
1284 }
1285
1286 SpecialTreeVisitor sts = new SpecialTreeVisitor();
1287 JCClassDecl cdef = (JCClassDecl) tree;
1288 for (JCTree defs: cdef.defs) {
1289 defs.accept(sts);
1290 if (sts.specialized) return allowSealed ? SEALED : 0;
1291 }
1292 return FINAL;
1293 }
1294
1295 /* *************************************************************************
1296 * Type Validation
1297 **************************************************************************/
1298
1299 /** Validate a type expression. That is,
1300 * check that all type arguments of a parametric type are within
1301 * their bounds. This must be done in a second phase after type attribution
1302 * since a class might have a subclass as type parameter bound. E.g:
1303 *
1304 * <pre>{@code
1305 * class B<A extends C> { ... }
1306 * class C extends B<C> { ... }
1307 * }</pre>
1308 *
1309 * and we can't make sure that the bound is already attributed because
1310 * of possible cycles.
1311 *
1312 * Visitor method: Validate a type expression, if it is not null, catching
1313 * and reporting any completion failures.
1314 */
1315 void validate(JCTree tree, Env<AttrContext> env) {
1316 validate(tree, env, true);
1317 }
1318 void validate(JCTree tree, Env<AttrContext> env, boolean checkRaw) {
1319 new Validator(env).validateTree(tree, checkRaw, true);
1320 }
1321
1322 /** Visitor method: Validate a list of type expressions.
1323 */
1324 void validate(List<? extends JCTree> trees, Env<AttrContext> env) {
1325 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
1326 validate(l.head, env);
1327 }
1328
1329 /** A visitor class for type validation.
1330 */
1331 class Validator extends JCTree.Visitor {
1332
1333 boolean checkRaw;
1334 boolean isOuter;
1335 Env<AttrContext> env;
1336
1337 Validator(Env<AttrContext> env) {
1338 this.env = env;
1339 }
1340
1341 @Override
1342 public void visitTypeArray(JCArrayTypeTree tree) {
1343 validateTree(tree.elemtype, checkRaw, isOuter);
1344 }
1345
1346 @Override
1347 public void visitTypeApply(JCTypeApply tree) {
1348 if (tree.type.hasTag(CLASS)) {
1349 List<JCExpression> args = tree.arguments;
1350 List<Type> forms = tree.type.tsym.type.getTypeArguments();
1351
1352 Type incompatibleArg = firstIncompatibleTypeArg(tree.type);
1353 if (incompatibleArg != null) {
1354 for (JCTree arg : tree.arguments) {
1355 if (arg.type == incompatibleArg) {
1356 log.error(arg, Errors.NotWithinBounds(incompatibleArg, forms.head));
1357 }
1358 forms = forms.tail;
1359 }
1360 }
1361
1362 forms = tree.type.tsym.type.getTypeArguments();
1363
1364 boolean is_java_lang_Class = tree.type.tsym.flatName() == names.java_lang_Class;
1365
1366 // For matching pairs of actual argument types `a' and
1367 // formal type parameters with declared bound `b' ...
1368 while (args.nonEmpty() && forms.nonEmpty()) {
1369 validateTree(args.head,
1370 !(isOuter && is_java_lang_Class),
1371 false);
1372 args = args.tail;
1373 forms = forms.tail;
1374 }
1375
1376 // Check that this type is either fully parameterized, or
1377 // not parameterized at all.
1378 if (tree.type.getEnclosingType().isRaw())
1379 log.error(tree.pos(), Errors.ImproperlyFormedTypeInnerRawParam);
1380 if (tree.clazz.hasTag(SELECT))
1381 visitSelectInternal((JCFieldAccess)tree.clazz);
1382 }
1383 }
1384
1385 @Override
1386 public void visitTypeParameter(JCTypeParameter tree) {
1387 validateTrees(tree.bounds, true, isOuter);
1388 checkClassBounds(tree.pos(), tree.type);
1389 }
1390
1391 @Override
1392 public void visitWildcard(JCWildcard tree) {
1393 if (tree.inner != null)
1394 validateTree(tree.inner, true, isOuter);
1395 }
1396
1397 @Override
1398 public void visitSelect(JCFieldAccess tree) {
1399 if (tree.type.hasTag(CLASS)) {
1400 visitSelectInternal(tree);
1401
1402 // Check that this type is either fully parameterized, or
1403 // not parameterized at all.
1404 if (tree.selected.type.isParameterized() && tree.type.tsym.type.getTypeArguments().nonEmpty())
1405 log.error(tree.pos(), Errors.ImproperlyFormedTypeParamMissing);
1406 }
1407 }
1408
1409 public void visitSelectInternal(JCFieldAccess tree) {
1410 if (tree.type.tsym.isStatic() &&
1411 tree.selected.type.isParameterized()) {
1412 // The enclosing type is not a class, so we are
1413 // looking at a static member type. However, the
1414 // qualifying expression is parameterized.
1415 log.error(tree.pos(), Errors.CantSelectStaticClassFromParamType);
1416 } else {
1417 // otherwise validate the rest of the expression
1418 tree.selected.accept(this);
1419 }
1420 }
1421
1422 @Override
1423 public void visitAnnotatedType(JCAnnotatedType tree) {
1424 tree.underlyingType.accept(this);
1425 }
1426
1427 @Override
1428 public void visitTypeIdent(JCPrimitiveTypeTree that) {
1429 if (that.type.hasTag(TypeTag.VOID)) {
1430 log.error(that.pos(), Errors.VoidNotAllowedHere);
1431 }
1432 super.visitTypeIdent(that);
1433 }
1434
1435 /** Default visitor method: do nothing.
1436 */
1437 @Override
1438 public void visitTree(JCTree tree) {
1439 }
1440
1441 public void validateTree(JCTree tree, boolean checkRaw, boolean isOuter) {
1442 if (tree != null) {
1443 boolean prevCheckRaw = this.checkRaw;
1444 this.checkRaw = checkRaw;
1445 this.isOuter = isOuter;
1446
1447 try {
1448 tree.accept(this);
1449 if (checkRaw)
1450 checkRaw(tree, env);
1451 } catch (CompletionFailure ex) {
1452 completionError(tree.pos(), ex);
1453 } finally {
1454 this.checkRaw = prevCheckRaw;
1455 }
1456 }
1457 }
1458
1459 public void validateTrees(List<? extends JCTree> trees, boolean checkRaw, boolean isOuter) {
1460 for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
1461 validateTree(l.head, checkRaw, isOuter);
1462 }
1463 }
1464
1465 void checkRaw(JCTree tree, Env<AttrContext> env) {
1466 if (tree.type.hasTag(CLASS) &&
1467 !TreeInfo.isDiamond(tree) &&
1468 !withinAnonConstr(env) &&
1469 tree.type.isRaw()) {
1470 log.warning(tree.pos(), LintWarnings.RawClassUse(tree.type, tree.type.tsym.type));
1471 }
1472 }
1473 //where
1474 private boolean withinAnonConstr(Env<AttrContext> env) {
1475 return env.enclClass.name.isEmpty() &&
1476 env.enclMethod != null && env.enclMethod.name == names.init;
1477 }
1478
1479 /* *************************************************************************
1480 * Exception checking
1481 **************************************************************************/
1482
1483 /* The following methods treat classes as sets that contain
1484 * the class itself and all their subclasses
1485 */
1486
1487 /** Is given type a subtype of some of the types in given list?
1488 */
1489 boolean subset(Type t, List<Type> ts) {
1490 for (List<Type> l = ts; l.nonEmpty(); l = l.tail)
1491 if (types.isSubtype(t, l.head)) return true;
1492 return false;
1493 }
1494
1495 /** Is given type a subtype or supertype of
1496 * some of the types in given list?
1497 */
1498 boolean intersects(Type t, List<Type> ts) {
1499 for (List<Type> l = ts; l.nonEmpty(); l = l.tail)
1500 if (types.isSubtype(t, l.head) || types.isSubtype(l.head, t)) return true;
1501 return false;
1502 }
1503
1504 /** Add type set to given type list, unless it is a subclass of some class
1505 * in the list.
1506 */
1507 List<Type> incl(Type t, List<Type> ts) {
1508 return subset(t, ts) ? ts : excl(t, ts).prepend(t);
1509 }
1510
1511 /** Remove type set from type set list.
1512 */
1513 List<Type> excl(Type t, List<Type> ts) {
1514 if (ts.isEmpty()) {
1515 return ts;
1516 } else {
1517 List<Type> ts1 = excl(t, ts.tail);
1518 if (types.isSubtype(ts.head, t)) return ts1;
1519 else if (ts1 == ts.tail) return ts;
1520 else return ts1.prepend(ts.head);
1521 }
1522 }
1523
1524 /** Form the union of two type set lists.
1525 */
1526 List<Type> union(List<Type> ts1, List<Type> ts2) {
1527 List<Type> ts = ts1;
1528 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail)
1529 ts = incl(l.head, ts);
1530 return ts;
1531 }
1532
1533 /** Form the difference of two type lists.
1534 */
1535 List<Type> diff(List<Type> ts1, List<Type> ts2) {
1536 List<Type> ts = ts1;
1537 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail)
1538 ts = excl(l.head, ts);
1539 return ts;
1540 }
1541
1542 /** Form the intersection of two type lists.
1543 */
1544 public List<Type> intersect(List<Type> ts1, List<Type> ts2) {
1545 List<Type> ts = List.nil();
1546 for (List<Type> l = ts1; l.nonEmpty(); l = l.tail)
1547 if (subset(l.head, ts2)) ts = incl(l.head, ts);
1548 for (List<Type> l = ts2; l.nonEmpty(); l = l.tail)
1549 if (subset(l.head, ts1)) ts = incl(l.head, ts);
1550 return ts;
1551 }
1552
1553 /** Is exc an exception symbol that need not be declared?
1554 */
1555 boolean isUnchecked(ClassSymbol exc) {
1556 return
1557 exc.kind == ERR ||
1558 exc.isSubClass(syms.errorType.tsym, types) ||
1559 exc.isSubClass(syms.runtimeExceptionType.tsym, types);
1560 }
1561
1562 /** Is exc an exception type that need not be declared?
1563 */
1564 boolean isUnchecked(Type exc) {
1565 return
1566 (exc.hasTag(TYPEVAR)) ? isUnchecked(types.supertype(exc)) :
1567 (exc.hasTag(CLASS)) ? isUnchecked((ClassSymbol)exc.tsym) :
1568 exc.hasTag(BOT);
1569 }
1570
1571 boolean isChecked(Type exc) {
1572 return !isUnchecked(exc);
1573 }
1574
1575 /** Same, but handling completion failures.
1576 */
1577 boolean isUnchecked(DiagnosticPosition pos, Type exc) {
1578 try {
1579 return isUnchecked(exc);
1580 } catch (CompletionFailure ex) {
1581 completionError(pos, ex);
1582 return true;
1583 }
1584 }
1585
1586 /** Is exc handled by given exception list?
1587 */
1588 boolean isHandled(Type exc, List<Type> handled) {
1589 return isUnchecked(exc) || subset(exc, handled);
1590 }
1591
1592 /** Return all exceptions in thrown list that are not in handled list.
1593 * @param thrown The list of thrown exceptions.
1594 * @param handled The list of handled exceptions.
1595 */
1596 List<Type> unhandled(List<Type> thrown, List<Type> handled) {
1597 List<Type> unhandled = List.nil();
1598 for (List<Type> l = thrown; l.nonEmpty(); l = l.tail)
1599 if (!isHandled(l.head, handled)) unhandled = unhandled.prepend(l.head);
1600 return unhandled;
1601 }
1602
1603 /* *************************************************************************
1604 * Overriding/Implementation checking
1605 **************************************************************************/
1606
1607 /** The level of access protection given by a flag set,
1608 * where PRIVATE is highest and PUBLIC is lowest.
1609 */
1610 static int protection(long flags) {
1611 switch ((short)(flags & AccessFlags)) {
1612 case PRIVATE: return 3;
1613 case PROTECTED: return 1;
1614 default:
1615 case PUBLIC: return 0;
1616 case 0: return 2;
1617 }
1618 }
1619
1620 /** A customized "cannot override" error message.
1621 * @param m The overriding method.
1622 * @param other The overridden method.
1623 * @return An internationalized string.
1624 */
1625 Fragment cannotOverride(MethodSymbol m, MethodSymbol other) {
1626 Symbol mloc = m.location();
1627 Symbol oloc = other.location();
1628
1629 if ((other.owner.flags() & INTERFACE) == 0)
1630 return Fragments.CantOverride(m, mloc, other, oloc);
1631 else if ((m.owner.flags() & INTERFACE) == 0)
1632 return Fragments.CantImplement(m, mloc, other, oloc);
1633 else
1634 return Fragments.ClashesWith(m, mloc, other, oloc);
1635 }
1636
1637 /** A customized "override" warning message.
1638 * @param m The overriding method.
1639 * @param other The overridden method.
1640 * @return An internationalized string.
1641 */
1642 Fragment uncheckedOverrides(MethodSymbol m, MethodSymbol other) {
1643 Symbol mloc = m.location();
1644 Symbol oloc = other.location();
1645
1646 if ((other.owner.flags() & INTERFACE) == 0)
1647 return Fragments.UncheckedOverride(m, mloc, other, oloc);
1648 else if ((m.owner.flags() & INTERFACE) == 0)
1649 return Fragments.UncheckedImplement(m, mloc, other, oloc);
1650 else
1651 return Fragments.UncheckedClashWith(m, mloc, other, oloc);
1652 }
1653
1654 /** A customized "override" warning message.
1655 * @param m The overriding method.
1656 * @param other The overridden method.
1657 * @return An internationalized string.
1658 */
1659 Fragment varargsOverrides(MethodSymbol m, MethodSymbol other) {
1660 Symbol mloc = m.location();
1661 Symbol oloc = other.location();
1662
1663 if ((other.owner.flags() & INTERFACE) == 0)
1664 return Fragments.VarargsOverride(m, mloc, other, oloc);
1665 else if ((m.owner.flags() & INTERFACE) == 0)
1666 return Fragments.VarargsImplement(m, mloc, other, oloc);
1667 else
1668 return Fragments.VarargsClashWith(m, mloc, other, oloc);
1669 }
1670
1671 /** Check that this method conforms with overridden method 'other'.
1672 * where `origin' is the class where checking started.
1673 * Complications:
1674 * (1) Do not check overriding of synthetic methods
1675 * (reason: they might be final).
1676 * todo: check whether this is still necessary.
1677 * (2) Admit the case where an interface proxy throws fewer exceptions
1678 * than the method it implements. Augment the proxy methods with the
1679 * undeclared exceptions in this case.
1680 * (3) When generics are enabled, admit the case where an interface proxy
1681 * has a result type
1682 * extended by the result type of the method it implements.
1683 * Change the proxies result type to the smaller type in this case.
1684 *
1685 * @param tree The tree from which positions
1686 * are extracted for errors.
1687 * @param m The overriding method.
1688 * @param other The overridden method.
1689 * @param origin The class of which the overriding method
1690 * is a member.
1691 */
1692 void checkOverride(JCTree tree,
1693 MethodSymbol m,
1694 MethodSymbol other,
1695 ClassSymbol origin) {
1696 // Don't check overriding of synthetic methods or by bridge methods.
1697 if ((m.flags() & (SYNTHETIC|BRIDGE)) != 0 || (other.flags() & SYNTHETIC) != 0) {
1698 return;
1699 }
1700
1701 // Error if static method overrides instance method (JLS 8.4.8.2).
1702 if ((m.flags() & STATIC) != 0 &&
1703 (other.flags() & STATIC) == 0) {
1704 log.error(TreeInfo.diagnosticPositionFor(m, tree),
1705 Errors.OverrideStatic(cannotOverride(m, other)));
1706 m.flags_field |= BAD_OVERRIDE;
1707 return;
1708 }
1709
1710 // Error if instance method overrides static or final
1711 // method (JLS 8.4.8.1).
1712 if ((other.flags() & FINAL) != 0 ||
1713 (m.flags() & STATIC) == 0 &&
1714 (other.flags() & STATIC) != 0) {
1715 log.error(TreeInfo.diagnosticPositionFor(m, tree),
1716 Errors.OverrideMeth(cannotOverride(m, other),
1717 asFlagSet(other.flags() & (FINAL | STATIC))));
1718 m.flags_field |= BAD_OVERRIDE;
1719 return;
1720 }
1721
1722 if ((m.owner.flags() & ANNOTATION) != 0) {
1723 // handled in validateAnnotationMethod
1724 return;
1725 }
1726
1727 // Error if overriding method has weaker access (JLS 8.4.8.3).
1728 if (protection(m.flags()) > protection(other.flags())) {
1729 log.error(TreeInfo.diagnosticPositionFor(m, tree),
1730 (other.flags() & AccessFlags) == 0 ?
1731 Errors.OverrideWeakerAccess(cannotOverride(m, other),
1732 "package") :
1733 Errors.OverrideWeakerAccess(cannotOverride(m, other),
1734 asFlagSet(other.flags() & AccessFlags)));
1735 m.flags_field |= BAD_OVERRIDE;
1736 return;
1737 }
1738
1739 if (shouldCheckPreview(m, other, origin)) {
1740 checkPreview(TreeInfo.diagnosticPositionFor(m, tree),
1741 m, origin.type, other);
1742 }
1743
1744 Type mt = types.memberType(origin.type, m);
1745 Type ot = types.memberType(origin.type, other);
1746 // Error if overriding result type is different
1747 // (or, in the case of generics mode, not a subtype) of
1748 // overridden result type. We have to rename any type parameters
1749 // before comparing types.
1750 List<Type> mtvars = mt.getTypeArguments();
1751 List<Type> otvars = ot.getTypeArguments();
1752 Type mtres = mt.getReturnType();
1753 Type otres = types.subst(ot.getReturnType(), otvars, mtvars);
1754
1755 overrideWarner.clear();
1756 boolean resultTypesOK =
1757 types.returnTypeSubstitutable(mt, ot, otres, overrideWarner);
1758 if (!resultTypesOK) {
1759 if ((m.flags() & STATIC) != 0 && (other.flags() & STATIC) != 0) {
1760 log.error(TreeInfo.diagnosticPositionFor(m, tree),
1761 Errors.OverrideIncompatibleRet(Fragments.CantHide(m, m.location(), other,
1762 other.location()), mtres, otres));
1763 m.flags_field |= BAD_OVERRIDE;
1764 } else {
1765 log.error(TreeInfo.diagnosticPositionFor(m, tree),
1766 Errors.OverrideIncompatibleRet(cannotOverride(m, other), mtres, otres));
1767 m.flags_field |= BAD_OVERRIDE;
1768 }
1769 return;
1770 } else if (overrideWarner.hasNonSilentLint(LintCategory.UNCHECKED)) {
1771 warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree),
1772 LintWarnings.OverrideUncheckedRet(uncheckedOverrides(m, other), mtres, otres));
1773 }
1774
1775 // Error if overriding method throws an exception not reported
1776 // by overridden method.
1777 List<Type> otthrown = types.subst(ot.getThrownTypes(), otvars, mtvars);
1778 List<Type> unhandledErased = unhandled(mt.getThrownTypes(), types.erasure(otthrown));
1779 List<Type> unhandledUnerased = unhandled(mt.getThrownTypes(), otthrown);
1780 if (unhandledErased.nonEmpty()) {
1781 log.error(TreeInfo.diagnosticPositionFor(m, tree),
1782 Errors.OverrideMethDoesntThrow(cannotOverride(m, other), unhandledUnerased.head));
1783 m.flags_field |= BAD_OVERRIDE;
1784 return;
1785 }
1786 else if (unhandledUnerased.nonEmpty()) {
1787 warnUnchecked(TreeInfo.diagnosticPositionFor(m, tree),
1788 LintWarnings.OverrideUncheckedThrown(cannotOverride(m, other), unhandledUnerased.head));
1789 return;
1790 }
1791
1792 // Optional warning if varargs don't agree
1793 if ((((m.flags() ^ other.flags()) & Flags.VARARGS) != 0)) {
1794 log.warning(TreeInfo.diagnosticPositionFor(m, tree),
1795 ((m.flags() & Flags.VARARGS) != 0)
1796 ? LintWarnings.OverrideVarargsMissing(varargsOverrides(m, other))
1797 : LintWarnings.OverrideVarargsExtra(varargsOverrides(m, other)));
1798 }
1799
1800 // Warn if instance method overrides bridge method (compiler spec ??)
1801 if ((other.flags() & BRIDGE) != 0) {
1802 log.warning(TreeInfo.diagnosticPositionFor(m, tree),
1803 Warnings.OverrideBridge(uncheckedOverrides(m, other)));
1804 }
1805
1806 // Warn if a deprecated method overridden by a non-deprecated one.
1807 if (!isDeprecatedOverrideIgnorable(other, origin)) {
1808 checkDeprecated(() -> TreeInfo.diagnosticPositionFor(m, tree), m, other);
1809 }
1810 }
1811 // where
1812 private boolean shouldCheckPreview(MethodSymbol m, MethodSymbol other, ClassSymbol origin) {
1813 if (m.owner != origin ||
1814 //performance - only do the expensive checks when the overridden method is a Preview API:
1815 ((other.flags() & PREVIEW_API) == 0 &&
1816 (other.owner.flags() & PREVIEW_API) == 0)) {
1817 return false;
1818 }
1819
1820 for (Symbol s : types.membersClosure(origin.type, false).getSymbolsByName(m.name)) {
1821 if (m != s && m.overrides(s, origin, types, false)) {
1822 //only produce preview warnings or errors if "m" immediatelly overrides "other"
1823 //without intermediate overriding methods:
1824 return s == other;
1825 }
1826 }
1827
1828 return false;
1829 }
1830 private boolean isDeprecatedOverrideIgnorable(MethodSymbol m, ClassSymbol origin) {
1831 // If the method, m, is defined in an interface, then ignore the issue if the method
1832 // is only inherited via a supertype and also implemented in the supertype,
1833 // because in that case, we will rediscover the issue when examining the method
1834 // in the supertype.
1835 // If the method, m, is not defined in an interface, then the only time we need to
1836 // address the issue is when the method is the supertype implementation: any other
1837 // case, we will have dealt with when examining the supertype classes
1838 ClassSymbol mc = m.enclClass();
1839 Type st = types.supertype(origin.type);
1840 if (!st.hasTag(CLASS))
1841 return true;
1842 MethodSymbol stimpl = m.implementation((ClassSymbol)st.tsym, types, false);
1843
1844 if (mc != null && ((mc.flags() & INTERFACE) != 0)) {
1845 List<Type> intfs = types.interfaces(origin.type);
1846 return (intfs.contains(mc.type) ? false : (stimpl != null));
1847 }
1848 else
1849 return (stimpl != m);
1850 }
1851
1852
1853 // used to check if there were any unchecked conversions
1854 Warner overrideWarner = new Warner();
1855
1856 /** Check that a class does not inherit two concrete methods
1857 * with the same signature.
1858 * @param pos Position to be used for error reporting.
1859 * @param site The class type to be checked.
1860 */
1861 public void checkCompatibleConcretes(DiagnosticPosition pos, Type site) {
1862 Type sup = types.supertype(site);
1863 if (!sup.hasTag(CLASS)) return;
1864
1865 for (Type t1 = sup;
1866 t1.hasTag(CLASS) && t1.tsym.type.isParameterized();
1867 t1 = types.supertype(t1)) {
1868 for (Symbol s1 : t1.tsym.members().getSymbols(NON_RECURSIVE)) {
1869 if (s1.kind != MTH ||
1870 (s1.flags() & (STATIC|SYNTHETIC|BRIDGE)) != 0 ||
1871 !s1.isInheritedIn(site.tsym, types) ||
1872 ((MethodSymbol)s1).implementation(site.tsym,
1873 types,
1874 true) != s1)
1875 continue;
1876 Type st1 = types.memberType(t1, s1);
1877 int s1ArgsLength = st1.getParameterTypes().length();
1878 if (st1 == s1.type) continue;
1879
1880 for (Type t2 = sup;
1881 t2.hasTag(CLASS);
1882 t2 = types.supertype(t2)) {
1883 for (Symbol s2 : t2.tsym.members().getSymbolsByName(s1.name)) {
1884 if (s2 == s1 ||
1885 s2.kind != MTH ||
1886 (s2.flags() & (STATIC|SYNTHETIC|BRIDGE)) != 0 ||
1887 s2.type.getParameterTypes().length() != s1ArgsLength ||
1888 !s2.isInheritedIn(site.tsym, types) ||
1889 ((MethodSymbol)s2).implementation(site.tsym,
1890 types,
1891 true) != s2)
1892 continue;
1893 Type st2 = types.memberType(t2, s2);
1894 if (types.overrideEquivalent(st1, st2))
1895 log.error(pos,
1896 Errors.ConcreteInheritanceConflict(s1, t1, s2, t2, sup));
1897 }
1898 }
1899 }
1900 }
1901 }
1902
1903 /** Check that classes (or interfaces) do not each define an abstract
1904 * method with same name and arguments but incompatible return types.
1905 * @param pos Position to be used for error reporting.
1906 * @param t1 The first argument type.
1907 * @param t2 The second argument type.
1908 */
1909 public boolean checkCompatibleAbstracts(DiagnosticPosition pos,
1910 Type t1,
1911 Type t2,
1912 Type site) {
1913 if ((site.tsym.flags() & COMPOUND) != 0) {
1914 // special case for intersections: need to eliminate wildcards in supertypes
1915 t1 = types.capture(t1);
1916 t2 = types.capture(t2);
1917 }
1918 return firstIncompatibility(pos, t1, t2, site) == null;
1919 }
1920
1921 /** Return the first method which is defined with same args
1922 * but different return types in two given interfaces, or null if none
1923 * exists.
1924 * @param t1 The first type.
1925 * @param t2 The second type.
1926 * @param site The most derived type.
1927 * @return symbol from t2 that conflicts with one in t1.
1928 */
1929 private Symbol firstIncompatibility(DiagnosticPosition pos, Type t1, Type t2, Type site) {
1930 Map<TypeSymbol,Type> interfaces1 = new HashMap<>();
1931 closure(t1, interfaces1);
1932 Map<TypeSymbol,Type> interfaces2;
1933 if (t1 == t2)
1934 interfaces2 = interfaces1;
1935 else
1936 closure(t2, interfaces1, interfaces2 = new HashMap<>());
1937
1938 for (Type t3 : interfaces1.values()) {
1939 for (Type t4 : interfaces2.values()) {
1940 Symbol s = firstDirectIncompatibility(pos, t3, t4, site);
1941 if (s != null) return s;
1942 }
1943 }
1944 return null;
1945 }
1946
1947 /** Compute all the supertypes of t, indexed by type symbol. */
1948 private void closure(Type t, Map<TypeSymbol,Type> typeMap) {
1949 if (!t.hasTag(CLASS)) return;
1950 if (typeMap.put(t.tsym, t) == null) {
1951 closure(types.supertype(t), typeMap);
1952 for (Type i : types.interfaces(t))
1953 closure(i, typeMap);
1954 }
1955 }
1956
1957 /** Compute all the supertypes of t, indexed by type symbol (except those in typesSkip). */
1958 private void closure(Type t, Map<TypeSymbol,Type> typesSkip, Map<TypeSymbol,Type> typeMap) {
1959 if (!t.hasTag(CLASS)) return;
1960 if (typesSkip.get(t.tsym) != null) return;
1961 if (typeMap.put(t.tsym, t) == null) {
1962 closure(types.supertype(t), typesSkip, typeMap);
1963 for (Type i : types.interfaces(t))
1964 closure(i, typesSkip, typeMap);
1965 }
1966 }
1967
1968 /** Return the first method in t2 that conflicts with a method from t1. */
1969 private Symbol firstDirectIncompatibility(DiagnosticPosition pos, Type t1, Type t2, Type site) {
1970 for (Symbol s1 : t1.tsym.members().getSymbols(NON_RECURSIVE)) {
1971 Type st1 = null;
1972 if (s1.kind != MTH || !s1.isInheritedIn(site.tsym, types) ||
1973 (s1.flags() & SYNTHETIC) != 0) continue;
1974 Symbol impl = ((MethodSymbol)s1).implementation(site.tsym, types, false);
1975 if (impl != null && (impl.flags() & ABSTRACT) == 0) continue;
1976 for (Symbol s2 : t2.tsym.members().getSymbolsByName(s1.name)) {
1977 if (s1 == s2) continue;
1978 if (s2.kind != MTH || !s2.isInheritedIn(site.tsym, types) ||
1979 (s2.flags() & SYNTHETIC) != 0) continue;
1980 if (st1 == null) st1 = types.memberType(t1, s1);
1981 Type st2 = types.memberType(t2, s2);
1982 if (types.overrideEquivalent(st1, st2)) {
1983 List<Type> tvars1 = st1.getTypeArguments();
1984 List<Type> tvars2 = st2.getTypeArguments();
1985 Type rt1 = st1.getReturnType();
1986 Type rt2 = types.subst(st2.getReturnType(), tvars2, tvars1);
1987 boolean compat =
1988 types.isSameType(rt1, rt2) ||
1989 !rt1.isPrimitiveOrVoid() &&
1990 !rt2.isPrimitiveOrVoid() &&
1991 (types.covariantReturnType(rt1, rt2, types.noWarnings) ||
1992 types.covariantReturnType(rt2, rt1, types.noWarnings)) ||
1993 checkCommonOverriderIn(s1,s2,site);
1994 if (!compat) {
1995 if (types.isSameType(t1, t2)) {
1996 log.error(pos, Errors.IncompatibleDiffRetSameType(t1,
1997 s2.name, types.memberType(t2, s2).getParameterTypes()));
1998 } else {
1999 log.error(pos, Errors.TypesIncompatible(t1, t2,
2000 Fragments.IncompatibleDiffRet(s2.name, types.memberType(t2, s2).getParameterTypes())));
2001 }
2002 return s2;
2003 }
2004 } else if (checkNameClash((ClassSymbol)site.tsym, s1, s2) &&
2005 !checkCommonOverriderIn(s1, s2, site)) {
2006 log.error(pos, Errors.NameClashSameErasureNoOverride(
2007 s1.name, types.memberType(site, s1).asMethodType().getParameterTypes(), s1.location(),
2008 s2.name, types.memberType(site, s2).asMethodType().getParameterTypes(), s2.location()));
2009 return s2;
2010 }
2011 }
2012 }
2013 return null;
2014 }
2015 //WHERE
2016 boolean checkCommonOverriderIn(Symbol s1, Symbol s2, Type site) {
2017 Map<TypeSymbol,Type> supertypes = new HashMap<>();
2018 Type st1 = types.memberType(site, s1);
2019 Type st2 = types.memberType(site, s2);
2020 closure(site, supertypes);
2021 for (Type t : supertypes.values()) {
2022 for (Symbol s3 : t.tsym.members().getSymbolsByName(s1.name)) {
2023 if (s3 == s1 || s3 == s2 || s3.kind != MTH || (s3.flags() & (BRIDGE|SYNTHETIC)) != 0) continue;
2024 Type st3 = types.memberType(site,s3);
2025 if (types.overrideEquivalent(st3, st1) &&
2026 types.overrideEquivalent(st3, st2) &&
2027 types.returnTypeSubstitutable(st3, st1) &&
2028 types.returnTypeSubstitutable(st3, st2)) {
2029 return true;
2030 }
2031 }
2032 }
2033 return false;
2034 }
2035
2036 /** Check that a given method conforms with any method it overrides.
2037 * @param tree The tree from which positions are extracted
2038 * for errors.
2039 * @param m The overriding method.
2040 */
2041 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2042 ClassSymbol origin = (ClassSymbol)m.owner;
2043 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2044 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2045 log.error(tree.pos(), Errors.EnumNoFinalize);
2046 return;
2047 }
2048 }
2049 if (allowRecords && origin.isRecord()) {
2050 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2051 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2052 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2053 if (recordComponent.isPresent()) {
2054 return;
2055 }
2056 }
2057
2058 for (Type t = origin.type; t.hasTag(CLASS);
2059 t = types.supertype(t)) {
2060 if (t != origin.type) {
2061 checkOverride(tree, t, origin, m);
2062 }
2063 for (Type t2 : types.interfaces(t)) {
2064 checkOverride(tree, t2, origin, m);
2065 }
2066 }
2067
2068 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
2069 // Check if this method must override a super method due to being annotated with @Override
2070 // or by virtue of being a member of a diamond inferred anonymous class. Latter case is to
2071 // be treated "as if as they were annotated" with @Override.
2072 boolean mustOverride = explicitOverride ||
2073 (env.info.isAnonymousDiamond && !m.isConstructor() && !m.isPrivate());
2074 if (mustOverride && !isOverrider(m)) {
2075 DiagnosticPosition pos = tree.pos();
2076 for (JCAnnotation a : tree.getModifiers().annotations) {
2077 if (a.annotationType.type.tsym == syms.overrideType.tsym) {
2078 pos = a.pos();
2079 break;
2080 }
2081 }
2082 log.error(pos,
2083 explicitOverride ? (m.isStatic() ? Errors.StaticMethodsCannotBeAnnotatedWithOverride : Errors.MethodDoesNotOverrideSuperclass) :
2084 Errors.AnonymousDiamondMethodDoesNotOverrideSuperclass(Fragments.DiamondAnonymousMethodsImplicitlyOverride));
2085 }
2086 }
2087
2088 void checkOverride(JCTree tree, Type site, ClassSymbol origin, MethodSymbol m) {
2089 TypeSymbol c = site.tsym;
2090 for (Symbol sym : c.members().getSymbolsByName(m.name)) {
2091 if (m.overrides(sym, origin, types, false)) {
2092 if ((sym.flags() & ABSTRACT) == 0) {
2093 checkOverride(tree, m, (MethodSymbol)sym, origin);
2094 }
2095 }
2096 }
2097 }
2098
2099 private Predicate<Symbol> equalsHasCodeFilter = s -> MethodSymbol.implementation_filter.test(s) &&
2100 (s.flags() & BAD_OVERRIDE) == 0;
2101
2102 public void checkClassOverrideEqualsAndHashIfNeeded(DiagnosticPosition pos,
2103 ClassSymbol someClass) {
2104 /* At present, annotations cannot possibly have a method that is override
2105 * equivalent with Object.equals(Object) but in any case the condition is
2106 * fine for completeness.
2107 */
2108 if (someClass == (ClassSymbol)syms.objectType.tsym ||
2109 someClass.isInterface() || someClass.isEnum() ||
2110 (someClass.flags() & ANNOTATION) != 0 ||
2111 (someClass.flags() & ABSTRACT) != 0) return;
2112 //anonymous inner classes implementing interfaces need especial treatment
2113 if (someClass.isAnonymous()) {
2114 List<Type> interfaces = types.interfaces(someClass.type);
2115 if (interfaces != null && !interfaces.isEmpty() &&
2116 interfaces.head.tsym == syms.comparatorType.tsym) return;
2117 }
2118 checkClassOverrideEqualsAndHash(pos, someClass);
2119 }
2120
2121 private void checkClassOverrideEqualsAndHash(DiagnosticPosition pos,
2122 ClassSymbol someClass) {
2123 if (lint.isEnabled(LintCategory.OVERRIDES)) {
2124 MethodSymbol equalsAtObject = (MethodSymbol)syms.objectType
2125 .tsym.members().findFirst(names.equals);
2126 MethodSymbol hashCodeAtObject = (MethodSymbol)syms.objectType
2127 .tsym.members().findFirst(names.hashCode);
2128 MethodSymbol equalsImpl = types.implementation(equalsAtObject,
2129 someClass, false, equalsHasCodeFilter);
2130 boolean overridesEquals = equalsImpl != null &&
2131 equalsImpl.owner == someClass;
2132 boolean overridesHashCode = types.implementation(hashCodeAtObject,
2133 someClass, false, equalsHasCodeFilter) != hashCodeAtObject;
2134
2135 if (overridesEquals && !overridesHashCode) {
2136 log.warning(pos,
2137 LintWarnings.OverrideEqualsButNotHashcode(someClass));
2138 }
2139 }
2140 }
2141
2142 public void checkHasMain(DiagnosticPosition pos, ClassSymbol c) {
2143 boolean found = false;
2144
2145 for (Symbol sym : c.members().getSymbolsByName(names.main)) {
2146 if (sym.kind == MTH && (sym.flags() & PRIVATE) == 0) {
2147 MethodSymbol meth = (MethodSymbol)sym;
2148 if (!types.isSameType(meth.getReturnType(), syms.voidType)) {
2149 continue;
2150 }
2151 if (meth.params.isEmpty()) {
2152 found = true;
2153 break;
2154 }
2155 if (meth.params.size() != 1) {
2156 continue;
2157 }
2158 if (!types.isSameType(meth.params.head.type, types.makeArrayType(syms.stringType))) {
2159 continue;
2160 }
2161
2162 found = true;
2163 break;
2164 }
2165 }
2166
2167 if (!found) {
2168 log.error(pos, Errors.ImplicitClassDoesNotHaveMainMethod);
2169 }
2170 }
2171
2172 public void checkModuleName (JCModuleDecl tree) {
2173 Name moduleName = tree.sym.name;
2174 Assert.checkNonNull(moduleName);
2175 if (lint.isEnabled(LintCategory.MODULE)) {
2176 JCExpression qualId = tree.qualId;
2177 while (qualId != null) {
2178 Name componentName;
2179 DiagnosticPosition pos;
2180 switch (qualId.getTag()) {
2181 case SELECT:
2182 JCFieldAccess selectNode = ((JCFieldAccess) qualId);
2183 componentName = selectNode.name;
2184 pos = selectNode.pos();
2185 qualId = selectNode.selected;
2186 break;
2187 case IDENT:
2188 componentName = ((JCIdent) qualId).name;
2189 pos = qualId.pos();
2190 qualId = null;
2191 break;
2192 default:
2193 throw new AssertionError("Unexpected qualified identifier: " + qualId.toString());
2194 }
2195 if (componentName != null) {
2196 String moduleNameComponentString = componentName.toString();
2197 int nameLength = moduleNameComponentString.length();
2198 if (nameLength > 0 && Character.isDigit(moduleNameComponentString.charAt(nameLength - 1))) {
2199 log.warning(pos, LintWarnings.PoorChoiceForModuleName(componentName));
2200 }
2201 }
2202 }
2203 }
2204 }
2205
2206 private boolean checkNameClash(ClassSymbol origin, Symbol s1, Symbol s2) {
2207 ClashFilter cf = new ClashFilter(origin.type);
2208 return (cf.test(s1) &&
2209 cf.test(s2) &&
2210 types.hasSameArgs(s1.erasure(types), s2.erasure(types)));
2211 }
2212
2213
2214 /** Check that all abstract members of given class have definitions.
2215 * @param pos Position to be used for error reporting.
2216 * @param c The class.
2217 */
2218 void checkAllDefined(DiagnosticPosition pos, ClassSymbol c) {
2219 MethodSymbol undef = types.firstUnimplementedAbstract(c);
2220 if (undef != null) {
2221 MethodSymbol undef1 =
2222 new MethodSymbol(undef.flags(), undef.name,
2223 types.memberType(c.type, undef), undef.owner);
2224 log.error(pos,
2225 Errors.DoesNotOverrideAbstract(c, undef1, undef1.location()));
2226 }
2227 }
2228
2229 void checkNonCyclicDecl(JCClassDecl tree) {
2230 CycleChecker cc = new CycleChecker();
2231 cc.scan(tree);
2232 if (!cc.errorFound && !cc.partialCheck) {
2233 tree.sym.flags_field |= ACYCLIC;
2234 }
2235 }
2236
2237 class CycleChecker extends TreeScanner {
2238
2239 Set<Symbol> seenClasses = new HashSet<>();
2240 boolean errorFound = false;
2241 boolean partialCheck = false;
2242
2243 private void checkSymbol(DiagnosticPosition pos, Symbol sym) {
2244 if (sym != null && sym.kind == TYP) {
2245 Env<AttrContext> classEnv = enter.getEnv((TypeSymbol)sym);
2246 if (classEnv != null) {
2247 DiagnosticSource prevSource = log.currentSource();
2248 try {
2249 log.useSource(classEnv.toplevel.sourcefile);
2250 scan(classEnv.tree);
2251 }
2252 finally {
2253 log.useSource(prevSource.getFile());
2254 }
2255 } else if (sym.kind == TYP) {
2256 checkClass(pos, sym, List.nil());
2257 }
2258 } else if (sym == null || sym.kind != PCK) {
2259 //not completed yet
2260 partialCheck = true;
2261 }
2262 }
2263
2264 @Override
2265 public void visitSelect(JCFieldAccess tree) {
2266 super.visitSelect(tree);
2267 checkSymbol(tree.pos(), tree.sym);
2268 }
2269
2270 @Override
2271 public void visitIdent(JCIdent tree) {
2272 checkSymbol(tree.pos(), tree.sym);
2273 }
2274
2275 @Override
2276 public void visitTypeApply(JCTypeApply tree) {
2277 scan(tree.clazz);
2278 }
2279
2280 @Override
2281 public void visitTypeArray(JCArrayTypeTree tree) {
2282 scan(tree.elemtype);
2283 }
2284
2285 @Override
2286 public void visitClassDef(JCClassDecl tree) {
2287 List<JCTree> supertypes = List.nil();
2288 if (tree.getExtendsClause() != null) {
2289 supertypes = supertypes.prepend(tree.getExtendsClause());
2290 }
2291 if (tree.getImplementsClause() != null) {
2292 for (JCTree intf : tree.getImplementsClause()) {
2293 supertypes = supertypes.prepend(intf);
2294 }
2295 }
2296 checkClass(tree.pos(), tree.sym, supertypes);
2297 }
2298
2299 void checkClass(DiagnosticPosition pos, Symbol c, List<JCTree> supertypes) {
2300 if ((c.flags_field & ACYCLIC) != 0)
2301 return;
2302 if (seenClasses.contains(c)) {
2303 errorFound = true;
2304 log.error(pos, Errors.CyclicInheritance(c));
2305 seenClasses.stream()
2306 .filter(s -> !s.type.isErroneous())
2307 .filter(ClassSymbol.class::isInstance)
2308 .map(ClassSymbol.class::cast)
2309 .forEach(Check.this::handleCyclic);
2310 } else if (!c.type.isErroneous()) {
2311 try {
2312 seenClasses.add(c);
2313 if (c.type.hasTag(CLASS)) {
2314 if (supertypes.nonEmpty()) {
2315 scan(supertypes);
2316 }
2317 else {
2318 ClassType ct = (ClassType)c.type;
2319 if (ct.supertype_field == null ||
2320 ct.interfaces_field == null) {
2321 //not completed yet
2322 partialCheck = true;
2323 return;
2324 }
2325 checkSymbol(pos, ct.supertype_field.tsym);
2326 for (Type intf : ct.interfaces_field) {
2327 checkSymbol(pos, intf.tsym);
2328 }
2329 }
2330 if (c.owner.kind == TYP) {
2331 checkSymbol(pos, c.owner);
2332 }
2333 }
2334 } finally {
2335 seenClasses.remove(c);
2336 }
2337 }
2338 }
2339 }
2340
2341 /** Check for cyclic references. Issue an error if the
2342 * symbol of the type referred to has a LOCKED flag set.
2343 *
2344 * @param pos Position to be used for error reporting.
2345 * @param t The type referred to.
2346 */
2347 void checkNonCyclic(DiagnosticPosition pos, Type t) {
2348 checkNonCyclicInternal(pos, t);
2349 }
2350
2351
2352 void checkNonCyclic(DiagnosticPosition pos, TypeVar t) {
2353 checkNonCyclic1(pos, t, List.nil());
2354 }
2355
2356 private void checkNonCyclic1(DiagnosticPosition pos, Type t, List<TypeVar> seen) {
2357 final TypeVar tv;
2358 if (t.hasTag(TYPEVAR) && (t.tsym.flags() & UNATTRIBUTED) != 0)
2359 return;
2360 if (seen.contains(t)) {
2361 tv = (TypeVar)t;
2362 tv.setUpperBound(types.createErrorType(t));
2363 log.error(pos, Errors.CyclicInheritance(t));
2364 } else if (t.hasTag(TYPEVAR)) {
2365 tv = (TypeVar)t;
2366 seen = seen.prepend(tv);
2367 for (Type b : types.getBounds(tv))
2368 checkNonCyclic1(pos, b, seen);
2369 }
2370 }
2371
2372 /** Check for cyclic references. Issue an error if the
2373 * symbol of the type referred to has a LOCKED flag set.
2374 *
2375 * @param pos Position to be used for error reporting.
2376 * @param t The type referred to.
2377 * @return True if the check completed on all attributed classes
2378 */
2379 private boolean checkNonCyclicInternal(DiagnosticPosition pos, Type t) {
2380 boolean complete = true; // was the check complete?
2381 //- System.err.println("checkNonCyclicInternal("+t+");");//DEBUG
2382 Symbol c = t.tsym;
2383 if ((c.flags_field & ACYCLIC) != 0) return true;
2384
2385 if ((c.flags_field & LOCKED) != 0) {
2386 log.error(pos, Errors.CyclicInheritance(c));
2387 handleCyclic((ClassSymbol)c);
2388 } else if (!c.type.isErroneous()) {
2389 try {
2390 c.flags_field |= LOCKED;
2391 if (c.type.hasTag(CLASS)) {
2392 ClassType clazz = (ClassType)c.type;
2393 if (clazz.interfaces_field != null)
2394 for (List<Type> l=clazz.interfaces_field; l.nonEmpty(); l=l.tail)
2395 complete &= checkNonCyclicInternal(pos, l.head);
2396 if (clazz.supertype_field != null) {
2397 Type st = clazz.supertype_field;
2398 if (st != null && st.hasTag(CLASS))
2399 complete &= checkNonCyclicInternal(pos, st);
2400 }
2401 if (c.owner.kind == TYP)
2402 complete &= checkNonCyclicInternal(pos, c.owner.type);
2403 }
2404 } finally {
2405 c.flags_field &= ~LOCKED;
2406 }
2407 }
2408 if (complete)
2409 complete = ((c.flags_field & UNATTRIBUTED) == 0) && c.isCompleted();
2410 if (complete) c.flags_field |= ACYCLIC;
2411 return complete;
2412 }
2413
2414 /** Handle finding an inheritance cycle on a class by setting
2415 * the class' and its supertypes' types to the error type.
2416 **/
2417 private void handleCyclic(ClassSymbol c) {
2418 for (List<Type> l=types.interfaces(c.type); l.nonEmpty(); l=l.tail)
2419 l.head = types.createErrorType((ClassSymbol)l.head.tsym, Type.noType);
2420 Type st = types.supertype(c.type);
2421 if (st.hasTag(CLASS))
2422 ((ClassType)c.type).supertype_field = types.createErrorType((ClassSymbol)st.tsym, Type.noType);
2423 c.type = types.createErrorType(c, c.type);
2424 c.flags_field |= ACYCLIC;
2425 }
2426
2427 /** Check that all methods which implement some
2428 * method conform to the method they implement.
2429 * @param tree The class definition whose members are checked.
2430 */
2431 void checkImplementations(JCClassDecl tree) {
2432 checkImplementations(tree, tree.sym, tree.sym);
2433 }
2434 //where
2435 /** Check that all methods which implement some
2436 * method in `ic' conform to the method they implement.
2437 */
2438 void checkImplementations(JCTree tree, ClassSymbol origin, ClassSymbol ic) {
2439 for (List<Type> l = types.closure(ic.type); l.nonEmpty(); l = l.tail) {
2440 ClassSymbol lc = (ClassSymbol)l.head.tsym;
2441 if ((lc.flags() & ABSTRACT) != 0) {
2442 for (Symbol sym : lc.members().getSymbols(NON_RECURSIVE)) {
2443 if (sym.kind == MTH &&
2444 (sym.flags() & (STATIC|ABSTRACT)) == ABSTRACT) {
2445 MethodSymbol absmeth = (MethodSymbol)sym;
2446 MethodSymbol implmeth = absmeth.implementation(origin, types, false);
2447 if (implmeth != null && implmeth != absmeth &&
2448 (implmeth.owner.flags() & INTERFACE) ==
2449 (origin.flags() & INTERFACE)) {
2450 // don't check if implmeth is in a class, yet
2451 // origin is an interface. This case arises only
2452 // if implmeth is declared in Object. The reason is
2453 // that interfaces really don't inherit from
2454 // Object it's just that the compiler represents
2455 // things that way.
2456 checkOverride(tree, implmeth, absmeth, origin);
2457 }
2458 }
2459 }
2460 }
2461 }
2462 }
2463
2464 /** Check that all abstract methods implemented by a class are
2465 * mutually compatible.
2466 * @param pos Position to be used for error reporting.
2467 * @param c The class whose interfaces are checked.
2468 */
2469 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2470 List<Type> supertypes = types.interfaces(c);
2471 Type supertype = types.supertype(c);
2472 if (supertype.hasTag(CLASS) &&
2473 (supertype.tsym.flags() & ABSTRACT) != 0)
2474 supertypes = supertypes.prepend(supertype);
2475 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2476 if (!l.head.getTypeArguments().isEmpty() &&
2477 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2478 return;
2479 for (List<Type> m = supertypes; m != l; m = m.tail)
2480 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2481 return;
2482 }
2483 checkCompatibleConcretes(pos, c);
2484 }
2485
2486 /** Check that all non-override equivalent methods accessible from 'site'
2487 * are mutually compatible (JLS 8.4.8/9.4.1).
2488 *
2489 * @param pos Position to be used for error reporting.
2490 * @param site The class whose methods are checked.
2491 * @param sym The method symbol to be checked.
2492 */
2493 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2494 ClashFilter cf = new ClashFilter(site);
2495 //for each method m1 that is overridden (directly or indirectly)
2496 //by method 'sym' in 'site'...
2497
2498 ArrayList<Symbol> symbolsByName = new ArrayList<>();
2499 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2500 for (Symbol m1 : symbolsByName) {
2501 if (!sym.overrides(m1, site.tsym, types, false)) {
2502 continue;
2503 }
2504
2505 //...check each method m2 that is a member of 'site'
2506 for (Symbol m2 : symbolsByName) {
2507 if (m2 == m1) continue;
2508 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as
2509 //a member of 'site') and (ii) m1 has the same erasure as m2, issue an error
2510 if (!types.isSubSignature(sym.type, types.memberType(site, m2)) &&
2511 types.hasSameArgs(m2.erasure(types), m1.erasure(types))) {
2512 sym.flags_field |= CLASH;
2513 if (m1 == sym) {
2514 log.error(pos, Errors.NameClashSameErasureNoOverride(
2515 m1.name, types.memberType(site, m1).asMethodType().getParameterTypes(), m1.location(),
2516 m2.name, types.memberType(site, m2).asMethodType().getParameterTypes(), m2.location()));
2517 } else {
2518 ClassType ct = (ClassType)site;
2519 String kind = ct.isInterface() ? "interface" : "class";
2520 log.error(pos, Errors.NameClashSameErasureNoOverride1(
2521 kind,
2522 ct.tsym.name,
2523 m1.name,
2524 types.memberType(site, m1).asMethodType().getParameterTypes(),
2525 m1.location(),
2526 m2.name,
2527 types.memberType(site, m2).asMethodType().getParameterTypes(),
2528 m2.location()));
2529 }
2530 return;
2531 }
2532 }
2533 }
2534 }
2535
2536 /** Check that all static methods accessible from 'site' are
2537 * mutually compatible (JLS 8.4.8).
2538 *
2539 * @param pos Position to be used for error reporting.
2540 * @param site The class whose methods are checked.
2541 * @param sym The method symbol to be checked.
2542 */
2543 void checkHideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2544 ClashFilter cf = new ClashFilter(site);
2545 //for each method m1 that is a member of 'site'...
2546 for (Symbol s : types.membersClosure(site, true).getSymbolsByName(sym.name, cf)) {
2547 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as
2548 //a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error
2549 if (!types.isSubSignature(sym.type, types.memberType(site, s))) {
2550 if (types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
2551 log.error(pos,
2552 Errors.NameClashSameErasureNoHide(sym, sym.location(), s, s.location()));
2553 return;
2554 }
2555 }
2556 }
2557 }
2558
2559 //where
2560 private class ClashFilter implements Predicate<Symbol> {
2561
2562 Type site;
2563
2564 ClashFilter(Type site) {
2565 this.site = site;
2566 }
2567
2568 boolean shouldSkip(Symbol s) {
2569 return (s.flags() & CLASH) != 0 &&
2570 s.owner == site.tsym;
2571 }
2572
2573 @Override
2574 public boolean test(Symbol s) {
2575 return s.kind == MTH &&
2576 (s.flags() & SYNTHETIC) == 0 &&
2577 !shouldSkip(s) &&
2578 s.isInheritedIn(site.tsym, types) &&
2579 !s.isConstructor();
2580 }
2581 }
2582
2583 void checkDefaultMethodClashes(DiagnosticPosition pos, Type site) {
2584 DefaultMethodClashFilter dcf = new DefaultMethodClashFilter(site);
2585 for (Symbol m : types.membersClosure(site, false).getSymbols(dcf)) {
2586 Assert.check(m.kind == MTH);
2587 List<MethodSymbol> prov = types.interfaceCandidates(site, (MethodSymbol)m);
2588 if (prov.size() > 1) {
2589 ListBuffer<Symbol> abstracts = new ListBuffer<>();
2590 ListBuffer<Symbol> defaults = new ListBuffer<>();
2591 for (MethodSymbol provSym : prov) {
2592 if ((provSym.flags() & DEFAULT) != 0) {
2593 defaults = defaults.append(provSym);
2594 } else if ((provSym.flags() & ABSTRACT) != 0) {
2595 abstracts = abstracts.append(provSym);
2596 }
2597 if (defaults.nonEmpty() && defaults.size() + abstracts.size() >= 2) {
2598 //strong semantics - issue an error if two sibling interfaces
2599 //have two override-equivalent defaults - or if one is abstract
2600 //and the other is default
2601 Fragment diagKey;
2602 Symbol s1 = defaults.first();
2603 Symbol s2;
2604 if (defaults.size() > 1) {
2605 s2 = defaults.toList().tail.head;
2606 diagKey = Fragments.IncompatibleUnrelatedDefaults(Kinds.kindName(site.tsym), site,
2607 m.name, types.memberType(site, m).getParameterTypes(),
2608 s1.location(), s2.location());
2609
2610 } else {
2611 s2 = abstracts.first();
2612 diagKey = Fragments.IncompatibleAbstractDefault(Kinds.kindName(site.tsym), site,
2613 m.name, types.memberType(site, m).getParameterTypes(),
2614 s1.location(), s2.location());
2615 }
2616 log.error(pos, Errors.TypesIncompatible(s1.location().type, s2.location().type, diagKey));
2617 break;
2618 }
2619 }
2620 }
2621 }
2622 }
2623
2624 //where
2625 private class DefaultMethodClashFilter implements Predicate<Symbol> {
2626
2627 Type site;
2628
2629 DefaultMethodClashFilter(Type site) {
2630 this.site = site;
2631 }
2632
2633 @Override
2634 public boolean test(Symbol s) {
2635 return s.kind == MTH &&
2636 (s.flags() & DEFAULT) != 0 &&
2637 s.isInheritedIn(site.tsym, types) &&
2638 !s.isConstructor();
2639 }
2640 }
2641
2642 /** Report warnings for potentially ambiguous method declarations in the given site. */
2643 void checkPotentiallyAmbiguousOverloads(JCClassDecl tree, Type site) {
2644
2645 // Skip if warning not enabled
2646 if (!lint.isEnabled(LintCategory.OVERLOADS))
2647 return;
2648
2649 // Gather all of site's methods, including overridden methods, grouped by name (except Object methods)
2650 List<java.util.List<MethodSymbol>> methodGroups = methodsGroupedByName(site,
2651 new PotentiallyAmbiguousFilter(site), ArrayList::new);
2652
2653 // Build the predicate that determines if site is responsible for an ambiguity
2654 BiPredicate<MethodSymbol, MethodSymbol> responsible = buildResponsiblePredicate(site, methodGroups);
2655
2656 // Now remove overridden methods from each group, leaving only site's actual members
2657 methodGroups.forEach(list -> removePreempted(list, (m1, m2) -> m1.overrides(m2, site.tsym, types, false)));
2658
2659 // Allow site's own declared methods (only) to apply @SuppressWarnings("overloads")
2660 methodGroups.forEach(list -> list.removeIf(
2661 m -> m.owner == site.tsym && !lint.augment(m).isEnabled(LintCategory.OVERLOADS)));
2662
2663 // Warn about ambiguous overload method pairs for which site is responsible
2664 methodGroups.forEach(list -> compareAndRemove(list, (m1, m2) -> {
2665
2666 // See if this is an ambiguous overload for which "site" is responsible
2667 if (!potentiallyAmbiguousOverload(site, m1, m2) || !responsible.test(m1, m2))
2668 return 0;
2669
2670 // Locate the warning at one of the methods, if possible
2671 DiagnosticPosition pos =
2672 m1.owner == site.tsym ? TreeInfo.diagnosticPositionFor(m1, tree) :
2673 m2.owner == site.tsym ? TreeInfo.diagnosticPositionFor(m2, tree) :
2674 tree.pos();
2675
2676 // Log the warning
2677 log.warning(pos,
2678 LintWarnings.PotentiallyAmbiguousOverload(
2679 m1.asMemberOf(site, types), m1.location(),
2680 m2.asMemberOf(site, types), m2.location()));
2681
2682 // Don't warn again for either of these two methods
2683 return FIRST | SECOND;
2684 }));
2685 }
2686
2687 /** Build a predicate that determines, given two methods that are members of the given class,
2688 * whether the class should be held "responsible" if the methods are potentially ambiguous.
2689 *
2690 * Sometimes ambiguous methods are unavoidable because they're inherited from a supertype.
2691 * For example, any subtype of Spliterator.OfInt will have ambiguities for both
2692 * forEachRemaining() and tryAdvance() (in both cases the overloads are IntConsumer and
2693 * Consumer<? super Integer>). So we only want to "blame" a class when that class is
2694 * itself responsible for creating the ambiguity. We declare that a class C is "responsible"
2695 * for the ambiguity between two methods m1 and m2 if there is no direct supertype T of C
2696 * such that m1 and m2, or some overrides thereof, both exist in T and are ambiguous in T.
2697 * As an optimization, we first check if either method is declared in C and does not override
2698 * any other methods; in this case the class is definitely responsible.
2699 */
2700 BiPredicate<MethodSymbol, MethodSymbol> buildResponsiblePredicate(Type site,
2701 List<? extends Collection<MethodSymbol>> methodGroups) {
2702
2703 // Define the "overrides" predicate
2704 BiPredicate<MethodSymbol, MethodSymbol> overrides = (m1, m2) -> m1.overrides(m2, site.tsym, types, false);
2705
2706 // Map each method declared in site to a list of the supertype method(s) it directly overrides
2707 HashMap<MethodSymbol, ArrayList<MethodSymbol>> overriddenMethodsMap = new HashMap<>();
2708 methodGroups.forEach(list -> {
2709 for (MethodSymbol m : list) {
2710
2711 // Skip methods not declared in site
2712 if (m.owner != site.tsym)
2713 continue;
2714
2715 // Gather all supertype methods overridden by m, directly or indirectly
2716 ArrayList<MethodSymbol> overriddenMethods = list.stream()
2717 .filter(m2 -> m2 != m && overrides.test(m, m2))
2718 .collect(Collectors.toCollection(ArrayList::new));
2719
2720 // Eliminate non-direct overrides
2721 removePreempted(overriddenMethods, overrides);
2722
2723 // Add to map
2724 overriddenMethodsMap.put(m, overriddenMethods);
2725 }
2726 });
2727
2728 // Build the predicate
2729 return (m1, m2) -> {
2730
2731 // Get corresponding supertype methods (if declared in site)
2732 java.util.List<MethodSymbol> overriddenMethods1 = overriddenMethodsMap.get(m1);
2733 java.util.List<MethodSymbol> overriddenMethods2 = overriddenMethodsMap.get(m2);
2734
2735 // Quick check for the case where a method was added by site itself
2736 if (overriddenMethods1 != null && overriddenMethods1.isEmpty())
2737 return true;
2738 if (overriddenMethods2 != null && overriddenMethods2.isEmpty())
2739 return true;
2740
2741 // Get each method's corresponding method(s) from supertypes of site
2742 java.util.List<MethodSymbol> supertypeMethods1 = overriddenMethods1 != null ?
2743 overriddenMethods1 : Collections.singletonList(m1);
2744 java.util.List<MethodSymbol> supertypeMethods2 = overriddenMethods2 != null ?
2745 overriddenMethods2 : Collections.singletonList(m2);
2746
2747 // See if we can blame some direct supertype instead
2748 return types.directSupertypes(site).stream()
2749 .filter(stype -> stype != syms.objectType)
2750 .map(stype -> stype.tsym.type) // view supertype in its original form
2751 .noneMatch(stype -> {
2752 for (MethodSymbol sm1 : supertypeMethods1) {
2753 if (!types.isSubtype(types.erasure(stype), types.erasure(sm1.owner.type)))
2754 continue;
2755 for (MethodSymbol sm2 : supertypeMethods2) {
2756 if (!types.isSubtype(types.erasure(stype), types.erasure(sm2.owner.type)))
2757 continue;
2758 if (potentiallyAmbiguousOverload(stype, sm1, sm2))
2759 return true;
2760 }
2761 }
2762 return false;
2763 });
2764 };
2765 }
2766
2767 /** Gather all of site's methods, including overridden methods, grouped and sorted by name,
2768 * after applying the given filter.
2769 */
2770 <C extends Collection<MethodSymbol>> List<C> methodsGroupedByName(Type site,
2771 Predicate<Symbol> filter, Supplier<? extends C> groupMaker) {
2772 Iterable<Symbol> symbols = types.membersClosure(site, false).getSymbols(filter, RECURSIVE);
2773 return StreamSupport.stream(symbols.spliterator(), false)
2774 .map(MethodSymbol.class::cast)
2775 .collect(Collectors.groupingBy(m -> m.name, Collectors.toCollection(groupMaker)))
2776 .entrySet()
2777 .stream()
2778 .sorted(Comparator.comparing(e -> e.getKey().toString()))
2779 .map(Map.Entry::getValue)
2780 .collect(List.collector());
2781 }
2782
2783 /** Compare elements in a list pair-wise in order to remove some of them.
2784 * @param list mutable list of items
2785 * @param comparer returns flag bit(s) to remove FIRST and/or SECOND
2786 */
2787 <T> void compareAndRemove(java.util.List<T> list, ToIntBiFunction<? super T, ? super T> comparer) {
2788 for (int index1 = 0; index1 < list.size() - 1; index1++) {
2789 T item1 = list.get(index1);
2790 for (int index2 = index1 + 1; index2 < list.size(); index2++) {
2791 T item2 = list.get(index2);
2792 int flags = comparer.applyAsInt(item1, item2);
2793 if ((flags & SECOND) != 0)
2794 list.remove(index2--); // remove item2
2795 if ((flags & FIRST) != 0) {
2796 list.remove(index1--); // remove item1
2797 break;
2798 }
2799 }
2800 }
2801 }
2802
2803 /** Remove elements in a list that are preempted by some other element in the list.
2804 * @param list mutable list of items
2805 * @param preempts decides if one item preempts another, causing the second one to be removed
2806 */
2807 <T> void removePreempted(java.util.List<T> list, BiPredicate<? super T, ? super T> preempts) {
2808 compareAndRemove(list, (item1, item2) -> {
2809 int flags = 0;
2810 if (preempts.test(item1, item2))
2811 flags |= SECOND;
2812 if (preempts.test(item2, item1))
2813 flags |= FIRST;
2814 return flags;
2815 });
2816 }
2817
2818 /** Filters method candidates for the "potentially ambiguous method" check */
2819 class PotentiallyAmbiguousFilter extends ClashFilter {
2820
2821 PotentiallyAmbiguousFilter(Type site) {
2822 super(site);
2823 }
2824
2825 @Override
2826 boolean shouldSkip(Symbol s) {
2827 return s.owner.type.tsym == syms.objectType.tsym || super.shouldSkip(s);
2828 }
2829 }
2830
2831 /**
2832 * Report warnings for potentially ambiguous method declarations. Two declarations
2833 * are potentially ambiguous if they feature two unrelated functional interface
2834 * in same argument position (in which case, a call site passing an implicit
2835 * lambda would be ambiguous). This assumes they already have the same name.
2836 */
2837 boolean potentiallyAmbiguousOverload(Type site, MethodSymbol msym1, MethodSymbol msym2) {
2838 Assert.check(msym1.name == msym2.name);
2839 if (msym1 == msym2)
2840 return false;
2841 Type mt1 = types.memberType(site, msym1);
2842 Type mt2 = types.memberType(site, msym2);
2843 //if both generic methods, adjust type variables
2844 if (mt1.hasTag(FORALL) && mt2.hasTag(FORALL) &&
2845 types.hasSameBounds((ForAll)mt1, (ForAll)mt2)) {
2846 mt2 = types.subst(mt2, ((ForAll)mt2).tvars, ((ForAll)mt1).tvars);
2847 }
2848 //expand varargs methods if needed
2849 int maxLength = Math.max(mt1.getParameterTypes().length(), mt2.getParameterTypes().length());
2850 List<Type> args1 = rs.adjustArgs(mt1.getParameterTypes(), msym1, maxLength, true);
2851 List<Type> args2 = rs.adjustArgs(mt2.getParameterTypes(), msym2, maxLength, true);
2852 //if arities don't match, exit
2853 if (args1.length() != args2.length())
2854 return false;
2855 boolean potentiallyAmbiguous = false;
2856 while (args1.nonEmpty() && args2.nonEmpty()) {
2857 Type s = args1.head;
2858 Type t = args2.head;
2859 if (!types.isSubtype(t, s) && !types.isSubtype(s, t)) {
2860 if (types.isFunctionalInterface(s) && types.isFunctionalInterface(t) &&
2861 types.findDescriptorType(s).getParameterTypes().length() > 0 &&
2862 types.findDescriptorType(s).getParameterTypes().length() ==
2863 types.findDescriptorType(t).getParameterTypes().length()) {
2864 potentiallyAmbiguous = true;
2865 } else {
2866 return false;
2867 }
2868 }
2869 args1 = args1.tail;
2870 args2 = args2.tail;
2871 }
2872 return potentiallyAmbiguous;
2873 }
2874
2875 // Apply special flag "-XDwarnOnAccessToMembers" which turns on just this particular warning for all types of access
2876 void checkAccessFromSerializableElement(final JCTree tree, boolean isLambda) {
2877 if (warnOnAnyAccessToMembers || isLambda)
2878 checkAccessFromSerializableElementInner(tree, isLambda);
2879 }
2880
2881 private void checkAccessFromSerializableElementInner(final JCTree tree, boolean isLambda) {
2882 Symbol sym = TreeInfo.symbol(tree);
2883 if (!sym.kind.matches(KindSelector.VAL_MTH)) {
2884 return;
2885 }
2886
2887 if (sym.kind == VAR) {
2888 if ((sym.flags() & PARAMETER) != 0 ||
2889 sym.isDirectlyOrIndirectlyLocal() ||
2890 sym.name == names._this ||
2891 sym.name == names._super) {
2892 return;
2893 }
2894 }
2895
2896 if (!types.isSubtype(sym.owner.type, syms.serializableType) && isEffectivelyNonPublic(sym)) {
2897 DiagnosticFlag flag = warnOnAnyAccessToMembers ? DiagnosticFlag.DEFAULT_ENABLED : null;
2898 if (isLambda) {
2899 if (belongsToRestrictedPackage(sym)) {
2900 log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableLambda(sym));
2901 }
2902 } else {
2903 log.warning(flag, tree.pos(), LintWarnings.AccessToMemberFromSerializableElement(sym));
2904 }
2905 }
2906 }
2907
2908 private boolean isEffectivelyNonPublic(Symbol sym) {
2909 if (sym.packge() == syms.rootPackage) {
2910 return false;
2911 }
2912
2913 while (sym.kind != PCK) {
2914 if ((sym.flags() & PUBLIC) == 0) {
2915 return true;
2916 }
2917 sym = sym.owner;
2918 }
2919 return false;
2920 }
2921
2922 private boolean belongsToRestrictedPackage(Symbol sym) {
2923 String fullName = sym.packge().fullname.toString();
2924 return fullName.startsWith("java.") ||
2925 fullName.startsWith("javax.") ||
2926 fullName.startsWith("sun.") ||
2927 fullName.contains(".internal.");
2928 }
2929
2930 /** Check that class c does not implement directly or indirectly
2931 * the same parameterized interface with two different argument lists.
2932 * @param pos Position to be used for error reporting.
2933 * @param type The type whose interfaces are checked.
2934 */
2935 void checkClassBounds(DiagnosticPosition pos, Type type) {
2936 checkClassBounds(pos, new HashMap<TypeSymbol,Type>(), type);
2937 }
2938 //where
2939 /** Enter all interfaces of type `type' into the hash table `seensofar'
2940 * with their class symbol as key and their type as value. Make
2941 * sure no class is entered with two different types.
2942 */
2943 void checkClassBounds(DiagnosticPosition pos,
2944 Map<TypeSymbol,Type> seensofar,
2945 Type type) {
2946 if (type.isErroneous()) return;
2947 for (List<Type> l = types.interfaces(type); l.nonEmpty(); l = l.tail) {
2948 Type it = l.head;
2949 if (type.hasTag(CLASS) && !it.hasTag(CLASS)) continue; // JLS 8.1.5
2950
2951 Type oldit = seensofar.put(it.tsym, it);
2952 if (oldit != null) {
2953 List<Type> oldparams = oldit.allparams();
2954 List<Type> newparams = it.allparams();
2955 if (!types.containsTypeEquivalent(oldparams, newparams))
2956 log.error(pos,
2957 Errors.CantInheritDiffArg(it.tsym,
2958 Type.toString(oldparams),
2959 Type.toString(newparams)));
2960 }
2961 checkClassBounds(pos, seensofar, it);
2962 }
2963 Type st = types.supertype(type);
2964 if (type.hasTag(CLASS) && !st.hasTag(CLASS)) return; // JLS 8.1.4
2965 if (st != Type.noType) checkClassBounds(pos, seensofar, st);
2966 }
2967
2968 /** Enter interface into into set.
2969 * If it existed already, issue a "repeated interface" error.
2970 */
2971 void checkNotRepeated(DiagnosticPosition pos, Type it, Set<Symbol> its) {
2972 if (its.contains(it.tsym))
2973 log.error(pos, Errors.RepeatedInterface);
2974 else {
2975 its.add(it.tsym);
2976 }
2977 }
2978
2979 /* *************************************************************************
2980 * Check annotations
2981 **************************************************************************/
2982
2983 /**
2984 * Recursively validate annotations values
2985 */
2986 void validateAnnotationTree(JCTree tree) {
2987 class AnnotationValidator extends TreeScanner {
2988 @Override
2989 public void visitAnnotation(JCAnnotation tree) {
2990 if (!tree.type.isErroneous() && tree.type.tsym.isAnnotationType()) {
2991 super.visitAnnotation(tree);
2992 validateAnnotation(tree);
2993 }
2994 }
2995 }
2996 tree.accept(new AnnotationValidator());
2997 }
2998
2999 /**
3000 * {@literal
3001 * Annotation types are restricted to primitives, String, an
3002 * enum, an annotation, Class, Class<?>, Class<? extends
3003 * Anything>, arrays of the preceding.
3004 * }
3005 */
3006 void validateAnnotationType(JCTree restype) {
3007 // restype may be null if an error occurred, so don't bother validating it
3008 if (restype != null) {
3009 validateAnnotationType(restype.pos(), restype.type);
3010 }
3011 }
3012
3013 void validateAnnotationType(DiagnosticPosition pos, Type type) {
3014 if (type.isPrimitive()) return;
3015 if (types.isSameType(type, syms.stringType)) return;
3016 if ((type.tsym.flags() & Flags.ENUM) != 0) return;
3017 if ((type.tsym.flags() & Flags.ANNOTATION) != 0) return;
3018 if (types.cvarLowerBound(type).tsym == syms.classType.tsym) return;
3019 if (types.isArray(type) && !types.isArray(types.elemtype(type))) {
3020 validateAnnotationType(pos, types.elemtype(type));
3021 return;
3022 }
3023 log.error(pos, Errors.InvalidAnnotationMemberType);
3024 }
3025
3026 /**
3027 * "It is also a compile-time error if any method declared in an
3028 * annotation type has a signature that is override-equivalent to
3029 * that of any public or protected method declared in class Object
3030 * or in the interface annotation.Annotation."
3031 *
3032 * @jls 9.6 Annotation Types
3033 */
3034 void validateAnnotationMethod(DiagnosticPosition pos, MethodSymbol m) {
3035 for (Type sup = syms.annotationType; sup.hasTag(CLASS); sup = types.supertype(sup)) {
3036 Scope s = sup.tsym.members();
3037 for (Symbol sym : s.getSymbolsByName(m.name)) {
3038 if (sym.kind == MTH &&
3039 (sym.flags() & (PUBLIC | PROTECTED)) != 0 &&
3040 types.overrideEquivalent(m.type, sym.type))
3041 log.error(pos, Errors.IntfAnnotationMemberClash(sym, sup));
3042 }
3043 }
3044 }
3045
3046 /** Check the annotations of a symbol.
3047 */
3048 public void validateAnnotations(List<JCAnnotation> annotations, JCTree declarationTree, Symbol s) {
3049 for (JCAnnotation a : annotations)
3050 validateAnnotation(a, declarationTree, s);
3051 }
3052
3053 /** Check the type annotations.
3054 */
3055 public void validateTypeAnnotations(List<JCAnnotation> annotations, Symbol s, boolean isTypeParameter) {
3056 for (JCAnnotation a : annotations)
3057 validateTypeAnnotation(a, s, isTypeParameter);
3058 }
3059
3060 /** Check an annotation of a symbol.
3061 */
3062 private void validateAnnotation(JCAnnotation a, JCTree declarationTree, Symbol s) {
3063 /** NOTE: if annotation processors are present, annotation processing rounds can happen after this method,
3064 * this can impact in particular records for which annotations are forcibly propagated.
3065 */
3066 validateAnnotationTree(a);
3067 boolean isRecordMember = ((s.flags_field & RECORD) != 0 || s.enclClass() != null && s.enclClass().isRecord());
3068
3069 boolean isRecordField = (s.flags_field & RECORD) != 0 &&
3070 declarationTree.hasTag(VARDEF) &&
3071 s.owner.kind == TYP;
3072
3073 if (isRecordField) {
3074 // first we need to check if the annotation is applicable to records
3075 Name[] targets = getTargetNames(a);
3076 boolean appliesToRecords = false;
3077 for (Name target : targets) {
3078 appliesToRecords =
3079 target == names.FIELD ||
3080 target == names.PARAMETER ||
3081 target == names.METHOD ||
3082 target == names.TYPE_USE ||
3083 target == names.RECORD_COMPONENT;
3084 if (appliesToRecords) {
3085 break;
3086 }
3087 }
3088 if (!appliesToRecords) {
3089 log.error(a.pos(), Errors.AnnotationTypeNotApplicable);
3090 } else {
3091 /* lets now find the annotations in the field that are targeted to record components and append them to
3092 * the corresponding record component
3093 */
3094 ClassSymbol recordClass = (ClassSymbol) s.owner;
3095 RecordComponent rc = recordClass.getRecordComponent((VarSymbol)s);
3096 SymbolMetadata metadata = rc.getMetadata();
3097 if (metadata == null || metadata.isEmpty()) {
3098 /* if not is empty then we have already been here, which is the case if multiple annotations are applied
3099 * to the record component declaration
3100 */
3101 rc.appendAttributes(s.getRawAttributes().stream().filter(anno ->
3102 Arrays.stream(getTargetNames(anno.type.tsym)).anyMatch(name -> name == names.RECORD_COMPONENT)
3103 ).collect(List.collector()));
3104
3105 JCVariableDecl fieldAST = (JCVariableDecl) declarationTree;
3106 for (JCAnnotation fieldAnnot : fieldAST.mods.annotations) {
3107 for (JCAnnotation rcAnnot : rc.declarationFor().mods.annotations) {
3108 if (rcAnnot.pos == fieldAnnot.pos) {
3109 rcAnnot.setType(fieldAnnot.type);
3110 break;
3111 }
3112 }
3113 }
3114
3115 /* At this point, we used to carry over any type annotations from the VARDEF to the record component, but
3116 * that is problematic, since we get here only when *some* annotation is applied to the SE5 (declaration)
3117 * annotation location, inadvertently failing to carry over the type annotations when the VarDef has no
3118 * annotations in the SE5 annotation location.
3119 *
3120 * Now type annotations are assigned to record components in a method that would execute irrespective of
3121 * whether there are SE5 annotations on a VarDef viz com.sun.tools.javac.code.TypeAnnotations.TypeAnnotationPositions.visitVarDef
3122 */
3123 }
3124 }
3125 }
3126
3127 /* the section below is tricky. Annotations applied to record components are propagated to the corresponding
3128 * record member so if an annotation has target: FIELD, it is propagated to the corresponding FIELD, if it has
3129 * target METHOD, it is propagated to the accessor and so on. But at the moment when method members are generated
3130 * there is no enough information to propagate only the right annotations. So all the annotations are propagated
3131 * to all the possible locations.
3132 *
3133 * At this point we need to remove all the annotations that are not in place before going on with the annotation
3134 * party. On top of the above there is the issue that there is no AST representing record components, just symbols
3135 * so the corresponding field has been holding all the annotations and it's metadata has been modified as if it
3136 * was both a field and a record component.
3137 *
3138 * So there are two places where we need to trim annotations from: the metadata of the symbol and / or the modifiers
3139 * in the AST. Whatever is in the metadata will be written to the class file, whatever is in the modifiers could
3140 * be see by annotation processors.
3141 *
3142 * The metadata contains both type annotations and declaration annotations. At this point of the game we don't
3143 * need to care about type annotations, they are all in the right place. But we could need to remove declaration
3144 * annotations. So for declaration annotations if they are not applicable to the record member, excluding type
3145 * annotations which are already correct, then we will remove it. For the AST modifiers if the annotation is not
3146 * applicable either as type annotation and or declaration annotation, only in that case it will be removed.
3147 *
3148 * So it could be that annotation is removed as a declaration annotation but it is kept in the AST modifier for
3149 * further inspection by annotation processors.
3150 *
3151 * For example:
3152 *
3153 * import java.lang.annotation.*;
3154 *
3155 * @Target({ElementType.TYPE_USE, ElementType.RECORD_COMPONENT})
3156 * @Retention(RetentionPolicy.RUNTIME)
3157 * @interface Anno { }
3158 *
3159 * record R(@Anno String s) {}
3160 *
3161 * at this point we will have for the case of the generated field:
3162 * - @Anno in the modifier
3163 * - @Anno as a type annotation
3164 * - @Anno as a declaration annotation
3165 *
3166 * the last one should be removed because the annotation has not FIELD as target but it was applied as a
3167 * declaration annotation because the field was being treated both as a field and as a record component
3168 * as we have already copied the annotations to the record component, now the field doesn't need to hold
3169 * annotations that are not intended for it anymore. Still @Anno has to be kept in the AST's modifiers as it
3170 * is applicable as a type annotation to the type of the field.
3171 */
3172
3173 if (a.type.tsym.isAnnotationType()) {
3174 Optional<Set<Name>> applicableTargetsOp = getApplicableTargets(a, s);
3175 if (!applicableTargetsOp.isEmpty()) {
3176 Set<Name> applicableTargets = applicableTargetsOp.get();
3177 boolean notApplicableOrIsTypeUseOnly = applicableTargets.isEmpty() ||
3178 applicableTargets.size() == 1 && applicableTargets.contains(names.TYPE_USE);
3179 boolean isCompGeneratedRecordElement = isRecordMember && (s.flags_field & Flags.GENERATED_MEMBER) != 0;
3180 boolean isCompRecordElementWithNonApplicableDeclAnno = isCompGeneratedRecordElement && notApplicableOrIsTypeUseOnly;
3181
3182 if (applicableTargets.isEmpty() || isCompRecordElementWithNonApplicableDeclAnno) {
3183 if (isCompRecordElementWithNonApplicableDeclAnno) {
3184 /* so we have found an annotation that is not applicable to a record member that was generated by the
3185 * compiler. This was intentionally done at TypeEnter, now is the moment strip away the annotations
3186 * that are not applicable to the given record member
3187 */
3188 JCModifiers modifiers = TreeInfo.getModifiers(declarationTree);
3189 /* lets first remove the annotation from the modifier if it is not applicable, we have to check again as
3190 * it could be a type annotation
3191 */
3192 if (modifiers != null && applicableTargets.isEmpty()) {
3193 ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<>();
3194 for (JCAnnotation anno : modifiers.annotations) {
3195 if (anno != a) {
3196 newAnnotations.add(anno);
3197 }
3198 }
3199 modifiers.annotations = newAnnotations.toList();
3200 }
3201 // now lets remove it from the symbol
3202 s.getMetadata().removeDeclarationMetadata(a.attribute);
3203 } else {
3204 log.error(a.pos(), Errors.AnnotationTypeNotApplicable);
3205 }
3206 }
3207 /* if we are seeing the @SafeVarargs annotation applied to a compiler generated accessor,
3208 * then this is an error as we know that no compiler generated accessor will be a varargs
3209 * method, better to fail asap
3210 */
3211 if (isCompGeneratedRecordElement && !isRecordField && a.type.tsym == syms.trustMeType.tsym && declarationTree.hasTag(METHODDEF)) {
3212 log.error(a.pos(), Errors.VarargsInvalidTrustmeAnno(syms.trustMeType.tsym, Fragments.VarargsTrustmeOnNonVarargsAccessor(s)));
3213 }
3214 }
3215 }
3216
3217 if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) {
3218 if (s.kind != TYP) {
3219 log.error(a.pos(), Errors.BadFunctionalIntfAnno);
3220 } else if (!s.isInterface() || (s.flags() & ANNOTATION) != 0) {
3221 log.error(a.pos(), Errors.BadFunctionalIntfAnno1(Fragments.NotAFunctionalIntf(s)));
3222 }
3223 }
3224 }
3225
3226 public void validateTypeAnnotation(JCAnnotation a, Symbol s, boolean isTypeParameter) {
3227 Assert.checkNonNull(a.type);
3228 // we just want to validate that the anotation doesn't have any wrong target
3229 if (s != null) getApplicableTargets(a, s);
3230 validateAnnotationTree(a);
3231
3232 if (a.hasTag(TYPE_ANNOTATION) &&
3233 !a.annotationType.type.isErroneous() &&
3234 !isTypeAnnotation(a, isTypeParameter)) {
3235 log.error(a.pos(), Errors.AnnotationTypeNotApplicableToType(a.type));
3236 }
3237 }
3238
3239 /**
3240 * Validate the proposed container 'repeatable' on the
3241 * annotation type symbol 's'. Report errors at position
3242 * 'pos'.
3243 *
3244 * @param s The (annotation)type declaration annotated with a @Repeatable
3245 * @param repeatable the @Repeatable on 's'
3246 * @param pos where to report errors
3247 */
3248 public void validateRepeatable(TypeSymbol s, Attribute.Compound repeatable, DiagnosticPosition pos) {
3249 Assert.check(types.isSameType(repeatable.type, syms.repeatableType));
3250
3251 Type t = null;
3252 List<Pair<MethodSymbol,Attribute>> l = repeatable.values;
3253 if (!l.isEmpty()) {
3254 Assert.check(l.head.fst.name == names.value);
3255 if (l.head.snd instanceof Attribute.Class) {
3256 t = ((Attribute.Class)l.head.snd).getValue();
3257 }
3258 }
3259
3260 if (t == null) {
3261 // errors should already have been reported during Annotate
3262 return;
3263 }
3264
3265 validateValue(t.tsym, s, pos);
3266 validateRetention(t.tsym, s, pos);
3267 validateDocumented(t.tsym, s, pos);
3268 validateInherited(t.tsym, s, pos);
3269 validateTarget(t.tsym, s, pos);
3270 validateDefault(t.tsym, pos);
3271 }
3272
3273 private void validateValue(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) {
3274 Symbol sym = container.members().findFirst(names.value);
3275 if (sym != null && sym.kind == MTH) {
3276 MethodSymbol m = (MethodSymbol) sym;
3277 Type ret = m.getReturnType();
3278 if (!(ret.hasTag(ARRAY) && types.isSameType(((ArrayType)ret).elemtype, contained.type))) {
3279 log.error(pos,
3280 Errors.InvalidRepeatableAnnotationValueReturn(container,
3281 ret,
3282 types.makeArrayType(contained.type)));
3283 }
3284 } else {
3285 log.error(pos, Errors.InvalidRepeatableAnnotationNoValue(container));
3286 }
3287 }
3288
3289 private void validateRetention(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) {
3290 Attribute.RetentionPolicy containerRetention = types.getRetention(container);
3291 Attribute.RetentionPolicy containedRetention = types.getRetention(contained);
3292
3293 boolean error = false;
3294 switch (containedRetention) {
3295 case RUNTIME:
3296 if (containerRetention != Attribute.RetentionPolicy.RUNTIME) {
3297 error = true;
3298 }
3299 break;
3300 case CLASS:
3301 if (containerRetention == Attribute.RetentionPolicy.SOURCE) {
3302 error = true;
3303 }
3304 }
3305 if (error ) {
3306 log.error(pos,
3307 Errors.InvalidRepeatableAnnotationRetention(container,
3308 containerRetention.name(),
3309 contained,
3310 containedRetention.name()));
3311 }
3312 }
3313
3314 private void validateDocumented(Symbol container, Symbol contained, DiagnosticPosition pos) {
3315 if (contained.attribute(syms.documentedType.tsym) != null) {
3316 if (container.attribute(syms.documentedType.tsym) == null) {
3317 log.error(pos, Errors.InvalidRepeatableAnnotationNotDocumented(container, contained));
3318 }
3319 }
3320 }
3321
3322 private void validateInherited(Symbol container, Symbol contained, DiagnosticPosition pos) {
3323 if (contained.attribute(syms.inheritedType.tsym) != null) {
3324 if (container.attribute(syms.inheritedType.tsym) == null) {
3325 log.error(pos, Errors.InvalidRepeatableAnnotationNotInherited(container, contained));
3326 }
3327 }
3328 }
3329
3330 private void validateTarget(TypeSymbol container, TypeSymbol contained, DiagnosticPosition pos) {
3331 // The set of targets the container is applicable to must be a subset
3332 // (with respect to annotation target semantics) of the set of targets
3333 // the contained is applicable to. The target sets may be implicit or
3334 // explicit.
3335
3336 Set<Name> containerTargets;
3337 Attribute.Array containerTarget = getAttributeTargetAttribute(container);
3338 if (containerTarget == null) {
3339 containerTargets = getDefaultTargetSet();
3340 } else {
3341 containerTargets = new HashSet<>();
3342 for (Attribute app : containerTarget.values) {
3343 if (!(app instanceof Attribute.Enum attributeEnum)) {
3344 continue; // recovery
3345 }
3346 containerTargets.add(attributeEnum.value.name);
3347 }
3348 }
3349
3350 Set<Name> containedTargets;
3351 Attribute.Array containedTarget = getAttributeTargetAttribute(contained);
3352 if (containedTarget == null) {
3353 containedTargets = getDefaultTargetSet();
3354 } else {
3355 containedTargets = new HashSet<>();
3356 for (Attribute app : containedTarget.values) {
3357 if (!(app instanceof Attribute.Enum attributeEnum)) {
3358 continue; // recovery
3359 }
3360 containedTargets.add(attributeEnum.value.name);
3361 }
3362 }
3363
3364 if (!isTargetSubsetOf(containerTargets, containedTargets)) {
3365 log.error(pos, Errors.InvalidRepeatableAnnotationIncompatibleTarget(container, contained));
3366 }
3367 }
3368
3369 /* get a set of names for the default target */
3370 private Set<Name> getDefaultTargetSet() {
3371 if (defaultTargets == null) {
3372 defaultTargets = Set.of(defaultTargetMetaInfo());
3373 }
3374
3375 return defaultTargets;
3376 }
3377 private Set<Name> defaultTargets;
3378
3379
3380 /** Checks that s is a subset of t, with respect to ElementType
3381 * semantics, specifically {ANNOTATION_TYPE} is a subset of {TYPE},
3382 * and {TYPE_USE} covers the set {ANNOTATION_TYPE, TYPE, TYPE_USE,
3383 * TYPE_PARAMETER}.
3384 */
3385 private boolean isTargetSubsetOf(Set<Name> s, Set<Name> t) {
3386 // Check that all elements in s are present in t
3387 for (Name n2 : s) {
3388 boolean currentElementOk = false;
3389 for (Name n1 : t) {
3390 if (n1 == n2) {
3391 currentElementOk = true;
3392 break;
3393 } else if (n1 == names.TYPE && n2 == names.ANNOTATION_TYPE) {
3394 currentElementOk = true;
3395 break;
3396 } else if (n1 == names.TYPE_USE &&
3397 (n2 == names.TYPE ||
3398 n2 == names.ANNOTATION_TYPE ||
3399 n2 == names.TYPE_PARAMETER)) {
3400 currentElementOk = true;
3401 break;
3402 }
3403 }
3404 if (!currentElementOk)
3405 return false;
3406 }
3407 return true;
3408 }
3409
3410 private void validateDefault(Symbol container, DiagnosticPosition pos) {
3411 // validate that all other elements of containing type has defaults
3412 Scope scope = container.members();
3413 for(Symbol elm : scope.getSymbols()) {
3414 if (elm.name != names.value &&
3415 elm.kind == MTH &&
3416 ((MethodSymbol)elm).defaultValue == null) {
3417 log.error(pos,
3418 Errors.InvalidRepeatableAnnotationElemNondefault(container, elm));
3419 }
3420 }
3421 }
3422
3423 /** Is s a method symbol that overrides a method in a superclass? */
3424 boolean isOverrider(Symbol s) {
3425 if (s.kind != MTH || s.isStatic())
3426 return false;
3427 MethodSymbol m = (MethodSymbol)s;
3428 TypeSymbol owner = (TypeSymbol)m.owner;
3429 for (Type sup : types.closure(owner.type)) {
3430 if (sup == owner.type)
3431 continue; // skip "this"
3432 Scope scope = sup.tsym.members();
3433 for (Symbol sym : scope.getSymbolsByName(m.name)) {
3434 if (!sym.isStatic() && m.overrides(sym, owner, types, true))
3435 return true;
3436 }
3437 }
3438 return false;
3439 }
3440
3441 /** Is the annotation applicable to types? */
3442 protected boolean isTypeAnnotation(JCAnnotation a, boolean isTypeParameter) {
3443 List<Attribute> targets = typeAnnotations.annotationTargets(a.annotationType.type.tsym);
3444 return (targets == null) ?
3445 (Feature.NO_TARGET_ANNOTATION_APPLICABILITY.allowedInSource(source) && isTypeParameter) :
3446 targets.stream()
3447 .anyMatch(attr -> isTypeAnnotation(attr, isTypeParameter));
3448 }
3449 //where
3450 boolean isTypeAnnotation(Attribute a, boolean isTypeParameter) {
3451 Attribute.Enum e = (Attribute.Enum)a;
3452 return (e.value.name == names.TYPE_USE ||
3453 (isTypeParameter && e.value.name == names.TYPE_PARAMETER));
3454 }
3455
3456 /** Is the annotation applicable to the symbol? */
3457 Name[] getTargetNames(JCAnnotation a) {
3458 return getTargetNames(a.annotationType.type.tsym);
3459 }
3460
3461 public Name[] getTargetNames(TypeSymbol annoSym) {
3462 Attribute.Array arr = getAttributeTargetAttribute(annoSym);
3463 Name[] targets;
3464 if (arr == null) {
3465 targets = defaultTargetMetaInfo();
3466 } else {
3467 // TODO: can we optimize this?
3468 targets = new Name[arr.values.length];
3469 for (int i=0; i<arr.values.length; ++i) {
3470 Attribute app = arr.values[i];
3471 if (!(app instanceof Attribute.Enum attributeEnum)) {
3472 return new Name[0];
3473 }
3474 targets[i] = attributeEnum.value.name;
3475 }
3476 }
3477 return targets;
3478 }
3479
3480 boolean annotationApplicable(JCAnnotation a, Symbol s) {
3481 Optional<Set<Name>> targets = getApplicableTargets(a, s);
3482 /* the optional could be empty if the annotation is unknown in that case
3483 * we return that it is applicable and if it is erroneous that should imply
3484 * an error at the declaration site
3485 */
3486 return targets.isEmpty() || targets.isPresent() && !targets.get().isEmpty();
3487 }
3488
3489 Optional<Set<Name>> getApplicableTargets(JCAnnotation a, Symbol s) {
3490 Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym);
3491 Name[] targets;
3492 Set<Name> applicableTargets = new HashSet<>();
3493
3494 if (arr == null) {
3495 targets = defaultTargetMetaInfo();
3496 } else {
3497 // TODO: can we optimize this?
3498 targets = new Name[arr.values.length];
3499 for (int i=0; i<arr.values.length; ++i) {
3500 Attribute app = arr.values[i];
3501 if (!(app instanceof Attribute.Enum attributeEnum)) {
3502 // recovery
3503 return Optional.empty();
3504 }
3505 targets[i] = attributeEnum.value.name;
3506 }
3507 }
3508 for (Name target : targets) {
3509 if (target == names.TYPE) {
3510 if (s.kind == TYP)
3511 applicableTargets.add(names.TYPE);
3512 } else if (target == names.FIELD) {
3513 if (s.kind == VAR && s.owner.kind != MTH)
3514 applicableTargets.add(names.FIELD);
3515 } else if (target == names.RECORD_COMPONENT) {
3516 if (s.getKind() == ElementKind.RECORD_COMPONENT) {
3517 applicableTargets.add(names.RECORD_COMPONENT);
3518 }
3519 } else if (target == names.METHOD) {
3520 if (s.kind == MTH && !s.isConstructor())
3521 applicableTargets.add(names.METHOD);
3522 } else if (target == names.PARAMETER) {
3523 if (s.kind == VAR &&
3524 (s.owner.kind == MTH && (s.flags() & PARAMETER) != 0)) {
3525 applicableTargets.add(names.PARAMETER);
3526 }
3527 } else if (target == names.CONSTRUCTOR) {
3528 if (s.kind == MTH && s.isConstructor())
3529 applicableTargets.add(names.CONSTRUCTOR);
3530 } else if (target == names.LOCAL_VARIABLE) {
3531 if (s.kind == VAR && s.owner.kind == MTH &&
3532 (s.flags() & PARAMETER) == 0) {
3533 applicableTargets.add(names.LOCAL_VARIABLE);
3534 }
3535 } else if (target == names.ANNOTATION_TYPE) {
3536 if (s.kind == TYP && (s.flags() & ANNOTATION) != 0) {
3537 applicableTargets.add(names.ANNOTATION_TYPE);
3538 }
3539 } else if (target == names.PACKAGE) {
3540 if (s.kind == PCK)
3541 applicableTargets.add(names.PACKAGE);
3542 } else if (target == names.TYPE_USE) {
3543 if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
3544 //cannot type annotate implicitly typed locals
3545 continue;
3546 } else if (s.kind == TYP || s.kind == VAR ||
3547 (s.kind == MTH && !s.isConstructor() &&
3548 !s.type.getReturnType().hasTag(VOID)) ||
3549 (s.kind == MTH && s.isConstructor())) {
3550 applicableTargets.add(names.TYPE_USE);
3551 }
3552 } else if (target == names.TYPE_PARAMETER) {
3553 if (s.kind == TYP && s.type.hasTag(TYPEVAR))
3554 applicableTargets.add(names.TYPE_PARAMETER);
3555 } else if (target == names.MODULE) {
3556 if (s.kind == MDL)
3557 applicableTargets.add(names.MODULE);
3558 } else {
3559 log.error(a, Errors.AnnotationUnrecognizedAttributeName(a.type, target));
3560 return Optional.empty(); // Unknown ElementType
3561 }
3562 }
3563 return Optional.of(applicableTargets);
3564 }
3565
3566 Attribute.Array getAttributeTargetAttribute(TypeSymbol s) {
3567 Attribute.Compound atTarget = s.getAnnotationTypeMetadata().getTarget();
3568 if (atTarget == null) return null; // ok, is applicable
3569 Attribute atValue = atTarget.member(names.value);
3570 return (atValue instanceof Attribute.Array attributeArray) ? attributeArray : null;
3571 }
3572
3573 private Name[] dfltTargetMeta;
3574 private Name[] defaultTargetMetaInfo() {
3575 if (dfltTargetMeta == null) {
3576 ArrayList<Name> defaultTargets = new ArrayList<>();
3577 defaultTargets.add(names.PACKAGE);
3578 defaultTargets.add(names.TYPE);
3579 defaultTargets.add(names.FIELD);
3580 defaultTargets.add(names.METHOD);
3581 defaultTargets.add(names.CONSTRUCTOR);
3582 defaultTargets.add(names.ANNOTATION_TYPE);
3583 defaultTargets.add(names.LOCAL_VARIABLE);
3584 defaultTargets.add(names.PARAMETER);
3585 if (allowRecords) {
3586 defaultTargets.add(names.RECORD_COMPONENT);
3587 }
3588 if (allowModules) {
3589 defaultTargets.add(names.MODULE);
3590 }
3591 dfltTargetMeta = defaultTargets.toArray(new Name[0]);
3592 }
3593 return dfltTargetMeta;
3594 }
3595
3596 /** Check an annotation value.
3597 *
3598 * @param a The annotation tree to check
3599 * @return true if this annotation tree is valid, otherwise false
3600 */
3601 public boolean validateAnnotationDeferErrors(JCAnnotation a) {
3602 boolean res = false;
3603 final Log.DiagnosticHandler diagHandler = log.new DiscardDiagnosticHandler();
3604 try {
3605 res = validateAnnotation(a);
3606 } finally {
3607 log.popDiagnosticHandler(diagHandler);
3608 }
3609 return res;
3610 }
3611
3612 private boolean validateAnnotation(JCAnnotation a) {
3613 boolean isValid = true;
3614 AnnotationTypeMetadata metadata = a.annotationType.type.tsym.getAnnotationTypeMetadata();
3615
3616 // collect an inventory of the annotation elements
3617 Set<MethodSymbol> elements = metadata.getAnnotationElements();
3618
3619 // remove the ones that are assigned values
3620 for (JCTree arg : a.args) {
3621 if (!arg.hasTag(ASSIGN)) continue; // recovery
3622 JCAssign assign = (JCAssign)arg;
3623 Symbol m = TreeInfo.symbol(assign.lhs);
3624 if (m == null || m.type.isErroneous()) continue;
3625 if (!elements.remove(m)) {
3626 isValid = false;
3627 log.error(assign.lhs.pos(),
3628 Errors.DuplicateAnnotationMemberValue(m.name, a.type));
3629 }
3630 }
3631
3632 // all the remaining ones better have default values
3633 List<Name> missingDefaults = List.nil();
3634 Set<MethodSymbol> membersWithDefault = metadata.getAnnotationElementsWithDefault();
3635 for (MethodSymbol m : elements) {
3636 if (m.type.isErroneous())
3637 continue;
3638
3639 if (!membersWithDefault.contains(m))
3640 missingDefaults = missingDefaults.append(m.name);
3641 }
3642 missingDefaults = missingDefaults.reverse();
3643 if (missingDefaults.nonEmpty()) {
3644 isValid = false;
3645 Error errorKey = (missingDefaults.size() > 1)
3646 ? Errors.AnnotationMissingDefaultValue1(a.type, missingDefaults)
3647 : Errors.AnnotationMissingDefaultValue(a.type, missingDefaults);
3648 log.error(a.pos(), errorKey);
3649 }
3650
3651 return isValid && validateTargetAnnotationValue(a);
3652 }
3653
3654 /* Validate the special java.lang.annotation.Target annotation */
3655 boolean validateTargetAnnotationValue(JCAnnotation a) {
3656 // special case: java.lang.annotation.Target must not have
3657 // repeated values in its value member
3658 if (a.annotationType.type.tsym != syms.annotationTargetType.tsym ||
3659 a.args.tail == null)
3660 return true;
3661
3662 boolean isValid = true;
3663 if (!a.args.head.hasTag(ASSIGN)) return false; // error recovery
3664 JCAssign assign = (JCAssign) a.args.head;
3665 Symbol m = TreeInfo.symbol(assign.lhs);
3666 if (m.name != names.value) return false;
3667 JCTree rhs = assign.rhs;
3668 if (!rhs.hasTag(NEWARRAY)) return false;
3669 JCNewArray na = (JCNewArray) rhs;
3670 Set<Symbol> targets = new HashSet<>();
3671 for (JCTree elem : na.elems) {
3672 if (!targets.add(TreeInfo.symbol(elem))) {
3673 isValid = false;
3674 log.error(elem.pos(), Errors.RepeatedAnnotationTarget);
3675 }
3676 }
3677 return isValid;
3678 }
3679
3680 void checkDeprecatedAnnotation(DiagnosticPosition pos, Symbol s) {
3681 if (lint.isEnabled(LintCategory.DEP_ANN) && s.isDeprecatableViaAnnotation() &&
3682 (s.flags() & DEPRECATED) != 0 &&
3683 !syms.deprecatedType.isErroneous() &&
3684 s.attribute(syms.deprecatedType.tsym) == null) {
3685 log.warning(pos, LintWarnings.MissingDeprecatedAnnotation);
3686 }
3687 // Note: @Deprecated has no effect on local variables, parameters and package decls.
3688 if (lint.isEnabled(LintCategory.DEPRECATION) && !s.isDeprecatableViaAnnotation()) {
3689 if (!syms.deprecatedType.isErroneous() && s.attribute(syms.deprecatedType.tsym) != null) {
3690 log.warning(pos, LintWarnings.DeprecatedAnnotationHasNoEffect(Kinds.kindName(s)));
3691 }
3692 }
3693 }
3694
3695 void checkDeprecated(final DiagnosticPosition pos, final Symbol other, final Symbol s) {
3696 checkDeprecated(() -> pos, other, s);
3697 }
3698
3699 void checkDeprecated(Supplier<DiagnosticPosition> pos, final Symbol other, final Symbol s) {
3700 if (!importSuppression
3701 && (s.isDeprecatedForRemoval() || s.isDeprecated() && !other.isDeprecated())
3702 && (s.outermostClass() != other.outermostClass() || s.outermostClass() == null)
3703 && s.kind != Kind.PCK) {
3704 warnDeprecated(pos.get(), s);
3705 }
3706 }
3707
3708 void checkSunAPI(final DiagnosticPosition pos, final Symbol s) {
3709 if ((s.flags() & PROPRIETARY) != 0) {
3710 log.warning(pos, Warnings.SunProprietary(s));
3711 }
3712 }
3713
3714 void checkProfile(final DiagnosticPosition pos, final Symbol s) {
3715 if (profile != Profile.DEFAULT && (s.flags() & NOT_IN_PROFILE) != 0) {
3716 log.error(pos, Errors.NotInProfile(s, profile));
3717 }
3718 }
3719
3720 void checkPreview(DiagnosticPosition pos, Symbol other, Symbol s) {
3721 checkPreview(pos, other, Type.noType, s);
3722 }
3723
3724 void checkPreview(DiagnosticPosition pos, Symbol other, Type site, Symbol s) {
3725 boolean sIsPreview;
3726 Symbol previewSymbol;
3727 if ((s.flags() & PREVIEW_API) != 0) {
3728 sIsPreview = true;
3729 previewSymbol= s;
3730 } else if ((s.kind == Kind.MTH || s.kind == Kind.VAR) &&
3731 site.tsym != null &&
3732 (site.tsym.flags() & PREVIEW_API) == 0 &&
3733 (s.owner.flags() & PREVIEW_API) != 0) {
3734 //calling a method, or using a field, whose owner is a preview, but
3735 //using a site that is not a preview. Also produce an error or warning:
3736 sIsPreview = true;
3737 previewSymbol = s.owner;
3738 } else {
3739 sIsPreview = false;
3740 previewSymbol = null;
3741 }
3742 if (sIsPreview && !preview.participatesInPreview(syms, other, s) && !disablePreviewCheck) {
3743 if ((previewSymbol.flags() & PREVIEW_REFLECTIVE) == 0) {
3744 if (!preview.isEnabled()) {
3745 log.error(pos, Errors.IsPreview(s));
3746 } else {
3747 preview.markUsesPreview(pos);
3748 warnPreviewAPI(pos, LintWarnings.IsPreview(s));
3749 }
3750 } else {
3751 warnPreviewAPI(pos, LintWarnings.IsPreviewReflective(s));
3752 }
3753 }
3754 if (preview.declaredUsingPreviewFeature(s)) {
3755 if (preview.isEnabled()) {
3756 //for preview disabled do presumably so not need to do anything?
3757 //If "s" is compiled from source, then there was an error for it already;
3758 //if "s" is from classfile, there already was an error for the classfile.
3759 preview.markUsesPreview(pos);
3760 warnPreviewAPI(pos, LintWarnings.DeclaredUsingPreview(kindName(s), s));
3761 }
3762 }
3763 }
3764
3765 void checkRestricted(DiagnosticPosition pos, Symbol s) {
3766 if (s.kind == MTH && (s.flags() & RESTRICTED) != 0) {
3767 log.warning(pos, LintWarnings.RestrictedMethod(s.enclClass(), s));
3768 }
3769 }
3770
3771 /* *************************************************************************
3772 * Check for recursive annotation elements.
3773 **************************************************************************/
3774
3775 /** Check for cycles in the graph of annotation elements.
3776 */
3777 void checkNonCyclicElements(JCClassDecl tree) {
3778 if ((tree.sym.flags_field & ANNOTATION) == 0) return;
3779 Assert.check((tree.sym.flags_field & LOCKED) == 0);
3780 try {
3781 tree.sym.flags_field |= LOCKED;
3782 for (JCTree def : tree.defs) {
3783 if (!def.hasTag(METHODDEF)) continue;
3784 JCMethodDecl meth = (JCMethodDecl)def;
3785 checkAnnotationResType(meth.pos(), meth.restype.type);
3786 }
3787 } finally {
3788 tree.sym.flags_field &= ~LOCKED;
3789 tree.sym.flags_field |= ACYCLIC_ANN;
3790 }
3791 }
3792
3793 void checkNonCyclicElementsInternal(DiagnosticPosition pos, TypeSymbol tsym) {
3794 if ((tsym.flags_field & ACYCLIC_ANN) != 0)
3795 return;
3796 if ((tsym.flags_field & LOCKED) != 0) {
3797 log.error(pos, Errors.CyclicAnnotationElement(tsym));
3798 return;
3799 }
3800 try {
3801 tsym.flags_field |= LOCKED;
3802 for (Symbol s : tsym.members().getSymbols(NON_RECURSIVE)) {
3803 if (s.kind != MTH)
3804 continue;
3805 checkAnnotationResType(pos, ((MethodSymbol)s).type.getReturnType());
3806 }
3807 } finally {
3808 tsym.flags_field &= ~LOCKED;
3809 tsym.flags_field |= ACYCLIC_ANN;
3810 }
3811 }
3812
3813 void checkAnnotationResType(DiagnosticPosition pos, Type type) {
3814 switch (type.getTag()) {
3815 case CLASS:
3816 if ((type.tsym.flags() & ANNOTATION) != 0)
3817 checkNonCyclicElementsInternal(pos, type.tsym);
3818 break;
3819 case ARRAY:
3820 checkAnnotationResType(pos, types.elemtype(type));
3821 break;
3822 default:
3823 break; // int etc
3824 }
3825 }
3826
3827 /* *************************************************************************
3828 * Check for cycles in the constructor call graph.
3829 **************************************************************************/
3830
3831 /** Check for cycles in the graph of constructors calling other
3832 * constructors.
3833 */
3834 void checkCyclicConstructors(JCClassDecl tree) {
3835 // use LinkedHashMap so we generate errors deterministically
3836 Map<Symbol,Symbol> callMap = new LinkedHashMap<>();
3837
3838 // enter each constructor this-call into the map
3839 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
3840 if (!TreeInfo.isConstructor(l.head))
3841 continue;
3842 JCMethodDecl meth = (JCMethodDecl)l.head;
3843 JCMethodInvocation app = TreeInfo.findConstructorCall(meth);
3844 if (app != null && TreeInfo.name(app.meth) == names._this) {
3845 callMap.put(meth.sym, TreeInfo.symbol(app.meth));
3846 } else {
3847 meth.sym.flags_field |= ACYCLIC;
3848 }
3849 }
3850
3851 // Check for cycles in the map
3852 Symbol[] ctors = new Symbol[0];
3853 ctors = callMap.keySet().toArray(ctors);
3854 for (Symbol caller : ctors) {
3855 checkCyclicConstructor(tree, caller, callMap);
3856 }
3857 }
3858
3859 /** Look in the map to see if the given constructor is part of a
3860 * call cycle.
3861 */
3862 private void checkCyclicConstructor(JCClassDecl tree, Symbol ctor,
3863 Map<Symbol,Symbol> callMap) {
3864 if (ctor != null && (ctor.flags_field & ACYCLIC) == 0) {
3865 if ((ctor.flags_field & LOCKED) != 0) {
3866 log.error(TreeInfo.diagnosticPositionFor(ctor, tree, false, t -> t.hasTag(IDENT)),
3867 Errors.RecursiveCtorInvocation);
3868 } else {
3869 ctor.flags_field |= LOCKED;
3870 checkCyclicConstructor(tree, callMap.remove(ctor), callMap);
3871 ctor.flags_field &= ~LOCKED;
3872 }
3873 ctor.flags_field |= ACYCLIC;
3874 }
3875 }
3876
3877 /* *************************************************************************
3878 * Verify the proper placement of super()/this() calls.
3879 *
3880 * - super()/this() may only appear in constructors
3881 * - There must be at most one super()/this() call per constructor
3882 * - The super()/this() call, if any, must be a top-level statement in the
3883 * constructor, i.e., not nested inside any other statement or block
3884 * - There must be no return statements prior to the super()/this() call
3885 **************************************************************************/
3886
3887 void checkSuperInitCalls(JCClassDecl tree) {
3888 new SuperThisChecker().check(tree);
3889 }
3890
3891 private class SuperThisChecker extends TreeScanner {
3892
3893 // Match this scan stack: 1=JCMethodDecl, 2=JCExpressionStatement, 3=JCMethodInvocation
3894 private static final int MATCH_SCAN_DEPTH = 3;
3895
3896 private boolean constructor; // is this method a constructor?
3897 private boolean firstStatement; // at the first statement in method?
3898 private JCReturn earlyReturn; // first return prior to the super()/init(), if any
3899 private Name initCall; // whichever of "super" or "init" we've seen already
3900 private int scanDepth; // current scan recursion depth in method body
3901
3902 public void check(JCClassDecl classDef) {
3903 scan(classDef.defs);
3904 }
3905
3906 @Override
3907 public void visitMethodDef(JCMethodDecl tree) {
3908 Assert.check(!constructor);
3909 Assert.check(earlyReturn == null);
3910 Assert.check(initCall == null);
3911 Assert.check(scanDepth == 1);
3912
3913 // Initialize state for this method
3914 constructor = TreeInfo.isConstructor(tree);
3915 try {
3916
3917 // Scan method body
3918 if (tree.body != null) {
3919 firstStatement = true;
3920 for (List<JCStatement> l = tree.body.stats; l.nonEmpty(); l = l.tail) {
3921 scan(l.head);
3922 firstStatement = false;
3923 }
3924 }
3925
3926 // Verify no 'return' seen prior to an explicit super()/this() call
3927 if (constructor && earlyReturn != null && initCall != null)
3928 log.error(earlyReturn.pos(), Errors.ReturnBeforeSuperclassInitialized);
3929 } finally {
3930 firstStatement = false;
3931 constructor = false;
3932 earlyReturn = null;
3933 initCall = null;
3934 }
3935 }
3936
3937 @Override
3938 public void scan(JCTree tree) {
3939 scanDepth++;
3940 try {
3941 super.scan(tree);
3942 } finally {
3943 scanDepth--;
3944 }
3945 }
3946
3947 @Override
3948 public void visitApply(JCMethodInvocation apply) {
3949 do {
3950
3951 // Is this a super() or this() call?
3952 Name methodName = TreeInfo.name(apply.meth);
3953 if (methodName != names._super && methodName != names._this)
3954 break;
3955
3956 // super()/this() calls must only appear in a constructor
3957 if (!constructor) {
3958 log.error(apply.pos(), Errors.CallMustOnlyAppearInCtor);
3959 break;
3960 }
3961
3962 // super()/this() calls must be a top level statement
3963 if (scanDepth != MATCH_SCAN_DEPTH) {
3964 log.error(apply.pos(), Errors.CtorCallsNotAllowedHere);
3965 break;
3966 }
3967
3968 // super()/this() calls must not appear more than once
3969 if (initCall != null) {
3970 log.error(apply.pos(), Errors.RedundantSuperclassInit);
3971 break;
3972 }
3973
3974 // If super()/this() isn't first, require flexible constructors feature
3975 if (!firstStatement)
3976 preview.checkSourceLevel(apply.pos(), Feature.FLEXIBLE_CONSTRUCTORS);
3977
3978 // We found a legitimate super()/this() call; remember it
3979 initCall = methodName;
3980 } while (false);
3981
3982 // Proceed
3983 super.visitApply(apply);
3984 }
3985
3986 @Override
3987 public void visitReturn(JCReturn tree) {
3988 if (constructor && initCall == null && earlyReturn == null)
3989 earlyReturn = tree; // we have seen a return but not (yet) a super()/this()
3990 super.visitReturn(tree);
3991 }
3992
3993 @Override
3994 public void visitClassDef(JCClassDecl tree) {
3995 // don't descend any further
3996 }
3997
3998 @Override
3999 public void visitLambda(JCLambda tree) {
4000 final boolean constructorPrev = constructor;
4001 final boolean firstStatementPrev = firstStatement;
4002 final JCReturn earlyReturnPrev = earlyReturn;
4003 final Name initCallPrev = initCall;
4004 final int scanDepthPrev = scanDepth;
4005 constructor = false;
4006 firstStatement = false;
4007 earlyReturn = null;
4008 initCall = null;
4009 scanDepth = 0;
4010 try {
4011 super.visitLambda(tree);
4012 } finally {
4013 constructor = constructorPrev;
4014 firstStatement = firstStatementPrev;
4015 earlyReturn = earlyReturnPrev;
4016 initCall = initCallPrev;
4017 scanDepth = scanDepthPrev;
4018 }
4019 }
4020 }
4021
4022 /* *************************************************************************
4023 * Miscellaneous
4024 **************************************************************************/
4025
4026 /**
4027 * Check for division by integer constant zero
4028 * @param pos Position for error reporting.
4029 * @param operator The operator for the expression
4030 * @param operand The right hand operand for the expression
4031 */
4032 void checkDivZero(final DiagnosticPosition pos, Symbol operator, Type operand) {
4033 if (operand.constValue() != null
4034 && operand.getTag().isSubRangeOf(LONG)
4035 && ((Number) (operand.constValue())).longValue() == 0) {
4036 int opc = ((OperatorSymbol)operator).opcode;
4037 if (opc == ByteCodes.idiv || opc == ByteCodes.imod
4038 || opc == ByteCodes.ldiv || opc == ByteCodes.lmod) {
4039 log.warning(pos, LintWarnings.DivZero);
4040 }
4041 }
4042 }
4043
4044 /**
4045 * Check for possible loss of precission
4046 * @param pos Position for error reporting.
4047 * @param found The computed type of the tree
4048 * @param req The computed type of the tree
4049 */
4050 void checkLossOfPrecision(final DiagnosticPosition pos, Type found, Type req) {
4051 if (found.isNumeric() && req.isNumeric() && !types.isAssignable(found, req)) {
4052 log.warning(pos, LintWarnings.PossibleLossOfPrecision(found, req));
4053 }
4054 }
4055
4056 /**
4057 * Check for empty statements after if
4058 */
4059 void checkEmptyIf(JCIf tree) {
4060 if (tree.thenpart.hasTag(SKIP) && tree.elsepart == null) {
4061 log.warning(tree.thenpart.pos(), LintWarnings.EmptyIf);
4062 }
4063 }
4064
4065 /** Check that symbol is unique in given scope.
4066 * @param pos Position for error reporting.
4067 * @param sym The symbol.
4068 * @param s The scope.
4069 */
4070 boolean checkUnique(DiagnosticPosition pos, Symbol sym, Scope s) {
4071 if (sym.type.isErroneous())
4072 return true;
4073 if (sym.owner.name == names.any) return false;
4074 for (Symbol byName : s.getSymbolsByName(sym.name, NON_RECURSIVE)) {
4075 if (sym != byName &&
4076 (byName.flags() & CLASH) == 0 &&
4077 sym.kind == byName.kind &&
4078 sym.name != names.error &&
4079 (sym.kind != MTH ||
4080 types.hasSameArgs(sym.type, byName.type) ||
4081 types.hasSameArgs(types.erasure(sym.type), types.erasure(byName.type)))) {
4082 if ((sym.flags() & VARARGS) != (byName.flags() & VARARGS)) {
4083 sym.flags_field |= CLASH;
4084 varargsDuplicateError(pos, sym, byName);
4085 return true;
4086 } else if (sym.kind == MTH && !types.hasSameArgs(sym.type, byName.type, false)) {
4087 duplicateErasureError(pos, sym, byName);
4088 sym.flags_field |= CLASH;
4089 return true;
4090 } else if ((sym.flags() & MATCH_BINDING) != 0 &&
4091 (byName.flags() & MATCH_BINDING) != 0 &&
4092 (byName.flags() & MATCH_BINDING_TO_OUTER) == 0) {
4093 if (!sym.type.isErroneous()) {
4094 log.error(pos, Errors.MatchBindingExists);
4095 sym.flags_field |= CLASH;
4096 }
4097 return false;
4098 } else {
4099 duplicateError(pos, byName);
4100 return false;
4101 }
4102 }
4103 }
4104 return true;
4105 }
4106
4107 /** Report duplicate declaration error.
4108 */
4109 void duplicateErasureError(DiagnosticPosition pos, Symbol sym1, Symbol sym2) {
4110 if (!sym1.type.isErroneous() && !sym2.type.isErroneous()) {
4111 log.error(pos, Errors.NameClashSameErasure(sym1, sym2));
4112 }
4113 }
4114
4115 /**Check that types imported through the ordinary imports don't clash with types imported
4116 * by other (static or ordinary) imports. Note that two static imports may import two clashing
4117 * types without an error on the imports.
4118 * @param toplevel The toplevel tree for which the test should be performed.
4119 */
4120 void checkImportsUnique(JCCompilationUnit toplevel) {
4121 WriteableScope ordinallyImportedSoFar = WriteableScope.create(toplevel.packge);
4122 WriteableScope staticallyImportedSoFar = WriteableScope.create(toplevel.packge);
4123 WriteableScope topLevelScope = toplevel.toplevelScope;
4124
4125 for (JCTree def : toplevel.defs) {
4126 if (!def.hasTag(IMPORT))
4127 continue;
4128
4129 JCImport imp = (JCImport) def;
4130
4131 if (imp.importScope == null)
4132 continue;
4133
4134 for (Symbol sym : imp.importScope.getSymbols(sym -> sym.kind == TYP)) {
4135 if (imp.isStatic()) {
4136 checkUniqueImport(imp.pos(), ordinallyImportedSoFar, staticallyImportedSoFar, topLevelScope, sym, true);
4137 staticallyImportedSoFar.enter(sym);
4138 } else {
4139 checkUniqueImport(imp.pos(), ordinallyImportedSoFar, staticallyImportedSoFar, topLevelScope, sym, false);
4140 ordinallyImportedSoFar.enter(sym);
4141 }
4142 }
4143
4144 imp.importScope = null;
4145 }
4146 }
4147
4148 /** Check that single-type import is not already imported or top-level defined,
4149 * but make an exception for two single-type imports which denote the same type.
4150 * @param pos Position for error reporting.
4151 * @param ordinallyImportedSoFar A Scope containing types imported so far through
4152 * ordinary imports.
4153 * @param staticallyImportedSoFar A Scope containing types imported so far through
4154 * static imports.
4155 * @param topLevelScope The current file's top-level Scope
4156 * @param sym The symbol.
4157 * @param staticImport Whether or not this was a static import
4158 */
4159 private boolean checkUniqueImport(DiagnosticPosition pos, Scope ordinallyImportedSoFar,
4160 Scope staticallyImportedSoFar, Scope topLevelScope,
4161 Symbol sym, boolean staticImport) {
4162 Predicate<Symbol> duplicates = candidate -> candidate != sym && !candidate.type.isErroneous();
4163 Symbol ordinaryClashing = ordinallyImportedSoFar.findFirst(sym.name, duplicates);
4164 Symbol staticClashing = null;
4165 if (ordinaryClashing == null && !staticImport) {
4166 staticClashing = staticallyImportedSoFar.findFirst(sym.name, duplicates);
4167 }
4168 if (ordinaryClashing != null || staticClashing != null) {
4169 if (ordinaryClashing != null)
4170 log.error(pos, Errors.AlreadyDefinedSingleImport(ordinaryClashing));
4171 else
4172 log.error(pos, Errors.AlreadyDefinedStaticSingleImport(staticClashing));
4173 return false;
4174 }
4175 Symbol clashing = topLevelScope.findFirst(sym.name, duplicates);
4176 if (clashing != null) {
4177 log.error(pos, Errors.AlreadyDefinedThisUnit(clashing));
4178 return false;
4179 }
4180 return true;
4181 }
4182
4183 /** Check that a qualified name is in canonical form (for import decls).
4184 */
4185 public void checkCanonical(JCTree tree) {
4186 if (!isCanonical(tree))
4187 log.error(tree.pos(),
4188 Errors.ImportRequiresCanonical(TreeInfo.symbol(tree)));
4189 }
4190 // where
4191 private boolean isCanonical(JCTree tree) {
4192 while (tree.hasTag(SELECT)) {
4193 JCFieldAccess s = (JCFieldAccess) tree;
4194 if (s.sym.owner.getQualifiedName() != TreeInfo.symbol(s.selected).getQualifiedName())
4195 return false;
4196 tree = s.selected;
4197 }
4198 return true;
4199 }
4200
4201 /** Check that an auxiliary class is not accessed from any other file than its own.
4202 */
4203 void checkForBadAuxiliaryClassAccess(DiagnosticPosition pos, Env<AttrContext> env, ClassSymbol c) {
4204 if ((c.flags() & AUXILIARY) != 0 &&
4205 rs.isAccessible(env, c) &&
4206 !fileManager.isSameFile(c.sourcefile, env.toplevel.sourcefile))
4207 {
4208 log.warning(pos, LintWarnings.AuxiliaryClassAccessedFromOutsideOfItsSourceFile(c, c.sourcefile));
4209 }
4210 }
4211
4212 /**
4213 * Check for a default constructor in an exported package.
4214 */
4215 void checkDefaultConstructor(ClassSymbol c, DiagnosticPosition pos) {
4216 if (lint.isEnabled(LintCategory.MISSING_EXPLICIT_CTOR) &&
4217 ((c.flags() & (ENUM | RECORD)) == 0) &&
4218 !c.isAnonymous() &&
4219 ((c.flags() & (PUBLIC | PROTECTED)) != 0) &&
4220 Feature.MODULES.allowedInSource(source)) {
4221 NestingKind nestingKind = c.getNestingKind();
4222 switch (nestingKind) {
4223 case ANONYMOUS,
4224 LOCAL -> {return;}
4225 case TOP_LEVEL -> {;} // No additional checks needed
4226 case MEMBER -> {
4227 // For nested member classes, all the enclosing
4228 // classes must be public or protected.
4229 Symbol owner = c.owner;
4230 while (owner != null && owner.kind == TYP) {
4231 if ((owner.flags() & (PUBLIC | PROTECTED)) == 0)
4232 return;
4233 owner = owner.owner;
4234 }
4235 }
4236 }
4237
4238 // Only check classes in named packages exported by its module
4239 PackageSymbol pkg = c.packge();
4240 if (!pkg.isUnnamed()) {
4241 ModuleSymbol modle = pkg.modle;
4242 for (ExportsDirective exportDir : modle.exports) {
4243 // Report warning only if the containing
4244 // package is unconditionally exported
4245 if (exportDir.packge.equals(pkg)) {
4246 if (exportDir.modules == null || exportDir.modules.isEmpty()) {
4247 // Warning may be suppressed by
4248 // annotations; check again for being
4249 // enabled in the deferred context.
4250 log.warning(pos, LintWarnings.MissingExplicitCtor(c, pkg, modle));
4251 } else {
4252 return;
4253 }
4254 }
4255 }
4256 }
4257 }
4258 return;
4259 }
4260
4261 private class ConversionWarner extends Warner {
4262 final String uncheckedKey;
4263 final Type found;
4264 final Type expected;
4265 public ConversionWarner(DiagnosticPosition pos, String uncheckedKey, Type found, Type expected) {
4266 super(pos);
4267 this.uncheckedKey = uncheckedKey;
4268 this.found = found;
4269 this.expected = expected;
4270 }
4271
4272 @Override
4273 public void warn(LintCategory lint) {
4274 boolean warned = this.warned;
4275 super.warn(lint);
4276 if (warned) return; // suppress redundant diagnostics
4277 switch (lint) {
4278 case UNCHECKED:
4279 Check.this.warnUnchecked(pos(), LintWarnings.ProbFoundReq(diags.fragment(uncheckedKey), found, expected));
4280 break;
4281 case VARARGS:
4282 if (method != null &&
4283 method.attribute(syms.trustMeType.tsym) != null &&
4284 isTrustMeAllowedOnMethod(method) &&
4285 !types.isReifiable(method.type.getParameterTypes().last())) {
4286 log.warning(pos(), LintWarnings.VarargsUnsafeUseVarargsParam(method.params.last()));
4287 }
4288 break;
4289 default:
4290 throw new AssertionError("Unexpected lint: " + lint);
4291 }
4292 }
4293 }
4294
4295 public Warner castWarner(DiagnosticPosition pos, Type found, Type expected) {
4296 return new ConversionWarner(pos, "unchecked.cast.to.type", found, expected);
4297 }
4298
4299 public Warner convertWarner(DiagnosticPosition pos, Type found, Type expected) {
4300 return new ConversionWarner(pos, "unchecked.assign", found, expected);
4301 }
4302
4303 public void checkFunctionalInterface(JCClassDecl tree, ClassSymbol cs) {
4304 Compound functionalType = cs.attribute(syms.functionalInterfaceType.tsym);
4305
4306 if (functionalType != null) {
4307 try {
4308 types.findDescriptorSymbol((TypeSymbol)cs);
4309 } catch (Types.FunctionDescriptorLookupError ex) {
4310 DiagnosticPosition pos = tree.pos();
4311 for (JCAnnotation a : tree.getModifiers().annotations) {
4312 if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) {
4313 pos = a.pos();
4314 break;
4315 }
4316 }
4317 log.error(pos, Errors.BadFunctionalIntfAnno1(ex.getDiagnostic()));
4318 }
4319 }
4320 }
4321
4322 public void checkImportsResolvable(final JCCompilationUnit toplevel) {
4323 for (final JCImportBase impBase : toplevel.getImports()) {
4324 if (!(impBase instanceof JCImport imp))
4325 continue;
4326 if (!imp.staticImport || !imp.qualid.hasTag(SELECT))
4327 continue;
4328 final JCFieldAccess select = imp.qualid;
4329 final Symbol origin;
4330 if (select.name == names.asterisk || (origin = TreeInfo.symbol(select.selected)) == null || origin.kind != TYP)
4331 continue;
4332
4333 TypeSymbol site = (TypeSymbol) TreeInfo.symbol(select.selected);
4334 if (!checkTypeContainsImportableElement(site, site, toplevel.packge, select.name, new HashSet<Symbol>())) {
4335 log.error(imp.pos(),
4336 Errors.CantResolveLocation(KindName.STATIC,
4337 select.name,
4338 null,
4339 null,
4340 Fragments.Location(kindName(site),
4341 site,
4342 null)));
4343 }
4344 }
4345 }
4346
4347 // Check that packages imported are in scope (JLS 7.4.3, 6.3, 6.5.3.1, 6.5.3.2)
4348 public void checkImportedPackagesObservable(final JCCompilationUnit toplevel) {
4349 OUTER: for (JCImportBase impBase : toplevel.getImports()) {
4350 if (impBase instanceof JCImport imp && !imp.staticImport &&
4351 TreeInfo.name(imp.qualid) == names.asterisk) {
4352 TypeSymbol tsym = imp.qualid.selected.type.tsym;
4353 if (tsym.kind == PCK && tsym.members().isEmpty() &&
4354 !(Feature.IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES.allowedInSource(source) && tsym.exists())) {
4355 log.error(DiagnosticFlag.RESOLVE_ERROR, imp.qualid.selected.pos(), Errors.DoesntExist(tsym));
4356 }
4357 }
4358 }
4359 }
4360
4361 private boolean checkTypeContainsImportableElement(TypeSymbol tsym, TypeSymbol origin, PackageSymbol packge, Name name, Set<Symbol> processed) {
4362 if (tsym == null || !processed.add(tsym))
4363 return false;
4364
4365 // also search through inherited names
4366 if (checkTypeContainsImportableElement(types.supertype(tsym.type).tsym, origin, packge, name, processed))
4367 return true;
4368
4369 for (Type t : types.interfaces(tsym.type))
4370 if (checkTypeContainsImportableElement(t.tsym, origin, packge, name, processed))
4371 return true;
4372
4373 for (Symbol sym : tsym.members().getSymbolsByName(name)) {
4374 if (sym.isStatic() &&
4375 importAccessible(sym, packge) &&
4376 sym.isMemberOf(origin, types)) {
4377 return true;
4378 }
4379 }
4380
4381 return false;
4382 }
4383
4384 // is the sym accessible everywhere in packge?
4385 public boolean importAccessible(Symbol sym, PackageSymbol packge) {
4386 try {
4387 int flags = (int)(sym.flags() & AccessFlags);
4388 switch (flags) {
4389 default:
4390 case PUBLIC:
4391 return true;
4392 case PRIVATE:
4393 return false;
4394 case 0:
4395 case PROTECTED:
4396 return sym.packge() == packge;
4397 }
4398 } catch (ClassFinder.BadClassFile err) {
4399 throw err;
4400 } catch (CompletionFailure ex) {
4401 return false;
4402 }
4403 }
4404
4405 public void checkLeaksNotAccessible(Env<AttrContext> env, JCClassDecl check) {
4406 JCCompilationUnit toplevel = env.toplevel;
4407
4408 if ( toplevel.modle == syms.unnamedModule
4409 || toplevel.modle == syms.noModule
4410 || (check.sym.flags() & COMPOUND) != 0) {
4411 return ;
4412 }
4413
4414 ExportsDirective currentExport = findExport(toplevel.packge);
4415
4416 if ( currentExport == null //not exported
4417 || currentExport.modules != null) //don't check classes in qualified export
4418 return ;
4419
4420 new TreeScanner() {
4421 Lint lint = env.info.lint;
4422 boolean inSuperType;
4423
4424 @Override
4425 public void visitBlock(JCBlock tree) {
4426 }
4427 @Override
4428 public void visitMethodDef(JCMethodDecl tree) {
4429 if (!isAPISymbol(tree.sym))
4430 return;
4431 Lint prevLint = lint;
4432 try {
4433 lint = lint.augment(tree.sym);
4434 if (lint.isEnabled(LintCategory.EXPORTS)) {
4435 super.visitMethodDef(tree);
4436 }
4437 } finally {
4438 lint = prevLint;
4439 }
4440 }
4441 @Override
4442 public void visitVarDef(JCVariableDecl tree) {
4443 if (!isAPISymbol(tree.sym) && tree.sym.owner.kind != MTH)
4444 return;
4445 Lint prevLint = lint;
4446 try {
4447 lint = lint.augment(tree.sym);
4448 if (lint.isEnabled(LintCategory.EXPORTS)) {
4449 scan(tree.mods);
4450 scan(tree.vartype);
4451 }
4452 } finally {
4453 lint = prevLint;
4454 }
4455 }
4456 @Override
4457 public void visitClassDef(JCClassDecl tree) {
4458 if (tree != check)
4459 return ;
4460
4461 if (!isAPISymbol(tree.sym))
4462 return ;
4463
4464 Lint prevLint = lint;
4465 try {
4466 lint = lint.augment(tree.sym);
4467 if (lint.isEnabled(LintCategory.EXPORTS)) {
4468 scan(tree.mods);
4469 scan(tree.typarams);
4470 try {
4471 inSuperType = true;
4472 scan(tree.extending);
4473 scan(tree.implementing);
4474 } finally {
4475 inSuperType = false;
4476 }
4477 scan(tree.defs);
4478 }
4479 } finally {
4480 lint = prevLint;
4481 }
4482 }
4483 @Override
4484 public void visitTypeApply(JCTypeApply tree) {
4485 scan(tree.clazz);
4486 boolean oldInSuperType = inSuperType;
4487 try {
4488 inSuperType = false;
4489 scan(tree.arguments);
4490 } finally {
4491 inSuperType = oldInSuperType;
4492 }
4493 }
4494 @Override
4495 public void visitIdent(JCIdent tree) {
4496 Symbol sym = TreeInfo.symbol(tree);
4497 if (sym.kind == TYP && !sym.type.hasTag(TYPEVAR)) {
4498 checkVisible(tree.pos(), sym, toplevel.packge, inSuperType);
4499 }
4500 }
4501
4502 @Override
4503 public void visitSelect(JCFieldAccess tree) {
4504 Symbol sym = TreeInfo.symbol(tree);
4505 Symbol sitesym = TreeInfo.symbol(tree.selected);
4506 if (sym.kind == TYP && sitesym.kind == PCK) {
4507 checkVisible(tree.pos(), sym, toplevel.packge, inSuperType);
4508 } else {
4509 super.visitSelect(tree);
4510 }
4511 }
4512
4513 @Override
4514 public void visitAnnotation(JCAnnotation tree) {
4515 if (tree.attribute.type.tsym.getAnnotation(java.lang.annotation.Documented.class) != null)
4516 super.visitAnnotation(tree);
4517 }
4518
4519 }.scan(check);
4520 }
4521 //where:
4522 private ExportsDirective findExport(PackageSymbol pack) {
4523 for (ExportsDirective d : pack.modle.exports) {
4524 if (d.packge == pack)
4525 return d;
4526 }
4527
4528 return null;
4529 }
4530 private boolean isAPISymbol(Symbol sym) {
4531 while (sym.kind != PCK) {
4532 if ((sym.flags() & Flags.PUBLIC) == 0 && (sym.flags() & Flags.PROTECTED) == 0) {
4533 return false;
4534 }
4535 sym = sym.owner;
4536 }
4537 return true;
4538 }
4539 private void checkVisible(DiagnosticPosition pos, Symbol what, PackageSymbol inPackage, boolean inSuperType) {
4540 if (!isAPISymbol(what) && !inSuperType) { //package private/private element
4541 log.warning(pos, LintWarnings.LeaksNotAccessible(kindName(what), what, what.packge().modle));
4542 return ;
4543 }
4544
4545 PackageSymbol whatPackage = what.packge();
4546 ExportsDirective whatExport = findExport(whatPackage);
4547 ExportsDirective inExport = findExport(inPackage);
4548
4549 if (whatExport == null) { //package not exported:
4550 log.warning(pos, LintWarnings.LeaksNotAccessibleUnexported(kindName(what), what, what.packge().modle));
4551 return ;
4552 }
4553
4554 if (whatExport.modules != null) {
4555 if (inExport.modules == null || !whatExport.modules.containsAll(inExport.modules)) {
4556 log.warning(pos, LintWarnings.LeaksNotAccessibleUnexportedQualified(kindName(what), what, what.packge().modle));
4557 }
4558 }
4559
4560 if (whatPackage.modle != inPackage.modle && whatPackage.modle != syms.java_base) {
4561 //check that relativeTo.modle requires transitive what.modle, somehow:
4562 List<ModuleSymbol> todo = List.of(inPackage.modle);
4563
4564 while (todo.nonEmpty()) {
4565 ModuleSymbol current = todo.head;
4566 todo = todo.tail;
4567 if (current == whatPackage.modle)
4568 return ; //OK
4569 if ((current.flags() & Flags.AUTOMATIC_MODULE) != 0)
4570 continue; //for automatic modules, don't look into their dependencies
4571 for (RequiresDirective req : current.requires) {
4572 if (req.isTransitive()) {
4573 todo = todo.prepend(req.module);
4574 }
4575 }
4576 }
4577
4578 log.warning(pos, LintWarnings.LeaksNotAccessibleNotRequiredTransitive(kindName(what), what, what.packge().modle));
4579 }
4580 }
4581
4582 void checkModuleExists(final DiagnosticPosition pos, ModuleSymbol msym) {
4583 if (msym.kind != MDL) {
4584 log.warning(pos, LintWarnings.ModuleNotFound(msym));
4585 }
4586 }
4587
4588 void checkPackageExistsForOpens(final DiagnosticPosition pos, PackageSymbol packge) {
4589 if (packge.members().isEmpty() &&
4590 ((packge.flags() & Flags.HAS_RESOURCE) == 0)) {
4591 log.warning(pos, LintWarnings.PackageEmptyOrNotFound(packge));
4592 }
4593 }
4594
4595 void checkModuleRequires(final DiagnosticPosition pos, final RequiresDirective rd) {
4596 if ((rd.module.flags() & Flags.AUTOMATIC_MODULE) != 0) {
4597 if (rd.isTransitive()) { // see comment in Log.applyLint() for special logic that applies
4598 log.warning(pos, LintWarnings.RequiresTransitiveAutomatic);
4599 } else {
4600 log.warning(pos, LintWarnings.RequiresAutomatic);
4601 }
4602 }
4603 }
4604
4605 /**
4606 * Verify the case labels conform to the constraints. Checks constraints related
4607 * combinations of patterns and other labels.
4608 *
4609 * @param cases the cases that should be checked.
4610 */
4611 void checkSwitchCaseStructure(List<JCCase> cases) {
4612 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
4613 JCCase c = l.head;
4614 if (c.labels.head instanceof JCConstantCaseLabel constLabel) {
4615 if (TreeInfo.isNull(constLabel.expr)) {
4616 if (c.labels.tail.nonEmpty()) {
4617 if (c.labels.tail.head instanceof JCDefaultCaseLabel defLabel) {
4618 if (c.labels.tail.tail.nonEmpty()) {
4619 log.error(c.labels.tail.tail.head.pos(), Errors.InvalidCaseLabelCombination);
4620 }
4621 } else {
4622 log.error(c.labels.tail.head.pos(), Errors.InvalidCaseLabelCombination);
4623 }
4624 }
4625 } else {
4626 for (JCCaseLabel label : c.labels.tail) {
4627 if (!(label instanceof JCConstantCaseLabel) || TreeInfo.isNullCaseLabel(label)) {
4628 log.error(label.pos(), Errors.InvalidCaseLabelCombination);
4629 break;
4630 }
4631 }
4632 }
4633 } else if (c.labels.tail.nonEmpty()) {
4634 var patterCaseLabels = c.labels.stream().filter(ll -> ll instanceof JCPatternCaseLabel).map(cl -> (JCPatternCaseLabel)cl);
4635 var allUnderscore = patterCaseLabels.allMatch(pcl -> !hasBindings(pcl.getPattern()));
4636
4637 if (!allUnderscore) {
4638 log.error(c.labels.tail.head.pos(), Errors.FlowsThroughFromPattern);
4639 }
4640
4641 boolean allPatternCaseLabels = c.labels.stream().allMatch(p -> p instanceof JCPatternCaseLabel);
4642
4643 if (allPatternCaseLabels) {
4644 preview.checkSourceLevel(c.labels.tail.head.pos(), Feature.UNNAMED_VARIABLES);
4645 }
4646
4647 for (JCCaseLabel label : c.labels.tail) {
4648 if (label instanceof JCConstantCaseLabel) {
4649 log.error(label.pos(), Errors.InvalidCaseLabelCombination);
4650 break;
4651 }
4652 }
4653 }
4654 }
4655
4656 boolean isCaseStatementGroup = cases.nonEmpty() &&
4657 cases.head.caseKind == CaseTree.CaseKind.STATEMENT;
4658
4659 if (isCaseStatementGroup) {
4660 boolean previousCompletessNormally = false;
4661 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
4662 JCCase c = l.head;
4663 if (previousCompletessNormally &&
4664 c.stats.nonEmpty() &&
4665 c.labels.head instanceof JCPatternCaseLabel patternLabel &&
4666 (hasBindings(patternLabel.pat) || hasBindings(c.guard))) {
4667 log.error(c.labels.head.pos(), Errors.FlowsThroughToPattern);
4668 } else if (c.stats.isEmpty() &&
4669 c.labels.head instanceof JCPatternCaseLabel patternLabel &&
4670 (hasBindings(patternLabel.pat) || hasBindings(c.guard)) &&
4671 hasStatements(l.tail)) {
4672 log.error(c.labels.head.pos(), Errors.FlowsThroughFromPattern);
4673 }
4674 previousCompletessNormally = c.completesNormally;
4675 }
4676 }
4677 }
4678
4679 boolean hasBindings(JCTree p) {
4680 boolean[] bindings = new boolean[1];
4681
4682 new TreeScanner() {
4683 @Override
4684 public void visitBindingPattern(JCBindingPattern tree) {
4685 bindings[0] |= !tree.var.sym.isUnnamedVariable();
4686 super.visitBindingPattern(tree);
4687 }
4688 }.scan(p);
4689
4690 return bindings[0];
4691 }
4692
4693 boolean hasStatements(List<JCCase> cases) {
4694 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
4695 if (l.head.stats.nonEmpty()) {
4696 return true;
4697 }
4698 }
4699
4700 return false;
4701 }
4702 void checkSwitchCaseLabelDominated(JCCaseLabel unconditionalCaseLabel, List<JCCase> cases) {
4703 List<Pair<JCCase, JCCaseLabel>> caseLabels = List.nil();
4704 boolean seenDefault = false;
4705 boolean seenDefaultLabel = false;
4706 boolean warnDominatedByDefault = false;
4707 boolean unconditionalFound = false;
4708
4709 for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
4710 JCCase c = l.head;
4711 for (JCCaseLabel label : c.labels) {
4712 if (label.hasTag(DEFAULTCASELABEL)) {
4713 seenDefault = true;
4714 seenDefaultLabel |=
4715 TreeInfo.isNullCaseLabel(c.labels.head);
4716 continue;
4717 }
4718 if (TreeInfo.isNullCaseLabel(label)) {
4719 if (seenDefault) {
4720 log.error(label.pos(), Errors.PatternDominated);
4721 }
4722 continue;
4723 }
4724 if (seenDefault && !warnDominatedByDefault) {
4725 if (label.hasTag(PATTERNCASELABEL) ||
4726 (label instanceof JCConstantCaseLabel && seenDefaultLabel)) {
4727 log.error(label.pos(), Errors.PatternDominated);
4728 warnDominatedByDefault = true;
4729 }
4730 }
4731 Type currentType = labelType(label);
4732 for (Pair<JCCase, JCCaseLabel> caseAndLabel : caseLabels) {
4733 JCCase testCase = caseAndLabel.fst;
4734 JCCaseLabel testCaseLabel = caseAndLabel.snd;
4735 Type testType = labelType(testCaseLabel);
4736 boolean dominated = false;
4737 if (types.isUnconditionallyExact(currentType, testType) &&
4738 !currentType.hasTag(ERROR) && !testType.hasTag(ERROR)) {
4739 //the current label is potentially dominated by the existing (test) label, check:
4740 if (label instanceof JCConstantCaseLabel) {
4741 dominated |= !(testCaseLabel instanceof JCConstantCaseLabel) &&
4742 TreeInfo.unguardedCase(testCase);
4743 } else if (label instanceof JCPatternCaseLabel patternCL &&
4744 testCaseLabel instanceof JCPatternCaseLabel testPatternCaseLabel &&
4745 (testCase.equals(c) || TreeInfo.unguardedCase(testCase))) {
4746 dominated = patternDominated(testPatternCaseLabel.pat,
4747 patternCL.pat);
4748 }
4749 }
4750
4751 if (dominated) {
4752 log.error(label.pos(), Errors.PatternDominated);
4753 }
4754 }
4755 caseLabels = caseLabels.prepend(Pair.of(c, label));
4756 }
4757 }
4758 }
4759 //where:
4760 private Type labelType(JCCaseLabel label) {
4761 return types.erasure(switch (label.getTag()) {
4762 case PATTERNCASELABEL -> ((JCPatternCaseLabel) label).pat.type;
4763 case CONSTANTCASELABEL -> ((JCConstantCaseLabel) label).expr.type;
4764 default -> throw Assert.error("Unexpected tree kind: " + label.getTag());
4765 });
4766 }
4767 private boolean patternDominated(JCPattern existingPattern, JCPattern currentPattern) {
4768 Type existingPatternType = types.erasure(existingPattern.type);
4769 Type currentPatternType = types.erasure(currentPattern.type);
4770 if (!types.isUnconditionallyExact(currentPatternType, existingPatternType)) {
4771 return false;
4772 }
4773 if (currentPattern instanceof JCBindingPattern ||
4774 currentPattern instanceof JCAnyPattern) {
4775 return existingPattern instanceof JCBindingPattern ||
4776 existingPattern instanceof JCAnyPattern;
4777 } else if (currentPattern instanceof JCRecordPattern currentRecordPattern) {
4778 if (existingPattern instanceof JCBindingPattern ||
4779 existingPattern instanceof JCAnyPattern) {
4780 return true;
4781 } else if (existingPattern instanceof JCRecordPattern existingRecordPattern) {
4782 List<JCPattern> existingNested = existingRecordPattern.nested;
4783 List<JCPattern> currentNested = currentRecordPattern.nested;
4784 if (existingNested.size() != currentNested.size()) {
4785 return false;
4786 }
4787 while (existingNested.nonEmpty()) {
4788 if (!patternDominated(existingNested.head, currentNested.head)) {
4789 return false;
4790 }
4791 existingNested = existingNested.tail;
4792 currentNested = currentNested.tail;
4793 }
4794 return true;
4795 } else {
4796 Assert.error("Unknown pattern: " + existingPattern.getTag());
4797 }
4798 } else {
4799 Assert.error("Unknown pattern: " + currentPattern.getTag());
4800 }
4801 return false;
4802 }
4803
4804 /** check if a type is a subtype of Externalizable, if that is available. */
4805 boolean isExternalizable(Type t) {
4806 try {
4807 syms.externalizableType.complete();
4808 } catch (CompletionFailure e) {
4809 return false;
4810 }
4811 return types.isSubtype(t, syms.externalizableType);
4812 }
4813
4814 /**
4815 * Check structure of serialization declarations.
4816 */
4817 public void checkSerialStructure(JCClassDecl tree, ClassSymbol c) {
4818 (new SerialTypeVisitor()).visit(c, tree);
4819 }
4820
4821 /**
4822 * This visitor will warn if a serialization-related field or
4823 * method is declared in a suspicious or incorrect way. In
4824 * particular, it will warn for cases where the runtime
4825 * serialization mechanism will silently ignore a mis-declared
4826 * entity.
4827 *
4828 * Distinguished serialization-related fields and methods:
4829 *
4830 * Methods:
4831 *
4832 * private void writeObject(ObjectOutputStream stream) throws IOException
4833 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
4834 *
4835 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
4836 * private void readObjectNoData() throws ObjectStreamException
4837 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
4838 *
4839 * Fields:
4840 *
4841 * private static final long serialVersionUID
4842 * private static final ObjectStreamField[] serialPersistentFields
4843 *
4844 * Externalizable: methods defined on the interface
4845 * public void writeExternal(ObjectOutput) throws IOException
4846 * public void readExternal(ObjectInput) throws IOException
4847 */
4848 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
4849 SerialTypeVisitor() {
4850 this.lint = Check.this.lint;
4851 }
4852
4853 private static final Set<String> serialMethodNames =
4854 Set.of("writeObject", "writeReplace",
4855 "readObject", "readObjectNoData",
4856 "readResolve");
4857
4858 private static final Set<String> serialFieldNames =
4859 Set.of("serialVersionUID", "serialPersistentFields");
4860
4861 // Type of serialPersistentFields
4862 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
4863
4864 Lint lint;
4865
4866 @Override
4867 public Void defaultAction(Element e, JCClassDecl p) {
4868 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
4869 }
4870
4871 @Override
4872 public Void visitType(TypeElement e, JCClassDecl p) {
4873 runUnderLint(e, p, (symbol, param) -> super.visitType(symbol, param));
4874 return null;
4875 }
4876
4877 @Override
4878 public Void visitTypeAsClass(TypeElement e,
4879 JCClassDecl p) {
4880 // Anonymous classes filtered out by caller.
4881
4882 ClassSymbol c = (ClassSymbol)e;
4883
4884 checkCtorAccess(p, c);
4885
4886 // Check for missing serialVersionUID; check *not* done
4887 // for enums or records.
4888 VarSymbol svuidSym = null;
4889 for (Symbol sym : c.members().getSymbolsByName(names.serialVersionUID)) {
4890 if (sym.kind == VAR) {
4891 svuidSym = (VarSymbol)sym;
4892 break;
4893 }
4894 }
4895
4896 if (svuidSym == null) {
4897 log.warning(p.pos(), LintWarnings.MissingSVUID(c));
4898 }
4899
4900 // Check for serialPersistentFields to gate checks for
4901 // non-serializable non-transient instance fields
4902 boolean serialPersistentFieldsPresent =
4903 c.members()
4904 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
4905 .iterator()
4906 .hasNext();
4907
4908 // Check declarations of serialization-related methods and
4909 // fields
4910 for(Symbol el : c.getEnclosedElements()) {
4911 runUnderLint(el, p, (enclosed, tree) -> {
4912 String name = null;
4913 switch(enclosed.getKind()) {
4914 case FIELD -> {
4915 if (!serialPersistentFieldsPresent) {
4916 var flags = enclosed.flags();
4917 if ( ((flags & TRANSIENT) == 0) &&
4918 ((flags & STATIC) == 0)) {
4919 Type varType = enclosed.asType();
4920 if (!canBeSerialized(varType)) {
4921 // Note per JLS arrays are
4922 // serializable even if the
4923 // component type is not.
4924 log.warning(
4925 TreeInfo.diagnosticPositionFor(enclosed, tree),
4926 LintWarnings.NonSerializableInstanceField);
4927 } else if (varType.hasTag(ARRAY)) {
4928 ArrayType arrayType = (ArrayType)varType;
4929 Type elementType = arrayType.elemtype;
4930 while (elementType.hasTag(ARRAY)) {
4931 arrayType = (ArrayType)elementType;
4932 elementType = arrayType.elemtype;
4933 }
4934 if (!canBeSerialized(elementType)) {
4935 log.warning(
4936 TreeInfo.diagnosticPositionFor(enclosed, tree),
4937 LintWarnings.NonSerializableInstanceFieldArray(elementType));
4938 }
4939 }
4940 }
4941 }
4942
4943 name = enclosed.getSimpleName().toString();
4944 if (serialFieldNames.contains(name)) {
4945 VarSymbol field = (VarSymbol)enclosed;
4946 switch (name) {
4947 case "serialVersionUID" -> checkSerialVersionUID(tree, e, field);
4948 case "serialPersistentFields" -> checkSerialPersistentFields(tree, e, field);
4949 default -> throw new AssertionError();
4950 }
4951 }
4952 }
4953
4954 // Correctly checking the serialization-related
4955 // methods is subtle. For the methods declared to be
4956 // private or directly declared in the class, the
4957 // enclosed elements of the class can be checked in
4958 // turn. However, writeReplace and readResolve can be
4959 // declared in a superclass and inherited. Note that
4960 // the runtime lookup walks the superclass chain
4961 // looking for writeReplace/readResolve via
4962 // Class.getDeclaredMethod. This differs from calling
4963 // Elements.getAllMembers(TypeElement) as the latter
4964 // will also pull in default methods from
4965 // superinterfaces. In other words, the runtime checks
4966 // (which long predate default methods on interfaces)
4967 // do not admit the possibility of inheriting methods
4968 // this way, a difference from general inheritance.
4969
4970 // The current implementation just checks the enclosed
4971 // elements and does not directly check the inherited
4972 // methods. If all the types are being checked this is
4973 // less of a concern; however, there are cases that
4974 // could be missed. In particular, readResolve and
4975 // writeReplace could, in principle, by inherited from
4976 // a non-serializable superclass and thus not checked
4977 // even if compiled with a serializable child class.
4978 case METHOD -> {
4979 var method = (MethodSymbol)enclosed;
4980 name = method.getSimpleName().toString();
4981 if (serialMethodNames.contains(name)) {
4982 switch (name) {
4983 case "writeObject" -> checkWriteObject(tree, e, method);
4984 case "writeReplace" -> checkWriteReplace(tree,e, method);
4985 case "readObject" -> checkReadObject(tree,e, method);
4986 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
4987 case "readResolve" -> checkReadResolve(tree, e, method);
4988 default -> throw new AssertionError();
4989 }
4990 }
4991 }
4992 }
4993 });
4994 }
4995
4996 return null;
4997 }
4998
4999 boolean canBeSerialized(Type type) {
5000 return type.isPrimitive() || rs.isSerializable(type);
5001 }
5002
5003 /**
5004 * Check that Externalizable class needs a public no-arg
5005 * constructor.
5006 *
5007 * Check that a Serializable class has access to the no-arg
5008 * constructor of its first nonserializable superclass.
5009 */
5010 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5011 if (isExternalizable(c.type)) {
5012 for(var sym : c.getEnclosedElements()) {
5013 if (sym.isConstructor() &&
5014 ((sym.flags() & PUBLIC) == PUBLIC)) {
5015 if (((MethodSymbol)sym).getParameters().isEmpty()) {
5016 return;
5017 }
5018 }
5019 }
5020 log.warning(tree.pos(),
5021 LintWarnings.ExternalizableMissingPublicNoArgCtor);
5022 } else {
5023 // Approximate access to the no-arg constructor up in
5024 // the superclass chain by checking that the
5025 // constructor is not private. This may not handle
5026 // some cross-package situations correctly.
5027 Type superClass = c.getSuperclass();
5028 // java.lang.Object is *not* Serializable so this loop
5029 // should terminate.
5030 while (rs.isSerializable(superClass) ) {
5031 try {
5032 superClass = (Type)((TypeElement)(((DeclaredType)superClass)).asElement()).getSuperclass();
5033 } catch(ClassCastException cce) {
5034 return ; // Don't try to recover
5035 }
5036 }
5037 // Non-Serializable superclass
5038 try {
5039 ClassSymbol supertype = ((ClassSymbol)(((DeclaredType)superClass).asElement()));
5040 for(var sym : supertype.getEnclosedElements()) {
5041 if (sym.isConstructor()) {
5042 MethodSymbol ctor = (MethodSymbol)sym;
5043 if (ctor.getParameters().isEmpty()) {
5044 if (((ctor.flags() & PRIVATE) == PRIVATE) ||
5045 // Handle nested classes and implicit this$0
5046 (supertype.getNestingKind() == NestingKind.MEMBER &&
5047 ((supertype.flags() & STATIC) == 0)))
5048 log.warning(tree.pos(),
5049 LintWarnings.SerializableMissingAccessNoArgCtor(supertype.getQualifiedName()));
5050 }
5051 }
5052 }
5053 } catch (ClassCastException cce) {
5054 return ; // Don't try to recover
5055 }
5056 return;
5057 }
5058 }
5059
5060 private void checkSerialVersionUID(JCClassDecl tree, Element e, VarSymbol svuid) {
5061 // To be effective, serialVersionUID must be marked static
5062 // and final, but private is recommended. But alas, in
5063 // practice there are many non-private serialVersionUID
5064 // fields.
5065 if ((svuid.flags() & (STATIC | FINAL)) !=
5066 (STATIC | FINAL)) {
5067 log.warning(
5068 TreeInfo.diagnosticPositionFor(svuid, tree),
5069 LintWarnings.ImproperSVUID((Symbol)e));
5070 }
5071
5072 // check svuid has type long
5073 if (!svuid.type.hasTag(LONG)) {
5074 log.warning(
5075 TreeInfo.diagnosticPositionFor(svuid, tree),
5076 LintWarnings.LongSVUID((Symbol)e));
5077 }
5078
5079 if (svuid.getConstValue() == null)
5080 log.warning(
5081 TreeInfo.diagnosticPositionFor(svuid, tree),
5082 LintWarnings.ConstantSVUID((Symbol)e));
5083 }
5084
5085 private void checkSerialPersistentFields(JCClassDecl tree, Element e, VarSymbol spf) {
5086 // To be effective, serialPersisentFields must be private, static, and final.
5087 if ((spf.flags() & (PRIVATE | STATIC | FINAL)) !=
5088 (PRIVATE | STATIC | FINAL)) {
5089 log.warning(
5090 TreeInfo.diagnosticPositionFor(spf, tree),
5091 LintWarnings.ImproperSPF);
5092 }
5093
5094 if (!types.isSameType(spf.type, OSF_TYPE)) {
5095 log.warning(
5096 TreeInfo.diagnosticPositionFor(spf, tree),
5097 LintWarnings.OSFArraySPF);
5098 }
5099
5100 if (isExternalizable((Type)(e.asType()))) {
5101 log.warning(
5102 TreeInfo.diagnosticPositionFor(spf, tree),
5103 LintWarnings.IneffectualSerialFieldExternalizable);
5104 }
5105
5106 // Warn if serialPersistentFields is initialized to a
5107 // literal null.
5108 JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5109 if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5110 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5111 JCExpression initExpr = variableDef.init;
5112 if (initExpr != null && TreeInfo.isNull(initExpr)) {
5113 log.warning(initExpr.pos(),
5114 LintWarnings.SPFNullInit);
5115 }
5116 }
5117 }
5118
5119 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5120 // The "synchronized" modifier is seen in the wild on
5121 // readObject and writeObject methods and is generally
5122 // innocuous.
5123
5124 // private void writeObject(ObjectOutputStream stream) throws IOException
5125 checkPrivateNonStaticMethod(tree, method);
5126 checkReturnType(tree, e, method, syms.voidType);
5127 checkOneArg(tree, e, method, syms.objectOutputStreamType);
5128 checkExceptions(tree, e, method, syms.ioExceptionType);
5129 checkExternalizable(tree, e, method);
5130 }
5131
5132 private void checkWriteReplace(JCClassDecl tree, Element e, MethodSymbol method) {
5133 // ANY-ACCESS-MODIFIER Object writeReplace() throws
5134 // ObjectStreamException
5135
5136 // Excluding abstract, could have a more complicated
5137 // rule based on abstract-ness of the class
5138 checkConcreteInstanceMethod(tree, e, method);
5139 checkReturnType(tree, e, method, syms.objectType);
5140 checkNoArgs(tree, e, method);
5141 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5142 }
5143
5144 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5145 // The "synchronized" modifier is seen in the wild on
5146 // readObject and writeObject methods and is generally
5147 // innocuous.
5148
5149 // private void readObject(ObjectInputStream stream)
5150 // throws IOException, ClassNotFoundException
5151 checkPrivateNonStaticMethod(tree, method);
5152 checkReturnType(tree, e, method, syms.voidType);
5153 checkOneArg(tree, e, method, syms.objectInputStreamType);
5154 checkExceptions(tree, e, method, syms.ioExceptionType, syms.classNotFoundExceptionType);
5155 checkExternalizable(tree, e, method);
5156 }
5157
5158 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5159 // private void readObjectNoData() throws ObjectStreamException
5160 checkPrivateNonStaticMethod(tree, method);
5161 checkReturnType(tree, e, method, syms.voidType);
5162 checkNoArgs(tree, e, method);
5163 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5164 checkExternalizable(tree, e, method);
5165 }
5166
5167 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5168 // ANY-ACCESS-MODIFIER Object readResolve()
5169 // throws ObjectStreamException
5170
5171 // Excluding abstract, could have a more complicated
5172 // rule based on abstract-ness of the class
5173 checkConcreteInstanceMethod(tree, e, method);
5174 checkReturnType(tree,e, method, syms.objectType);
5175 checkNoArgs(tree, e, method);
5176 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5177 }
5178
5179 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5180 //public void writeExternal(ObjectOutput) throws IOException
5181 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5182 }
5183
5184 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5185 // public void readExternal(ObjectInput) throws IOException
5186 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5187 }
5188
5189 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5190 boolean isExtern) {
5191 if (isExtern && isExternMethod(tree, e, method, argType)) {
5192 log.warning(
5193 TreeInfo.diagnosticPositionFor(method, tree),
5194 LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5195 }
5196 }
5197
5198 void checkPrivateNonStaticMethod(JCClassDecl tree, MethodSymbol method) {
5199 var flags = method.flags();
5200 if ((flags & PRIVATE) == 0) {
5201 log.warning(
5202 TreeInfo.diagnosticPositionFor(method, tree),
5203 LintWarnings.SerialMethodNotPrivate(method.getSimpleName()));
5204 }
5205
5206 if ((flags & STATIC) != 0) {
5207 log.warning(
5208 TreeInfo.diagnosticPositionFor(method, tree),
5209 LintWarnings.SerialMethodStatic(method.getSimpleName()));
5210 }
5211 }
5212
5213 /**
5214 * Per section 1.12 "Serialization of Enum Constants" of
5215 * the serialization specification, due to the special
5216 * serialization handling of enums, any writeObject,
5217 * readObject, writeReplace, and readResolve methods are
5218 * ignored as are serialPersistentFields and
5219 * serialVersionUID fields.
5220 */
5221 @Override
5222 public Void visitTypeAsEnum(TypeElement e,
5223 JCClassDecl p) {
5224 boolean isExtern = isExternalizable((Type)e.asType());
5225 for(Element el : e.getEnclosedElements()) {
5226 runUnderLint(el, p, (enclosed, tree) -> {
5227 String name = enclosed.getSimpleName().toString();
5228 switch(enclosed.getKind()) {
5229 case FIELD -> {
5230 var field = (VarSymbol)enclosed;
5231 if (serialFieldNames.contains(name)) {
5232 log.warning(
5233 TreeInfo.diagnosticPositionFor(field, tree),
5234 LintWarnings.IneffectualSerialFieldEnum(name));
5235 }
5236 }
5237
5238 case METHOD -> {
5239 var method = (MethodSymbol)enclosed;
5240 if (serialMethodNames.contains(name)) {
5241 log.warning(
5242 TreeInfo.diagnosticPositionFor(method, tree),
5243 LintWarnings.IneffectualSerialMethodEnum(name));
5244 }
5245
5246 if (isExtern) {
5247 switch(name) {
5248 case "writeExternal" -> checkWriteExternalEnum(tree, e, method);
5249 case "readExternal" -> checkReadExternalEnum(tree, e, method);
5250 }
5251 }
5252 }
5253
5254 // Also perform checks on any class bodies of enum constants, see JLS 8.9.1.
5255 case ENUM_CONSTANT -> {
5256 var field = (VarSymbol)enclosed;
5257 JCVariableDecl decl = (JCVariableDecl) TreeInfo.declarationFor(field, p);
5258 if (decl.init instanceof JCNewClass nc && nc.def != null) {
5259 ClassSymbol enumConstantType = nc.def.sym;
5260 visitTypeAsEnum(enumConstantType, p);
5261 }
5262 }
5263
5264 }});
5265 }
5266 return null;
5267 }
5268
5269 private void checkWriteExternalEnum(JCClassDecl tree, Element e, MethodSymbol method) {
5270 //public void writeExternal(ObjectOutput) throws IOException
5271 checkExternMethodEnum(tree, e, method, syms.objectOutputType);
5272 }
5273
5274 private void checkReadExternalEnum(JCClassDecl tree, Element e, MethodSymbol method) {
5275 // public void readExternal(ObjectInput) throws IOException
5276 checkExternMethodEnum(tree, e, method, syms.objectInputType);
5277 }
5278
5279 private void checkExternMethodEnum(JCClassDecl tree, Element e, MethodSymbol method, Type argType) {
5280 if (isExternMethod(tree, e, method, argType)) {
5281 log.warning(
5282 TreeInfo.diagnosticPositionFor(method, tree),
5283 LintWarnings.IneffectualExternMethodEnum(method.getSimpleName().toString()));
5284 }
5285 }
5286
5287 private boolean isExternMethod(JCClassDecl tree, Element e, MethodSymbol method, Type argType) {
5288 long flags = method.flags();
5289 Type rtype = method.getReturnType();
5290
5291 // Not necessary to check throws clause in this context
5292 return (flags & PUBLIC) != 0 && (flags & STATIC) == 0 &&
5293 types.isSameType(syms.voidType, rtype) &&
5294 hasExactlyOneArgWithType(tree, e, method, argType);
5295 }
5296
5297 /**
5298 * Most serialization-related fields and methods on interfaces
5299 * are ineffectual or problematic.
5300 */
5301 @Override
5302 public Void visitTypeAsInterface(TypeElement e,
5303 JCClassDecl p) {
5304 for(Element el : e.getEnclosedElements()) {
5305 runUnderLint(el, p, (enclosed, tree) -> {
5306 String name = null;
5307 switch(enclosed.getKind()) {
5308 case FIELD -> {
5309 var field = (VarSymbol)enclosed;
5310 name = field.getSimpleName().toString();
5311 switch(name) {
5312 case "serialPersistentFields" -> {
5313 log.warning(
5314 TreeInfo.diagnosticPositionFor(field, tree),
5315 LintWarnings.IneffectualSerialFieldInterface);
5316 }
5317
5318 case "serialVersionUID" -> {
5319 checkSerialVersionUID(tree, e, field);
5320 }
5321 }
5322 }
5323
5324 case METHOD -> {
5325 var method = (MethodSymbol)enclosed;
5326 name = enclosed.getSimpleName().toString();
5327 if (serialMethodNames.contains(name)) {
5328 switch (name) {
5329 case
5330 "readObject",
5331 "readObjectNoData",
5332 "writeObject" -> checkPrivateMethod(tree, e, method);
5333
5334 case
5335 "writeReplace",
5336 "readResolve" -> checkDefaultIneffective(tree, e, method);
5337
5338 default -> throw new AssertionError();
5339 }
5340
5341 }
5342 }}
5343 });
5344 }
5345
5346 return null;
5347 }
5348
5349 private void checkPrivateMethod(JCClassDecl tree,
5350 Element e,
5351 MethodSymbol method) {
5352 if ((method.flags() & PRIVATE) == 0) {
5353 log.warning(
5354 TreeInfo.diagnosticPositionFor(method, tree),
5355 LintWarnings.NonPrivateMethodWeakerAccess);
5356 }
5357 }
5358
5359 private void checkDefaultIneffective(JCClassDecl tree,
5360 Element e,
5361 MethodSymbol method) {
5362 if ((method.flags() & DEFAULT) == DEFAULT) {
5363 log.warning(
5364 TreeInfo.diagnosticPositionFor(method, tree),
5365 LintWarnings.DefaultIneffective);
5366
5367 }
5368 }
5369
5370 @Override
5371 public Void visitTypeAsAnnotationType(TypeElement e,
5372 JCClassDecl p) {
5373 // Per the JLS, annotation types are not serializeable
5374 return null;
5375 }
5376
5377 /**
5378 * From the Java Object Serialization Specification, 1.13
5379 * Serialization of Records:
5380 *
5381 * "The process by which record objects are serialized or
5382 * externalized cannot be customized; any class-specific
5383 * writeObject, readObject, readObjectNoData, writeExternal,
5384 * and readExternal methods defined by record classes are
5385 * ignored during serialization and deserialization. However,
5386 * a substitute object to be serialized or a designate
5387 * replacement may be specified, by the writeReplace and
5388 * readResolve methods, respectively. Any
5389 * serialPersistentFields field declaration is
5390 * ignored. Documenting serializable fields and data for
5391 * record classes is unnecessary, since there is no variation
5392 * in the serial form, other than whether a substitute or
5393 * replacement object is used. The serialVersionUID of a
5394 * record class is 0L unless explicitly declared. The
5395 * requirement for matching serialVersionUID values is waived
5396 * for record classes."
5397 */
5398 @Override
5399 public Void visitTypeAsRecord(TypeElement e,
5400 JCClassDecl p) {
5401 boolean isExtern = isExternalizable((Type)e.asType());
5402 for(Element el : e.getEnclosedElements()) {
5403 runUnderLint(el, p, (enclosed, tree) -> {
5404 String name = enclosed.getSimpleName().toString();
5405 switch(enclosed.getKind()) {
5406 case FIELD -> {
5407 var field = (VarSymbol)enclosed;
5408 switch(name) {
5409 case "serialPersistentFields" -> {
5410 log.warning(
5411 TreeInfo.diagnosticPositionFor(field, tree),
5412 LintWarnings.IneffectualSerialFieldRecord);
5413 }
5414
5415 case "serialVersionUID" -> {
5416 // Could generate additional warning that
5417 // svuid value is not checked to match for
5418 // records.
5419 checkSerialVersionUID(tree, e, field);
5420 }}
5421 }
5422
5423 case METHOD -> {
5424 var method = (MethodSymbol)enclosed;
5425 switch(name) {
5426 case "writeReplace" -> checkWriteReplace(tree, e, method);
5427 case "readResolve" -> checkReadResolve(tree, e, method);
5428
5429 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5430 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern);
5431
5432 default -> {
5433 if (serialMethodNames.contains(name)) {
5434 log.warning(
5435 TreeInfo.diagnosticPositionFor(method, tree),
5436 LintWarnings.IneffectualSerialMethodRecord(name));
5437 }
5438 }}
5439 }}});
5440 }
5441 return null;
5442 }
5443
5444 void checkConcreteInstanceMethod(JCClassDecl tree,
5445 Element enclosing,
5446 MethodSymbol method) {
5447 if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5448 log.warning(
5449 TreeInfo.diagnosticPositionFor(method, tree),
5450 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5451 }
5452 }
5453
5454 private void checkReturnType(JCClassDecl tree,
5455 Element enclosing,
5456 MethodSymbol method,
5457 Type expectedReturnType) {
5458 // Note: there may be complications checking writeReplace
5459 // and readResolve since they return Object and could, in
5460 // principle, have covariant overrides and any synthetic
5461 // bridge method would not be represented here for
5462 // checking.
5463 Type rtype = method.getReturnType();
5464 if (!types.isSameType(expectedReturnType, rtype)) {
5465 log.warning(
5466 TreeInfo.diagnosticPositionFor(method, tree),
5467 LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5468 rtype, expectedReturnType));
5469 }
5470 }
5471
5472 private void checkOneArg(JCClassDecl tree,
5473 Element enclosing,
5474 MethodSymbol method,
5475 Type expectedType) {
5476 String name = method.getSimpleName().toString();
5477
5478 var parameters= method.getParameters();
5479
5480 if (parameters.size() != 1) {
5481 log.warning(
5482 TreeInfo.diagnosticPositionFor(method, tree),
5483 LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5484 return;
5485 }
5486
5487 Type parameterType = parameters.get(0).asType();
5488 if (!types.isSameType(parameterType, expectedType)) {
5489 log.warning(
5490 TreeInfo.diagnosticPositionFor(method, tree),
5491 LintWarnings.SerialMethodParameterType(method.getSimpleName(),
5492 expectedType,
5493 parameterType));
5494 }
5495 }
5496
5497 private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5498 Element enclosing,
5499 MethodSymbol method,
5500 Type expectedType) {
5501 var parameters = method.getParameters();
5502 return (parameters.size() == 1) &&
5503 types.isSameType(parameters.get(0).asType(), expectedType);
5504 }
5505
5506
5507 private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5508 var parameters = method.getParameters();
5509 if (!parameters.isEmpty()) {
5510 log.warning(
5511 TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5512 LintWarnings.SerialMethodNoArgs(method.getSimpleName()));
5513 }
5514 }
5515
5516 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5517 // If the enclosing class is externalizable, warn for the method
5518 if (isExternalizable((Type)enclosing.asType())) {
5519 log.warning(
5520 TreeInfo.diagnosticPositionFor(method, tree),
5521 LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5522 }
5523 return;
5524 }
5525
5526 private void checkExceptions(JCClassDecl tree,
5527 Element enclosing,
5528 MethodSymbol method,
5529 Type... declaredExceptions) {
5530 for (Type thrownType: method.getThrownTypes()) {
5531 // For each exception in the throws clause of the
5532 // method, if not an Error and not a RuntimeException,
5533 // check if the exception is a subtype of a declared
5534 // exception from the throws clause of the
5535 // serialization method in question.
5536 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5537 types.isSubtype(thrownType, syms.errorType) ) {
5538 continue;
5539 } else {
5540 boolean declared = false;
5541 for (Type declaredException : declaredExceptions) {
5542 if (types.isSubtype(thrownType, declaredException)) {
5543 declared = true;
5544 continue;
5545 }
5546 }
5547 if (!declared) {
5548 log.warning(
5549 TreeInfo.diagnosticPositionFor(method, tree),
5550 LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5551 thrownType));
5552 }
5553 }
5554 }
5555 return;
5556 }
5557
5558 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5559 Lint prevLint = lint;
5560 try {
5561 lint = lint.augment((Symbol) symbol);
5562
5563 if (lint.isEnabled(LintCategory.SERIAL)) {
5564 task.accept(symbol, p);
5565 }
5566
5567 return null;
5568 } finally {
5569 lint = prevLint;
5570 }
5571 }
5572
5573 }
5574
5575 void checkRequiresIdentity(JCTree tree, Lint lint) {
5576 switch (tree) {
5577 case JCClassDecl classDecl -> {
5578 Type st = types.supertype(classDecl.sym.type);
5579 if (st != null &&
5580 // no need to recheck j.l.Object, shortcut,
5581 st.tsym != syms.objectType.tsym &&
5582 // this one could be null, no explicit extends
5583 classDecl.extending != null) {
5584 checkIfIdentityIsExpected(classDecl.extending.pos(), st, lint);
5585 }
5586 for (JCExpression intrface: classDecl.implementing) {
5587 checkIfIdentityIsExpected(intrface.pos(), intrface.type, lint);
5588 }
5589 for (JCTypeParameter tp : classDecl.typarams) {
5590 checkIfIdentityIsExpected(tp.pos(), tp.type, lint);
5591 }
5592 }
5593 case JCVariableDecl variableDecl -> {
5594 if (variableDecl.vartype != null &&
5595 (variableDecl.sym.flags_field & RECORD) == 0 ||
5596 (variableDecl.sym.flags_field & ~(Flags.PARAMETER | RECORD | GENERATED_MEMBER)) != 0) {
5597 /* we don't want to warn twice so if this variable is a compiler generated parameter of
5598 * a canonical record constructor, we don't want to issue a warning as we will warn the
5599 * corresponding compiler generated private record field anyways
5600 */
5601 checkIfIdentityIsExpected(variableDecl.vartype.pos(), variableDecl.vartype.type, lint);
5602 }
5603 }
5604 case JCTypeCast typeCast -> checkIfIdentityIsExpected(typeCast.clazz.pos(), typeCast.clazz.type, lint);
5605 case JCBindingPattern bindingPattern -> {
5606 if (bindingPattern.var.vartype != null) {
5607 checkIfIdentityIsExpected(bindingPattern.var.vartype.pos(), bindingPattern.var.vartype.type, lint);
5608 }
5609 }
5610 case JCMethodDecl methodDecl -> {
5611 for (JCTypeParameter tp : methodDecl.typarams) {
5612 checkIfIdentityIsExpected(tp.pos(), tp.type, lint);
5613 }
5614 if (methodDecl.restype != null && !methodDecl.restype.type.hasTag(VOID)) {
5615 checkIfIdentityIsExpected(methodDecl.restype.pos(), methodDecl.restype.type, lint);
5616 }
5617 }
5618 case JCMemberReference mref -> {
5619 checkIfIdentityIsExpected(mref.expr.pos(), mref.target, lint);
5620 checkIfTypeParamsRequiresIdentity(mref.sym.getMetadata(), mref.typeargs, lint);
5621 }
5622 case JCPolyExpression poly
5623 when (poly instanceof JCNewClass || poly instanceof JCMethodInvocation) -> {
5624 if (poly instanceof JCNewClass newClass) {
5625 checkIfIdentityIsExpected(newClass.clazz.pos(), newClass.clazz.type, lint);
5626 }
5627 List<JCExpression> argExps = poly instanceof JCNewClass ?
5628 ((JCNewClass)poly).args :
5629 ((JCMethodInvocation)poly).args;
5630 Symbol msym = TreeInfo.symbolFor(poly);
5631 if (msym != null) {
5632 if (!argExps.isEmpty() && msym instanceof MethodSymbol ms && ms.params != null) {
5633 VarSymbol lastParam = ms.params.head;
5634 for (VarSymbol param: ms.params) {
5635 if ((param.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) {
5636 log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
5637 }
5638 lastParam = param;
5639 argExps = argExps.tail;
5640 }
5641 while (argExps != null && !argExps.isEmpty() && lastParam != null) {
5642 if ((lastParam.flags_field & REQUIRES_IDENTITY) != 0 && argExps.head.type.isValueBased()) {
5643 log.warning(argExps.head.pos(), LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
5644 }
5645 argExps = argExps.tail;
5646 }
5647 }
5648 checkIfTypeParamsRequiresIdentity(
5649 msym.getMetadata(),
5650 poly instanceof JCNewClass ?
5651 ((JCNewClass)poly).typeargs :
5652 ((JCMethodInvocation)poly).typeargs,
5653 lint);
5654 }
5655 }
5656 default -> throw new AssertionError("unexpected tree " + tree);
5657 }
5658 }
5659
5660 /** Check if a type required an identity class
5661 */
5662 private boolean checkIfIdentityIsExpected(DiagnosticPosition pos, Type t, Lint lint) {
5663 if (t != null &&
5664 lint != null &&
5665 lint.isEnabled(LintCategory.IDENTITY)) {
5666 RequiresIdentityVisitor requiresIdentityVisitor = new RequiresIdentityVisitor();
5667 // we need to avoid recursion due to self referencing type vars or captures, this is why we need a set
5668 requiresIdentityVisitor.visit(t, new HashSet<>());
5669 if (requiresIdentityVisitor.requiresWarning) {
5670 log.warning(pos, LintWarnings.AttemptToUseValueBasedWhereIdentityExpected);
5671 return true;
5672 }
5673 }
5674 return false;
5675 }
5676
5677 // where
5678 private class RequiresIdentityVisitor extends Types.SimpleVisitor<Void, Set<Type>> {
5679 boolean requiresWarning = false;
5680
5681 @Override
5682 public Void visitType(Type t, Set<Type> seen) {
5683 return null;
5684 }
5685
5686 @Override
5687 public Void visitWildcardType(WildcardType t, Set<Type> seen) {
5688 return visit(t.type, seen);
5689 }
5690
5691 @Override
5692 public Void visitTypeVar(TypeVar t, Set<Type> seen) {
5693 if (seen.add(t)) {
5694 visit(t.getUpperBound(), seen);
5695 }
5696 return null;
5697 }
5698
5699 @Override
5700 public Void visitCapturedType(CapturedType t, Set<Type> seen) {
5701 if (seen.add(t)) {
5702 visit(t.getUpperBound(), seen);
5703 visit(t.getLowerBound(), seen);
5704 }
5705 return null;
5706 }
5707
5708 @Override
5709 public Void visitArrayType(ArrayType t, Set<Type> seen) {
5710 return visit(t.elemtype, seen);
5711 }
5712
5713 @Override
5714 public Void visitClassType(ClassType t, Set<Type> seen) {
5715 if (t != null && t.tsym != null) {
5716 SymbolMetadata sm = t.tsym.getMetadata();
5717 if (sm != null && !t.getTypeArguments().isEmpty()) {
5718 if (sm.getTypeAttributes().stream()
5719 .filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) &&
5720 t.getTypeArguments().get(ta.position.parameter_index) != null &&
5721 t.getTypeArguments().get(ta.position.parameter_index).isValueBased()).findAny().isPresent()) {
5722 requiresWarning = true;
5723 return null;
5724 }
5725 }
5726 }
5727 visit(t.getEnclosingType(), seen);
5728 for (Type targ : t.getTypeArguments()) {
5729 visit(targ, seen);
5730 }
5731 return null;
5732 }
5733 } // RequiresIdentityVisitor
5734
5735 private void checkIfTypeParamsRequiresIdentity(SymbolMetadata sm,
5736 List<JCExpression> typeParamTrees,
5737 Lint lint) {
5738 if (typeParamTrees != null && !typeParamTrees.isEmpty()) {
5739 for (JCExpression targ : typeParamTrees) {
5740 checkIfIdentityIsExpected(targ.pos(), targ.type, lint);
5741 }
5742 if (sm != null)
5743 sm.getTypeAttributes().stream()
5744 .filter(ta -> isRequiresIdentityAnnotation(ta.type.tsym) &&
5745 typeParamTrees.get(ta.position.parameter_index).type != null &&
5746 typeParamTrees.get(ta.position.parameter_index).type.isValueBased())
5747 .forEach(ta -> log.warning(typeParamTrees.get(ta.position.parameter_index).pos(),
5748 CompilerProperties.LintWarnings.AttemptToUseValueBasedWhereIdentityExpected));
5749 }
5750 }
5751
5752 private boolean isRequiresIdentityAnnotation(TypeSymbol annoType) {
5753 return annoType == syms.requiresIdentityType.tsym ||
5754 annoType.flatName() == syms.requiresIdentityInternalType.tsym.flatName();
5755 }
5756 }