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