< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java

Print this page

 162         profile = Profile.instance(context);
 163         preview = Preview.instance(context);
 164 
 165         boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
 166         boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
 167         boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
 168         boolean enforceMandatoryWarnings = true;
 169 
 170         deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated,
 171                 enforceMandatoryWarnings, LintCategory.DEPRECATION, "deprecated");
 172         removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
 173                 enforceMandatoryWarnings, LintCategory.REMOVAL);
 174         uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
 175                 enforceMandatoryWarnings, LintCategory.UNCHECKED);
 176 
 177         deferredLintHandler = DeferredLintHandler.instance(context);
 178 
 179         allowModules = Feature.MODULES.allowedInSource(source);
 180         allowRecords = Feature.RECORDS.allowedInSource(source);
 181         allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);


 182     }
 183 
 184     /** Character for synthetic names
 185      */
 186     char syntheticNameChar;
 187 
 188     /** A table mapping flat names of all compiled classes for each module in this run
 189      *  to their symbols; maintained from outside.
 190      */
 191     private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
 192 
 193     /** A handler for messages about deprecated usage.
 194      */
 195     private MandatoryWarningHandler deprecationHandler;
 196 
 197     /** A handler for messages about deprecated-for-removal usage.
 198      */
 199     private MandatoryWarningHandler removalHandler;
 200 
 201     /** A handler for messages about unchecked or unsafe usage.
 202      */
 203     private MandatoryWarningHandler uncheckedHandler;
 204 
 205     /** A handler for deferred lint warnings.
 206      */
 207     private DeferredLintHandler deferredLintHandler;
 208 
 209     /** Are modules allowed
 210      */
 211     private final boolean allowModules;
 212 
 213     /** Are records allowed
 214      */
 215     private final boolean allowRecords;
 216 
 217     /** Are sealed classes allowed
 218      */
 219     private final boolean allowSealed;
 220 




 221     /** Whether to force suppression of deprecation and preview warnings.
 222      *  This happens when attributing import statements for JDK 9+.
 223      *  @see Feature#DEPRECATION_ON_IMPORT
 224      */
 225     private boolean importSuppression;
 226 
 227 /* *************************************************************************
 228  * Errors and Warnings
 229  **************************************************************************/
 230 
 231     Lint setLint(Lint newLint) {
 232         Lint prev = lint;
 233         lint = newLint;
 234         return prev;
 235     }
 236 
 237     boolean setImportSuppression(boolean newImportSuppression) {
 238         boolean prev = importSuppression;
 239         importSuppression = newImportSuppression;
 240         return prev;

 711     /** Check that type is a class or interface type.
 712      *  @param pos           Position to be used for error reporting.
 713      *  @param t             The type to be checked.
 714      */
 715     Type checkClassType(DiagnosticPosition pos, Type t) {
 716         if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
 717             return typeTagError(pos,
 718                                 diags.fragment(Fragments.TypeReqClass),
 719                                 asTypeParam(t));
 720         } else {
 721             return t;
 722         }
 723     }
 724     //where
 725         private Object asTypeParam(Type t) {
 726             return (t.hasTag(TYPEVAR))
 727                                     ? diags.fragment(Fragments.TypeParameter(t))
 728                                     : t;
 729         }
 730 

























 731     /** Check that type is a valid qualifier for a constructor reference expression
 732      */
 733     Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
 734         t = checkClassOrArrayType(pos, t);
 735         if (t.hasTag(CLASS)) {
 736             if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
 737                 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
 738                 t = types.createErrorType(t);
 739             } else if ((t.tsym.flags() & ENUM) != 0) {
 740                 log.error(pos, Errors.EnumCantBeInstantiated);
 741                 t = types.createErrorType(t);
 742             } else {
 743                 t = checkClassType(pos, t, true);
 744             }
 745         } else if (t.hasTag(ARRAY)) {
 746             if (!types.isReifiable(((ArrayType)t).elemtype)) {
 747                 log.error(pos, Errors.GenericArrayCreation);
 748                 t = types.createErrorType(t);
 749             }
 750         }

 768                 args = args.tail;
 769             }
 770         }
 771         return t;
 772     }
 773 
 774     /** Check that type is a reference type, i.e. a class, interface or array type
 775      *  or a type variable.
 776      *  @param pos           Position to be used for error reporting.
 777      *  @param t             The type to be checked.
 778      */
 779     Type checkRefType(DiagnosticPosition pos, Type t) {
 780         if (t.isReference())
 781             return t;
 782         else
 783             return typeTagError(pos,
 784                                 diags.fragment(Fragments.TypeReqRef),
 785                                 t);
 786     }
 787 


























 788     /** Check that each type is a reference type, i.e. a class, interface or array type
 789      *  or a type variable.
 790      *  @param trees         Original trees, used for error reporting.
 791      *  @param types         The types to be checked.
 792      */
 793     List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
 794         List<JCExpression> tl = trees;
 795         for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
 796             l.head = checkRefType(tl.head.pos(), l.head);
 797             tl = tl.tail;
 798         }
 799         return types;
 800     }
 801 
 802     /** Check that type is a null or reference type.
 803      *  @param pos           Position to be used for error reporting.
 804      *  @param t             The type to be checked.
 805      */
 806     Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
 807         if (t.isReference() || t.hasTag(BOT))

1159      *  Warning: we can't use flags() here since this method
1160      *  is called during class enter, when flags() would cause a premature
1161      *  completion.
1162      *  @param flags         The set of modifiers given in a definition.
1163      *  @param sym           The defined symbol.
1164      *  @param tree          The declaration
1165      */
1166     long checkFlags(long flags, Symbol sym, JCTree tree) {
1167         final DiagnosticPosition pos = tree.pos();
1168         long mask;
1169         long implicit = 0;
1170 
1171         switch (sym.kind) {
1172         case VAR:
1173             if (TreeInfo.isReceiverParam(tree))
1174                 mask = ReceiverParamFlags;
1175             else if (sym.owner.kind != TYP)
1176                 mask = LocalVarFlags;
1177             else if ((sym.owner.flags_field & INTERFACE) != 0)
1178                 mask = implicit = InterfaceVarFlags;
1179             else
1180                 mask = VarFlags;





1181             break;
1182         case MTH:
1183             if (sym.name == names.init) {
1184                 if ((sym.owner.flags_field & ENUM) != 0) {
1185                     // enum constructors cannot be declared public or
1186                     // protected and must be implicitly or explicitly
1187                     // private
1188                     implicit = PRIVATE;
1189                     mask = PRIVATE;
1190                 } else
1191                     mask = ConstructorFlags;
1192             }  else if ((sym.owner.flags_field & INTERFACE) != 0) {
1193                 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1194                     mask = AnnotationTypeElementMask;
1195                     implicit = PUBLIC | ABSTRACT;
1196                 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1197                     mask = InterfaceMethodMask;
1198                     implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1199                     if ((flags & DEFAULT) != 0) {
1200                         implicit |= ABSTRACT;
1201                     }
1202                 } else {
1203                     mask = implicit = InterfaceMethodFlags;
1204                 }
1205             } else if ((sym.owner.flags_field & RECORD) != 0) {
1206                 mask = RecordMethodFlags;

1207             } else {
1208                 mask = MethodFlags;


1209             }
1210             if ((flags & STRICTFP) != 0) {
1211                 warnOnExplicitStrictfp(tree);
1212             }
1213             // Imply STRICTFP if owner has STRICTFP set.
1214             if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1215                 ((flags) & Flags.DEFAULT) != 0)
1216                 implicit |= sym.owner.flags_field & STRICTFP;
1217             break;
1218         case TYP:
1219             if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1220                     (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1221                 boolean implicitlyStatic = !sym.isAnonymous() &&
1222                         ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1223                 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1224                 // local statics are allowed only if records are allowed too
1225                 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
1226                 implicit = implicitlyStatic ? STATIC : implicit;
1227             } else if (sym.owner.kind == TYP) {
1228                 // statics in inner classes are allowed only if records are allowed too
1229                 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1230                 if (sym.owner.owner.kind == PCK ||
1231                     (sym.owner.flags_field & STATIC) != 0) {
1232                     mask |= STATIC;
1233                 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1234                     log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1235                 }
1236                 // Nested interfaces and enums are always STATIC (Spec ???)
1237                 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1238             } else {
1239                 mask = ExtendedClassFlags;
1240             }




1241             // Interfaces are always ABSTRACT
1242             if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1243 




1244             if ((flags & ENUM) != 0) {
1245                 // enums can't be declared abstract, final, sealed or non-sealed
1246                 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
1247                 implicit |= implicitEnumFinalFlag(tree);
1248             }
1249             if ((flags & RECORD) != 0) {
1250                 // records can't be declared abstract
1251                 mask &= ~ABSTRACT;
1252                 implicit |= FINAL;
1253             }
1254             if ((flags & STRICTFP) != 0) {
1255                 warnOnExplicitStrictfp(tree);
1256             }
1257             // Imply STRICTFP if owner has STRICTFP set.
1258             implicit |= sym.owner.flags_field & STRICTFP;





1259             break;
1260         default:
1261             throw new AssertionError();
1262         }
1263         long illegal = flags & ExtendedStandardFlags & ~mask;
1264         if (illegal != 0) {
1265             if ((illegal & INTERFACE) != 0) {
1266                 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1267                 mask |= INTERFACE;
1268             }
1269             else {
1270                 log.error(pos,
1271                         Errors.ModNotAllowedHere(asFlagSet(illegal)));
1272             }
1273         }
1274         else if ((sym.kind == TYP ||
1275                   // ISSUE: Disallowing abstract&private is no longer appropriate
1276                   // in the presence of inner classes. Should it be deleted here?
1277                   checkDisjoint(pos, flags,
1278                                 ABSTRACT,
1279                                 PRIVATE | STATIC | DEFAULT))
1280                  &&
1281                  checkDisjoint(pos, flags,
1282                                 STATIC | PRIVATE,
1283                                 DEFAULT)
1284                  &&
1285                  checkDisjoint(pos, flags,
1286                                ABSTRACT | INTERFACE,
1287                                FINAL | NATIVE | SYNCHRONIZED)
1288                  &&
1289                  checkDisjoint(pos, flags,
1290                                PUBLIC,
1291                                PRIVATE | PROTECTED)
1292                  &&
1293                  checkDisjoint(pos, flags,
1294                                PRIVATE,
1295                                PUBLIC | PROTECTED)
1296                  &&
1297                  checkDisjoint(pos, flags,

1298                                FINAL,
1299                                VOLATILE)
1300                  &&
1301                  (sym.kind == TYP ||
1302                   checkDisjoint(pos, flags,
1303                                 ABSTRACT | NATIVE,
1304                                 STRICTFP))
1305                  && checkDisjoint(pos, flags,
1306                                 FINAL,
1307                            SEALED | NON_SEALED)
1308                  && checkDisjoint(pos, flags,
1309                                 SEALED,
1310                            FINAL | NON_SEALED)
1311                  && checkDisjoint(pos, flags,
1312                                 SEALED,
1313                                 ANNOTATION)) {






1314             // skip
1315         }
1316         return flags & (mask | ~ExtendedStandardFlags) | implicit;
1317     }
1318 
1319     private void warnOnExplicitStrictfp(JCTree tree) {
1320         deferredLintHandler.push(tree);
1321         try {
1322             deferredLintHandler.report(_ -> lint.logIfEnabled(tree.pos(), LintWarnings.Strictfp));
1323         } finally {
1324             deferredLintHandler.pop();
1325         }
1326     }
1327 
1328 
1329     /** Determine if this enum should be implicitly final.
1330      *
1331      *  If the enum has no specialized enum constants, it is final.
1332      *
1333      *  If the enum does have specialized enum constants, it is

2105                     return true;
2106                 }
2107             }
2108         }
2109         return false;
2110     }
2111 
2112     /** Check that a given method conforms with any method it overrides.
2113      *  @param tree         The tree from which positions are extracted
2114      *                      for errors.
2115      *  @param m            The overriding method.
2116      */
2117     void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2118         ClassSymbol origin = (ClassSymbol)m.owner;
2119         if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2120             if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2121                 log.error(tree.pos(), Errors.EnumNoFinalize);
2122                 return;
2123             }
2124         }





2125         if (allowRecords && origin.isRecord()) {
2126             // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2127             Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2128                     .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2129             if (recordComponent.isPresent()) {
2130                 return;
2131             }
2132         }
2133 
2134         for (Type t = origin.type; t.hasTag(CLASS);
2135              t = types.supertype(t)) {
2136             if (t != origin.type) {
2137                 checkOverride(tree, t, origin, m);
2138             }
2139             for (Type t2 : types.interfaces(t)) {
2140                 checkOverride(tree, t2, origin, m);
2141             }
2142         }
2143 
2144         final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;

2540     /** Check that all abstract methods implemented by a class are
2541      *  mutually compatible.
2542      *  @param pos          Position to be used for error reporting.
2543      *  @param c            The class whose interfaces are checked.
2544      */
2545     void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2546         List<Type> supertypes = types.interfaces(c);
2547         Type supertype = types.supertype(c);
2548         if (supertype.hasTag(CLASS) &&
2549             (supertype.tsym.flags() & ABSTRACT) != 0)
2550             supertypes = supertypes.prepend(supertype);
2551         for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2552             if (!l.head.getTypeArguments().isEmpty() &&
2553                 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2554                 return;
2555             for (List<Type> m = supertypes; m != l; m = m.tail)
2556                 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2557                     return;
2558         }
2559         checkCompatibleConcretes(pos, c);












2560     }
2561 
2562     /** Check that all non-override equivalent methods accessible from 'site'
2563      *  are mutually compatible (JLS 8.4.8/9.4.1).
2564      *
2565      *  @param pos  Position to be used for error reporting.
2566      *  @param site The class whose methods are checked.
2567      *  @param sym  The method symbol to be checked.
2568      */
2569     void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2570          ClashFilter cf = new ClashFilter(site);
2571         //for each method m1 that is overridden (directly or indirectly)
2572         //by method 'sym' in 'site'...
2573 
2574         ArrayList<Symbol> symbolsByName = new ArrayList<>();
2575         types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2576         for (Symbol m1 : symbolsByName) {
2577             if (!sym.overrides(m1, site.tsym, types, false)) {
2578                 continue;
2579             }

4892                 }
4893             } else {
4894                 Assert.error("Unknown pattern: " + currentPattern.getTag());
4895             }
4896             return false;
4897         }
4898 
4899     /** check if a type is a subtype of Externalizable, if that is available. */
4900     boolean isExternalizable(Type t) {
4901         try {
4902             syms.externalizableType.complete();
4903         } catch (CompletionFailure e) {
4904             return false;
4905         }
4906         return types.isSubtype(t, syms.externalizableType);
4907     }
4908 
4909     /**
4910      * Check structure of serialization declarations.
4911      */
4912     public void checkSerialStructure(JCClassDecl tree, ClassSymbol c) {
4913         (new SerialTypeVisitor()).visit(c, tree);
4914     }
4915 
4916     /**
4917      * This visitor will warn if a serialization-related field or
4918      * method is declared in a suspicious or incorrect way. In
4919      * particular, it will warn for cases where the runtime
4920      * serialization mechanism will silently ignore a mis-declared
4921      * entity.
4922      *
4923      * Distinguished serialization-related fields and methods:
4924      *
4925      * Methods:
4926      *
4927      * private void writeObject(ObjectOutputStream stream) throws IOException
4928      * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
4929      *
4930      * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
4931      * private void readObjectNoData() throws ObjectStreamException
4932      * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
4933      *
4934      * Fields:
4935      *
4936      * private static final long serialVersionUID
4937      * private static final ObjectStreamField[] serialPersistentFields
4938      *
4939      * Externalizable: methods defined on the interface
4940      * public void writeExternal(ObjectOutput) throws IOException
4941      * public void readExternal(ObjectInput) throws IOException
4942      */
4943     private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
4944         SerialTypeVisitor() {

4945             this.lint = Check.this.lint;

4946         }
4947 
4948         private static final Set<String> serialMethodNames =
4949             Set.of("writeObject", "writeReplace",
4950                    "readObject",  "readObjectNoData",
4951                    "readResolve");
4952 
4953         private static final Set<String> serialFieldNames =
4954             Set.of("serialVersionUID", "serialPersistentFields");
4955 
4956         // Type of serialPersistentFields
4957         private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
4958 
4959         Lint lint;
4960 
4961         @Override
4962         public Void defaultAction(Element e, JCClassDecl p) {
4963             throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
4964         }
4965 

4985                 if (sym.kind == VAR) {
4986                     svuidSym = (VarSymbol)sym;
4987                     break;
4988                 }
4989             }
4990 
4991             if (svuidSym == null) {
4992                 log.warning(p.pos(), LintWarnings.MissingSVUID(c));
4993             }
4994 
4995             // Check for serialPersistentFields to gate checks for
4996             // non-serializable non-transient instance fields
4997             boolean serialPersistentFieldsPresent =
4998                     c.members()
4999                      .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
5000                      .iterator()
5001                      .hasNext();
5002 
5003             // Check declarations of serialization-related methods and
5004             // fields

5005             for(Symbol el : c.getEnclosedElements()) {
5006                 runUnderLint(el, p, (enclosed, tree) -> {
5007                     String name = null;
5008                     switch(enclosed.getKind()) {
5009                     case FIELD -> {
5010                         if (!serialPersistentFieldsPresent) {
5011                             var flags = enclosed.flags();
5012                             if ( ((flags & TRANSIENT) == 0) &&
5013                                  ((flags & STATIC) == 0)) {
5014                                 Type varType = enclosed.asType();
5015                                 if (!canBeSerialized(varType)) {
5016                                     // Note per JLS arrays are
5017                                     // serializable even if the
5018                                     // component type is not.
5019                                     log.warning(
5020                                             TreeInfo.diagnosticPositionFor(enclosed, tree),
5021                                                 LintWarnings.NonSerializableInstanceField);
5022                                 } else if (varType.hasTag(ARRAY)) {
5023                                     ArrayType arrayType = (ArrayType)varType;
5024                                     Type elementType = arrayType.elemtype;

5059                     // will also pull in default methods from
5060                     // superinterfaces. In other words, the runtime checks
5061                     // (which long predate default methods on interfaces)
5062                     // do not admit the possibility of inheriting methods
5063                     // this way, a difference from general inheritance.
5064 
5065                     // The current implementation just checks the enclosed
5066                     // elements and does not directly check the inherited
5067                     // methods. If all the types are being checked this is
5068                     // less of a concern; however, there are cases that
5069                     // could be missed. In particular, readResolve and
5070                     // writeReplace could, in principle, by inherited from
5071                     // a non-serializable superclass and thus not checked
5072                     // even if compiled with a serializable child class.
5073                     case METHOD -> {
5074                         var method = (MethodSymbol)enclosed;
5075                         name = method.getSimpleName().toString();
5076                         if (serialMethodNames.contains(name)) {
5077                             switch (name) {
5078                             case "writeObject"      -> checkWriteObject(tree, e, method);
5079                             case "writeReplace"     -> checkWriteReplace(tree,e, method);
5080                             case "readObject"       -> checkReadObject(tree,e, method);
5081                             case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
5082                             case "readResolve"      -> checkReadResolve(tree, e, method);
5083                             default ->  throw new AssertionError();
5084                             }
5085                         }
5086                     }
5087                     }
5088                 });
5089             }
5090 



















5091             return null;
5092         }
5093 
5094         boolean canBeSerialized(Type type) {
5095             return type.isPrimitive() || rs.isSerializable(type);
5096         }
5097 
















5098         /**
5099          * Check that Externalizable class needs a public no-arg
5100          * constructor.
5101          *
5102          * Check that a Serializable class has access to the no-arg
5103          * constructor of its first nonserializable superclass.
5104          */
5105         private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5106             if (isExternalizable(c.type)) {
5107                 for(var sym : c.getEnclosedElements()) {
5108                     if (sym.isConstructor() &&
5109                         ((sym.flags() & PUBLIC) == PUBLIC)) {
5110                         if (((MethodSymbol)sym).getParameters().isEmpty()) {
5111                             return;
5112                         }
5113                     }
5114                 }
5115                 log.warning(tree.pos(),
5116                             LintWarnings.ExternalizableMissingPublicNoArgCtor);
5117             } else {

5201             // Warn if serialPersistentFields is initialized to a
5202             // literal null.
5203             JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5204             if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5205                 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5206                 JCExpression initExpr = variableDef.init;
5207                  if (initExpr != null && TreeInfo.isNull(initExpr)) {
5208                      log.warning(initExpr.pos(),
5209                                  LintWarnings.SPFNullInit);
5210                  }
5211             }
5212         }
5213 
5214         private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5215             // The "synchronized" modifier is seen in the wild on
5216             // readObject and writeObject methods and is generally
5217             // innocuous.
5218 
5219             // private void writeObject(ObjectOutputStream stream) throws IOException
5220             checkPrivateNonStaticMethod(tree, method);
5221             checkReturnType(tree, e, method, syms.voidType);
5222             checkOneArg(tree, e, method, syms.objectOutputStreamType);
5223             checkExceptions(tree, e, method, syms.ioExceptionType);
5224             checkExternalizable(tree, e, method);
5225         }
5226 
5227         private void checkWriteReplace(JCClassDecl tree, Element e, MethodSymbol method) {
5228             // ANY-ACCESS-MODIFIER Object writeReplace() throws
5229             // ObjectStreamException
5230 
5231             // Excluding abstract, could have a more complicated
5232             // rule based on abstract-ness of the class
5233             checkConcreteInstanceMethod(tree, e, method);
5234             checkReturnType(tree, e, method, syms.objectType);
5235             checkNoArgs(tree, e, method);
5236             checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5237         }
5238 
5239         private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5240             // The "synchronized" modifier is seen in the wild on
5241             // readObject and writeObject methods and is generally
5242             // innocuous.
5243 
5244             // private void readObject(ObjectInputStream stream)
5245             //   throws IOException, ClassNotFoundException
5246             checkPrivateNonStaticMethod(tree, method);
5247             checkReturnType(tree, e, method, syms.voidType);
5248             checkOneArg(tree, e, method, syms.objectInputStreamType);
5249             checkExceptions(tree, e, method, syms.ioExceptionType, syms.classNotFoundExceptionType);
5250             checkExternalizable(tree, e, method);
5251         }
5252 
5253         private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5254             // private void readObjectNoData() throws ObjectStreamException
5255             checkPrivateNonStaticMethod(tree, method);
5256             checkReturnType(tree, e, method, syms.voidType);
5257             checkNoArgs(tree, e, method);
5258             checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5259             checkExternalizable(tree, e, method);
5260         }
5261 
5262         private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5263             // ANY-ACCESS-MODIFIER Object readResolve()
5264             // throws ObjectStreamException
5265 
5266             // Excluding abstract, could have a more complicated
5267             // rule based on abstract-ness of the class
5268             checkConcreteInstanceMethod(tree, e, method);
5269             checkReturnType(tree,e, method, syms.objectType);
5270             checkNoArgs(tree, e, method);
5271             checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5272         }
5273 
5274         private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5275             //public void writeExternal(ObjectOutput) throws IOException
5276             checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5277         }
5278 
5279         private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5280             // public void readExternal(ObjectInput) throws IOException
5281             checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5282          }
5283 
5284         private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5285                                              boolean isExtern) {
5286             if (isExtern && isExternMethod(tree, e, method, argType)) {
5287                 log.warning(
5288                         TreeInfo.diagnosticPositionFor(method, tree),
5289                             LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5290             }
5291         }

5501                     case FIELD -> {
5502                         var field = (VarSymbol)enclosed;
5503                         switch(name) {
5504                         case "serialPersistentFields" -> {
5505                             log.warning(
5506                                     TreeInfo.diagnosticPositionFor(field, tree),
5507                                         LintWarnings.IneffectualSerialFieldRecord);
5508                         }
5509 
5510                         case "serialVersionUID" -> {
5511                             // Could generate additional warning that
5512                             // svuid value is not checked to match for
5513                             // records.
5514                             checkSerialVersionUID(tree, e, field);
5515                         }}
5516                     }
5517 
5518                     case METHOD -> {
5519                         var method = (MethodSymbol)enclosed;
5520                         switch(name) {
5521                         case "writeReplace" -> checkWriteReplace(tree, e, method);
5522                         case "readResolve"  -> checkReadResolve(tree, e, method);
5523 
5524                         case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5525                         case "readExternal"  -> checkReadExternalRecord(tree, e, method, isExtern);
5526 
5527                         default -> {
5528                             if (serialMethodNames.contains(name)) {
5529                                 log.warning(
5530                                         TreeInfo.diagnosticPositionFor(method, tree),
5531                                             LintWarnings.IneffectualSerialMethodRecord(name));
5532                             }
5533                         }}
5534                     }}});
5535             }
5536             return null;
5537         }
5538 
5539         void checkConcreteInstanceMethod(JCClassDecl tree,
5540                                          Element enclosing,
5541                                          MethodSymbol method) {
5542             if ((method.flags() & (STATIC | ABSTRACT)) != 0) {

5543                     log.warning(
5544                             TreeInfo.diagnosticPositionFor(method, tree),
5545                                 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));


5546             }

5547         }
5548 
5549         private void checkReturnType(JCClassDecl tree,
5550                                      Element enclosing,
5551                                      MethodSymbol method,
5552                                      Type expectedReturnType) {
5553             // Note: there may be complications checking writeReplace
5554             // and readResolve since they return Object and could, in
5555             // principle, have covariant overrides and any synthetic
5556             // bridge method would not be represented here for
5557             // checking.
5558             Type rtype = method.getReturnType();
5559             if (!types.isSameType(expectedReturnType, rtype)) {
5560                 log.warning(
5561                         TreeInfo.diagnosticPositionFor(method, tree),

5562                             LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5563                                                                       rtype, expectedReturnType));


5564             }

5565         }
5566 
5567         private void checkOneArg(JCClassDecl tree,
5568                                  Element enclosing,
5569                                  MethodSymbol method,
5570                                  Type expectedType) {
5571             String name = method.getSimpleName().toString();
5572 
5573             var parameters= method.getParameters();
5574 
5575             if (parameters.size() != 1) {
5576                 log.warning(
5577                         TreeInfo.diagnosticPositionFor(method, tree),
5578                             LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5579                 return;
5580             }
5581 
5582             Type parameterType = parameters.get(0).asType();
5583             if (!types.isSameType(parameterType, expectedType)) {
5584                 log.warning(
5585                         TreeInfo.diagnosticPositionFor(method, tree),
5586                             LintWarnings.SerialMethodParameterType(method.getSimpleName(),
5587                                                                expectedType,
5588                                                                parameterType));
5589             }
5590         }
5591 
5592         private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5593                                                  Element enclosing,
5594                                                  MethodSymbol method,
5595                                                  Type expectedType) {
5596             var parameters = method.getParameters();
5597             return (parameters.size() == 1) &&
5598                 types.isSameType(parameters.get(0).asType(), expectedType);
5599         }
5600 
5601 
5602         private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5603             var parameters = method.getParameters();
5604             if (!parameters.isEmpty()) {
5605                 log.warning(
5606                         TreeInfo.diagnosticPositionFor(parameters.get(0), tree),

5607                             LintWarnings.SerialMethodNoArgs(method.getSimpleName()));


5608             }

5609         }
5610 
5611         private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5612             // If the enclosing class is externalizable, warn for the method
5613             if (isExternalizable((Type)enclosing.asType())) {
5614                 log.warning(
5615                         TreeInfo.diagnosticPositionFor(method, tree),
5616                             LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5617             }
5618             return;
5619         }
5620 
5621         private void checkExceptions(JCClassDecl tree,
5622                                      Element enclosing,
5623                                      MethodSymbol method,
5624                                      Type... declaredExceptions) {
5625             for (Type thrownType: method.getThrownTypes()) {
5626                 // For each exception in the throws clause of the
5627                 // method, if not an Error and not a RuntimeException,
5628                 // check if the exception is a subtype of a declared
5629                 // exception from the throws clause of the
5630                 // serialization method in question.
5631                 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5632                     types.isSubtype(thrownType, syms.errorType) ) {
5633                     continue;
5634                 } else {
5635                     boolean declared = false;
5636                     for (Type declaredException : declaredExceptions) {
5637                         if (types.isSubtype(thrownType, declaredException)) {
5638                             declared = true;
5639                             continue;
5640                         }
5641                     }
5642                     if (!declared) {
5643                         log.warning(
5644                                 TreeInfo.diagnosticPositionFor(method, tree),

5645                                     LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5646                                                                              thrownType));


5647                     }
5648                 }
5649             }
5650             return;
5651         }
5652 
5653         private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5654             Lint prevLint = lint;
5655             try {
5656                 lint = lint.augment((Symbol) symbol);
5657 
5658                 if (lint.isEnabled(LintCategory.SERIAL)) {
5659                     task.accept(symbol, p);
5660                 }
5661 
5662                 return null;
5663             } finally {
5664                 lint = prevLint;
5665             }
5666         }
5667 
5668     }
5669 
5670 }

 162         profile = Profile.instance(context);
 163         preview = Preview.instance(context);
 164 
 165         boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
 166         boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
 167         boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
 168         boolean enforceMandatoryWarnings = true;
 169 
 170         deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated,
 171                 enforceMandatoryWarnings, LintCategory.DEPRECATION, "deprecated");
 172         removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
 173                 enforceMandatoryWarnings, LintCategory.REMOVAL);
 174         uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
 175                 enforceMandatoryWarnings, LintCategory.UNCHECKED);
 176 
 177         deferredLintHandler = DeferredLintHandler.instance(context);
 178 
 179         allowModules = Feature.MODULES.allowedInSource(source);
 180         allowRecords = Feature.RECORDS.allowedInSource(source);
 181         allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
 182         allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
 183                 Feature.VALUE_CLASSES.allowedInSource(source);
 184     }
 185 
 186     /** Character for synthetic names
 187      */
 188     char syntheticNameChar;
 189 
 190     /** A table mapping flat names of all compiled classes for each module in this run
 191      *  to their symbols; maintained from outside.
 192      */
 193     private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
 194 
 195     /** A handler for messages about deprecated usage.
 196      */
 197     private MandatoryWarningHandler deprecationHandler;
 198 
 199     /** A handler for messages about deprecated-for-removal usage.
 200      */
 201     private MandatoryWarningHandler removalHandler;
 202 
 203     /** A handler for messages about unchecked or unsafe usage.
 204      */
 205     private MandatoryWarningHandler uncheckedHandler;
 206 
 207     /** A handler for deferred lint warnings.
 208      */
 209     private DeferredLintHandler deferredLintHandler;
 210 
 211     /** Are modules allowed
 212      */
 213     private final boolean allowModules;
 214 
 215     /** Are records allowed
 216      */
 217     private final boolean allowRecords;
 218 
 219     /** Are sealed classes allowed
 220      */
 221     private final boolean allowSealed;
 222 
 223     /** Are value classes allowed
 224      */
 225     private final boolean allowValueClasses;
 226 
 227     /** Whether to force suppression of deprecation and preview warnings.
 228      *  This happens when attributing import statements for JDK 9+.
 229      *  @see Feature#DEPRECATION_ON_IMPORT
 230      */
 231     private boolean importSuppression;
 232 
 233 /* *************************************************************************
 234  * Errors and Warnings
 235  **************************************************************************/
 236 
 237     Lint setLint(Lint newLint) {
 238         Lint prev = lint;
 239         lint = newLint;
 240         return prev;
 241     }
 242 
 243     boolean setImportSuppression(boolean newImportSuppression) {
 244         boolean prev = importSuppression;
 245         importSuppression = newImportSuppression;
 246         return prev;

 717     /** Check that type is a class or interface type.
 718      *  @param pos           Position to be used for error reporting.
 719      *  @param t             The type to be checked.
 720      */
 721     Type checkClassType(DiagnosticPosition pos, Type t) {
 722         if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
 723             return typeTagError(pos,
 724                                 diags.fragment(Fragments.TypeReqClass),
 725                                 asTypeParam(t));
 726         } else {
 727             return t;
 728         }
 729     }
 730     //where
 731         private Object asTypeParam(Type t) {
 732             return (t.hasTag(TYPEVAR))
 733                                     ? diags.fragment(Fragments.TypeParameter(t))
 734                                     : t;
 735         }
 736 
 737     void checkConstraintsOfValueClass(JCClassDecl tree, ClassSymbol c) {
 738         DiagnosticPosition pos = tree.pos();
 739         for (Type st : types.closure(c.type)) {
 740             if (st == null || st.tsym == null || st.tsym.kind == ERR)
 741                 continue;
 742             if  (st.tsym == syms.objectType.tsym || st.tsym == syms.recordType.tsym || st.isInterface())
 743                 continue;
 744             if (!st.tsym.isAbstract()) {
 745                 if (c != st.tsym) {
 746                     log.error(pos, Errors.ConcreteSupertypeForValueClass(c, st));
 747                 }
 748                 continue;
 749             }
 750             // dealing with an abstract value or value super class below.
 751             for (Symbol s : st.tsym.members().getSymbols(NON_RECURSIVE)) {
 752                 if (s.kind == MTH) {
 753                     if ((s.flags() & (SYNCHRONIZED | STATIC)) == SYNCHRONIZED) {
 754                         log.error(pos, Errors.SuperClassMethodCannotBeSynchronized(s, c, st));
 755                     }
 756                     break;
 757                 }
 758             }
 759         }
 760     }
 761 
 762     /** Check that type is a valid qualifier for a constructor reference expression
 763      */
 764     Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
 765         t = checkClassOrArrayType(pos, t);
 766         if (t.hasTag(CLASS)) {
 767             if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
 768                 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
 769                 t = types.createErrorType(t);
 770             } else if ((t.tsym.flags() & ENUM) != 0) {
 771                 log.error(pos, Errors.EnumCantBeInstantiated);
 772                 t = types.createErrorType(t);
 773             } else {
 774                 t = checkClassType(pos, t, true);
 775             }
 776         } else if (t.hasTag(ARRAY)) {
 777             if (!types.isReifiable(((ArrayType)t).elemtype)) {
 778                 log.error(pos, Errors.GenericArrayCreation);
 779                 t = types.createErrorType(t);
 780             }
 781         }

 799                 args = args.tail;
 800             }
 801         }
 802         return t;
 803     }
 804 
 805     /** Check that type is a reference type, i.e. a class, interface or array type
 806      *  or a type variable.
 807      *  @param pos           Position to be used for error reporting.
 808      *  @param t             The type to be checked.
 809      */
 810     Type checkRefType(DiagnosticPosition pos, Type t) {
 811         if (t.isReference())
 812             return t;
 813         else
 814             return typeTagError(pos,
 815                                 diags.fragment(Fragments.TypeReqRef),
 816                                 t);
 817     }
 818 
 819     /** Check that type is an identity type, i.e. not a value type.
 820      *  When not discernible statically, give it the benefit of doubt
 821      *  and defer to runtime.
 822      *
 823      *  @param pos           Position to be used for error reporting.
 824      *  @param t             The type to be checked.
 825      */
 826     boolean checkIdentityType(DiagnosticPosition pos, Type t) {
 827         if (t.hasTag(TYPEVAR)) {
 828             t = types.skipTypeVars(t, false);
 829         }
 830         if (t.isIntersection()) {
 831             IntersectionClassType ict = (IntersectionClassType)t;
 832             boolean result = true;
 833             for (Type component : ict.getExplicitComponents()) {
 834                 result &= checkIdentityType(pos, component);
 835             }
 836             return result;
 837         }
 838         if (t.isPrimitive() || (t.isValueClass() && !t.tsym.isAbstract())) {
 839             typeTagError(pos, diags.fragment(Fragments.TypeReqIdentity), t);
 840             return false;
 841         }
 842         return true;
 843     }
 844 
 845     /** Check that each type is a reference type, i.e. a class, interface or array type
 846      *  or a type variable.
 847      *  @param trees         Original trees, used for error reporting.
 848      *  @param types         The types to be checked.
 849      */
 850     List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
 851         List<JCExpression> tl = trees;
 852         for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
 853             l.head = checkRefType(tl.head.pos(), l.head);
 854             tl = tl.tail;
 855         }
 856         return types;
 857     }
 858 
 859     /** Check that type is a null or reference type.
 860      *  @param pos           Position to be used for error reporting.
 861      *  @param t             The type to be checked.
 862      */
 863     Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
 864         if (t.isReference() || t.hasTag(BOT))

1216      *  Warning: we can't use flags() here since this method
1217      *  is called during class enter, when flags() would cause a premature
1218      *  completion.
1219      *  @param flags         The set of modifiers given in a definition.
1220      *  @param sym           The defined symbol.
1221      *  @param tree          The declaration
1222      */
1223     long checkFlags(long flags, Symbol sym, JCTree tree) {
1224         final DiagnosticPosition pos = tree.pos();
1225         long mask;
1226         long implicit = 0;
1227 
1228         switch (sym.kind) {
1229         case VAR:
1230             if (TreeInfo.isReceiverParam(tree))
1231                 mask = ReceiverParamFlags;
1232             else if (sym.owner.kind != TYP)
1233                 mask = LocalVarFlags;
1234             else if ((sym.owner.flags_field & INTERFACE) != 0)
1235                 mask = implicit = InterfaceVarFlags;
1236             else {
1237                 boolean isInstanceFieldOfValueClass = sym.owner.type.isValueClass() && (flags & STATIC) == 0;
1238                 mask = !isInstanceFieldOfValueClass ? VarFlags : ValueFieldFlags;
1239                 if (isInstanceFieldOfValueClass) {
1240                     implicit |= FINAL | STRICT;
1241                 }
1242             }
1243             break;
1244         case MTH:
1245             if (sym.name == names.init) {
1246                 if ((sym.owner.flags_field & ENUM) != 0) {
1247                     // enum constructors cannot be declared public or
1248                     // protected and must be implicitly or explicitly
1249                     // private
1250                     implicit = PRIVATE;
1251                     mask = PRIVATE;
1252                 } else
1253                     mask = ConstructorFlags;
1254             }  else if ((sym.owner.flags_field & INTERFACE) != 0) {
1255                 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1256                     mask = AnnotationTypeElementMask;
1257                     implicit = PUBLIC | ABSTRACT;
1258                 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1259                     mask = InterfaceMethodMask;
1260                     implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1261                     if ((flags & DEFAULT) != 0) {
1262                         implicit |= ABSTRACT;
1263                     }
1264                 } else {
1265                     mask = implicit = InterfaceMethodFlags;
1266                 }
1267             } else if ((sym.owner.flags_field & RECORD) != 0) {
1268                 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1269                         RecordMethodFlags & ~SYNCHRONIZED : RecordMethodFlags;
1270             } else {
1271                 // value objects do not have an associated monitor/lock
1272                 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1273                         MethodFlags & ~SYNCHRONIZED : MethodFlags;
1274             }
1275             if ((flags & STRICTFP) != 0) {
1276                 warnOnExplicitStrictfp(tree);
1277             }
1278             // Imply STRICTFP if owner has STRICTFP set.
1279             if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1280                 ((flags) & Flags.DEFAULT) != 0)
1281                 implicit |= sym.owner.flags_field & STRICTFP;
1282             break;
1283         case TYP:
1284             if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1285                     (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1286                 boolean implicitlyStatic = !sym.isAnonymous() &&
1287                         ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1288                 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1289                 // local statics are allowed only if records are allowed too
1290                 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedStaticLocalClassFlags : ExtendedLocalClassFlags;
1291                 implicit = implicitlyStatic ? STATIC : implicit;
1292             } else if (sym.owner.kind == TYP) {
1293                 // statics in inner classes are allowed only if records are allowed too
1294                 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1295                 if (sym.owner.owner.kind == PCK ||
1296                     (sym.owner.flags_field & STATIC) != 0) {
1297                     mask |= STATIC;
1298                 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1299                     log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1300                 }
1301                 // Nested interfaces and enums are always STATIC (Spec ???)
1302                 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1303             } else {
1304                 mask = ExtendedClassFlags;
1305             }
1306             if ((flags & (VALUE_CLASS | SEALED | ABSTRACT)) == (VALUE_CLASS | SEALED) ||
1307                 (flags & (VALUE_CLASS | NON_SEALED | ABSTRACT)) == (VALUE_CLASS | NON_SEALED)) {
1308                 log.error(pos, Errors.NonAbstractValueClassCantBeSealedOrNonSealed);
1309             }
1310             // Interfaces are always ABSTRACT
1311             if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1312 
1313             if ((flags & (INTERFACE | VALUE_CLASS)) == 0) {
1314                 implicit |= IDENTITY_TYPE;
1315             }
1316 
1317             if ((flags & ENUM) != 0) {
1318                 // enums can't be declared abstract, final, sealed or non-sealed or value
1319                 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | VALUE_CLASS);
1320                 implicit |= implicitEnumFinalFlag(tree);
1321             }
1322             if ((flags & RECORD) != 0) {
1323                 // records can't be declared abstract
1324                 mask &= ~ABSTRACT;
1325                 implicit |= FINAL;
1326             }
1327             if ((flags & STRICTFP) != 0) {
1328                 warnOnExplicitStrictfp(tree);
1329             }
1330             // Imply STRICTFP if owner has STRICTFP set.
1331             implicit |= sym.owner.flags_field & STRICTFP;
1332 
1333             // concrete value classes are implicitly final
1334             if ((flags & (ABSTRACT | INTERFACE | VALUE_CLASS)) == VALUE_CLASS) {
1335                 implicit |= FINAL;
1336             }
1337             break;
1338         default:
1339             throw new AssertionError();
1340         }
1341         long illegal = flags & ExtendedStandardFlags & ~mask;
1342         if (illegal != 0) {
1343             if ((illegal & INTERFACE) != 0) {
1344                 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1345                 mask |= INTERFACE;
1346             }
1347             else {
1348                 log.error(pos,
1349                         Errors.ModNotAllowedHere(asFlagSet(illegal)));
1350             }
1351         } else if ((sym.kind == TYP ||

1352                   // ISSUE: Disallowing abstract&private is no longer appropriate
1353                   // in the presence of inner classes. Should it be deleted here?
1354                   checkDisjoint(pos, flags,
1355                                 ABSTRACT,
1356                                 PRIVATE | STATIC | DEFAULT))
1357                  &&
1358                  checkDisjoint(pos, flags,
1359                                 STATIC | PRIVATE,
1360                                 DEFAULT)
1361                  &&
1362                  checkDisjoint(pos, flags,
1363                                ABSTRACT | INTERFACE,
1364                                FINAL | NATIVE | SYNCHRONIZED)
1365                  &&
1366                  checkDisjoint(pos, flags,
1367                                PUBLIC,
1368                                PRIVATE | PROTECTED)
1369                  &&
1370                  checkDisjoint(pos, flags,
1371                                PRIVATE,
1372                                PUBLIC | PROTECTED)
1373                  &&
1374                  // we are using `implicit` here as instance fields of value classes are implicitly final
1375                  checkDisjoint(pos, flags | implicit,
1376                                FINAL,
1377                                VOLATILE)
1378                  &&
1379                  (sym.kind == TYP ||
1380                   checkDisjoint(pos, flags,
1381                                 ABSTRACT | NATIVE,
1382                                 STRICTFP))
1383                  && checkDisjoint(pos, flags,
1384                                 FINAL,
1385                            SEALED | NON_SEALED)
1386                  && checkDisjoint(pos, flags,
1387                                 SEALED,
1388                            FINAL | NON_SEALED)
1389                  && checkDisjoint(pos, flags,
1390                                 SEALED,
1391                                 ANNOTATION)
1392                 && checkDisjoint(pos, flags,
1393                                 VALUE_CLASS,
1394                                 ANNOTATION)
1395                 && checkDisjoint(pos, flags,
1396                                 VALUE_CLASS,
1397                                 INTERFACE) ) {
1398             // skip
1399         }
1400         return flags & (mask | ~ExtendedStandardFlags) | implicit;
1401     }
1402 
1403     private void warnOnExplicitStrictfp(JCTree tree) {
1404         deferredLintHandler.push(tree);
1405         try {
1406             deferredLintHandler.report(_ -> lint.logIfEnabled(tree.pos(), LintWarnings.Strictfp));
1407         } finally {
1408             deferredLintHandler.pop();
1409         }
1410     }
1411 
1412 
1413     /** Determine if this enum should be implicitly final.
1414      *
1415      *  If the enum has no specialized enum constants, it is final.
1416      *
1417      *  If the enum does have specialized enum constants, it is

2189                     return true;
2190                 }
2191             }
2192         }
2193         return false;
2194     }
2195 
2196     /** Check that a given method conforms with any method it overrides.
2197      *  @param tree         The tree from which positions are extracted
2198      *                      for errors.
2199      *  @param m            The overriding method.
2200      */
2201     void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2202         ClassSymbol origin = (ClassSymbol)m.owner;
2203         if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2204             if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2205                 log.error(tree.pos(), Errors.EnumNoFinalize);
2206                 return;
2207             }
2208         }
2209         if (allowValueClasses && origin.isValueClass() && names.finalize.equals(m.name)) {
2210             if (m.overrides(syms.objectFinalize, origin, types, false)) {
2211                 log.warning(tree.pos(), Warnings.ValueFinalize);
2212             }
2213         }
2214         if (allowRecords && origin.isRecord()) {
2215             // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2216             Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2217                     .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2218             if (recordComponent.isPresent()) {
2219                 return;
2220             }
2221         }
2222 
2223         for (Type t = origin.type; t.hasTag(CLASS);
2224              t = types.supertype(t)) {
2225             if (t != origin.type) {
2226                 checkOverride(tree, t, origin, m);
2227             }
2228             for (Type t2 : types.interfaces(t)) {
2229                 checkOverride(tree, t2, origin, m);
2230             }
2231         }
2232 
2233         final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;

2629     /** Check that all abstract methods implemented by a class are
2630      *  mutually compatible.
2631      *  @param pos          Position to be used for error reporting.
2632      *  @param c            The class whose interfaces are checked.
2633      */
2634     void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2635         List<Type> supertypes = types.interfaces(c);
2636         Type supertype = types.supertype(c);
2637         if (supertype.hasTag(CLASS) &&
2638             (supertype.tsym.flags() & ABSTRACT) != 0)
2639             supertypes = supertypes.prepend(supertype);
2640         for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2641             if (!l.head.getTypeArguments().isEmpty() &&
2642                 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2643                 return;
2644             for (List<Type> m = supertypes; m != l; m = m.tail)
2645                 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2646                     return;
2647         }
2648         checkCompatibleConcretes(pos, c);
2649 
2650         Type identitySuper = null;
2651         for (Type t : types.closure(c)) {
2652             if (t != c) {
2653                 if (t.isIdentityClass() && (t.tsym.flags() & VALUE_BASED) == 0)
2654                     identitySuper = t;
2655                 if (c.isValueClass() && identitySuper != null && identitySuper.tsym != syms.objectType.tsym) { // Object is special
2656                     log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, identitySuper));
2657                     break;
2658                 }
2659             }
2660         }
2661     }
2662 
2663     /** Check that all non-override equivalent methods accessible from 'site'
2664      *  are mutually compatible (JLS 8.4.8/9.4.1).
2665      *
2666      *  @param pos  Position to be used for error reporting.
2667      *  @param site The class whose methods are checked.
2668      *  @param sym  The method symbol to be checked.
2669      */
2670     void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2671          ClashFilter cf = new ClashFilter(site);
2672         //for each method m1 that is overridden (directly or indirectly)
2673         //by method 'sym' in 'site'...
2674 
2675         ArrayList<Symbol> symbolsByName = new ArrayList<>();
2676         types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2677         for (Symbol m1 : symbolsByName) {
2678             if (!sym.overrides(m1, site.tsym, types, false)) {
2679                 continue;
2680             }

4993                 }
4994             } else {
4995                 Assert.error("Unknown pattern: " + currentPattern.getTag());
4996             }
4997             return false;
4998         }
4999 
5000     /** check if a type is a subtype of Externalizable, if that is available. */
5001     boolean isExternalizable(Type t) {
5002         try {
5003             syms.externalizableType.complete();
5004         } catch (CompletionFailure e) {
5005             return false;
5006         }
5007         return types.isSubtype(t, syms.externalizableType);
5008     }
5009 
5010     /**
5011      * Check structure of serialization declarations.
5012      */
5013     public void checkSerialStructure(Env<AttrContext> env, JCClassDecl tree, ClassSymbol c) {
5014         (new SerialTypeVisitor(env)).visit(c, tree);
5015     }
5016 
5017     /**
5018      * This visitor will warn if a serialization-related field or
5019      * method is declared in a suspicious or incorrect way. In
5020      * particular, it will warn for cases where the runtime
5021      * serialization mechanism will silently ignore a mis-declared
5022      * entity.
5023      *
5024      * Distinguished serialization-related fields and methods:
5025      *
5026      * Methods:
5027      *
5028      * private void writeObject(ObjectOutputStream stream) throws IOException
5029      * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
5030      *
5031      * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
5032      * private void readObjectNoData() throws ObjectStreamException
5033      * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
5034      *
5035      * Fields:
5036      *
5037      * private static final long serialVersionUID
5038      * private static final ObjectStreamField[] serialPersistentFields
5039      *
5040      * Externalizable: methods defined on the interface
5041      * public void writeExternal(ObjectOutput) throws IOException
5042      * public void readExternal(ObjectInput) throws IOException
5043      */
5044     private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
5045         Env<AttrContext> env;
5046         SerialTypeVisitor(Env<AttrContext> env) {
5047             this.lint = Check.this.lint;
5048             this.env = env;
5049         }
5050 
5051         private static final Set<String> serialMethodNames =
5052             Set.of("writeObject", "writeReplace",
5053                    "readObject",  "readObjectNoData",
5054                    "readResolve");
5055 
5056         private static final Set<String> serialFieldNames =
5057             Set.of("serialVersionUID", "serialPersistentFields");
5058 
5059         // Type of serialPersistentFields
5060         private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
5061 
5062         Lint lint;
5063 
5064         @Override
5065         public Void defaultAction(Element e, JCClassDecl p) {
5066             throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
5067         }
5068 

5088                 if (sym.kind == VAR) {
5089                     svuidSym = (VarSymbol)sym;
5090                     break;
5091                 }
5092             }
5093 
5094             if (svuidSym == null) {
5095                 log.warning(p.pos(), LintWarnings.MissingSVUID(c));
5096             }
5097 
5098             // Check for serialPersistentFields to gate checks for
5099             // non-serializable non-transient instance fields
5100             boolean serialPersistentFieldsPresent =
5101                     c.members()
5102                      .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
5103                      .iterator()
5104                      .hasNext();
5105 
5106             // Check declarations of serialization-related methods and
5107             // fields
5108             final boolean[] hasWriteReplace = {false};
5109             for(Symbol el : c.getEnclosedElements()) {
5110                 runUnderLint(el, p, (enclosed, tree) -> {
5111                     String name = null;
5112                     switch(enclosed.getKind()) {
5113                     case FIELD -> {
5114                         if (!serialPersistentFieldsPresent) {
5115                             var flags = enclosed.flags();
5116                             if ( ((flags & TRANSIENT) == 0) &&
5117                                  ((flags & STATIC) == 0)) {
5118                                 Type varType = enclosed.asType();
5119                                 if (!canBeSerialized(varType)) {
5120                                     // Note per JLS arrays are
5121                                     // serializable even if the
5122                                     // component type is not.
5123                                     log.warning(
5124                                             TreeInfo.diagnosticPositionFor(enclosed, tree),
5125                                                 LintWarnings.NonSerializableInstanceField);
5126                                 } else if (varType.hasTag(ARRAY)) {
5127                                     ArrayType arrayType = (ArrayType)varType;
5128                                     Type elementType = arrayType.elemtype;

5163                     // will also pull in default methods from
5164                     // superinterfaces. In other words, the runtime checks
5165                     // (which long predate default methods on interfaces)
5166                     // do not admit the possibility of inheriting methods
5167                     // this way, a difference from general inheritance.
5168 
5169                     // The current implementation just checks the enclosed
5170                     // elements and does not directly check the inherited
5171                     // methods. If all the types are being checked this is
5172                     // less of a concern; however, there are cases that
5173                     // could be missed. In particular, readResolve and
5174                     // writeReplace could, in principle, by inherited from
5175                     // a non-serializable superclass and thus not checked
5176                     // even if compiled with a serializable child class.
5177                     case METHOD -> {
5178                         var method = (MethodSymbol)enclosed;
5179                         name = method.getSimpleName().toString();
5180                         if (serialMethodNames.contains(name)) {
5181                             switch (name) {
5182                             case "writeObject"      -> checkWriteObject(tree, e, method);
5183                             case "writeReplace"     -> {hasWriteReplace[0] = true; hasAppropriateWriteReplace(tree, method, true);}
5184                             case "readObject"       -> checkReadObject(tree,e, method);
5185                             case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
5186                             case "readResolve"      -> checkReadResolve(tree, e, method);
5187                             default ->  throw new AssertionError();
5188                             }
5189                         }
5190                     }
5191                     }
5192                 });
5193             }
5194             if (!hasWriteReplace[0] &&
5195                     (c.isValueClass() || hasAbstractValueSuperClass(c, Set.of(syms.numberType.tsym))) &&
5196                     !c.isAbstract() && !c.isRecord() &&
5197                     types.unboxedType(c.type) == Type.noType) {
5198                 // we need to check if the class is inheriting an appropriate writeReplace method
5199                 MethodSymbol ms = null;
5200                 Log.DiagnosticHandler discardHandler = log.new DiscardDiagnosticHandler();
5201                 try {
5202                     ms = rs.resolveInternalMethod(env.tree, env, c.type, names.writeReplace, List.nil(), List.nil());
5203                 } catch (FatalError fe) {
5204                     // ignore no method was found
5205                 } finally {
5206                     log.popDiagnosticHandler(discardHandler);
5207                 }
5208                 if (ms == null || !hasAppropriateWriteReplace(p, ms, false)) {
5209                     log.warning(p.pos(),
5210                             c.isValueClass() ? LintWarnings.SerializableValueClassWithoutWriteReplace1 :
5211                                     LintWarnings.SerializableValueClassWithoutWriteReplace2);
5212                 }
5213             }
5214             return null;
5215         }
5216 
5217         boolean canBeSerialized(Type type) {
5218             return type.isPrimitive() || rs.isSerializable(type);
5219         }
5220 
5221         private boolean hasAbstractValueSuperClass(Symbol c, Set<Symbol> excluding) {
5222             while (c.getKind() == ElementKind.CLASS) {
5223                 Type sup = ((ClassSymbol)c).getSuperclass();
5224                 if (!sup.hasTag(CLASS) || sup.isErroneous() ||
5225                         sup.tsym == syms.objectType.tsym) {
5226                     return false;
5227                 }
5228                 // if it is a value super class it has to be abstract
5229                 if (sup.isValueClass() && !excluding.contains(sup.tsym)) {
5230                     return true;
5231                 }
5232                 c = sup.tsym;
5233             }
5234             return false;
5235         }
5236 
5237         /**
5238          * Check that Externalizable class needs a public no-arg
5239          * constructor.
5240          *
5241          * Check that a Serializable class has access to the no-arg
5242          * constructor of its first nonserializable superclass.
5243          */
5244         private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5245             if (isExternalizable(c.type)) {
5246                 for(var sym : c.getEnclosedElements()) {
5247                     if (sym.isConstructor() &&
5248                         ((sym.flags() & PUBLIC) == PUBLIC)) {
5249                         if (((MethodSymbol)sym).getParameters().isEmpty()) {
5250                             return;
5251                         }
5252                     }
5253                 }
5254                 log.warning(tree.pos(),
5255                             LintWarnings.ExternalizableMissingPublicNoArgCtor);
5256             } else {

5340             // Warn if serialPersistentFields is initialized to a
5341             // literal null.
5342             JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5343             if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5344                 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5345                 JCExpression initExpr = variableDef.init;
5346                  if (initExpr != null && TreeInfo.isNull(initExpr)) {
5347                      log.warning(initExpr.pos(),
5348                                  LintWarnings.SPFNullInit);
5349                  }
5350             }
5351         }
5352 
5353         private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5354             // The "synchronized" modifier is seen in the wild on
5355             // readObject and writeObject methods and is generally
5356             // innocuous.
5357 
5358             // private void writeObject(ObjectOutputStream stream) throws IOException
5359             checkPrivateNonStaticMethod(tree, method);
5360             isExpectedReturnType(tree, method, syms.voidType, true);
5361             checkOneArg(tree, e, method, syms.objectOutputStreamType);
5362             hasExpectedExceptions(tree, method, true, syms.ioExceptionType);
5363             checkExternalizable(tree, e, method);
5364         }
5365 
5366         private boolean hasAppropriateWriteReplace(JCClassDecl tree, MethodSymbol method, boolean warn) {
5367             // ANY-ACCESS-MODIFIER Object writeReplace() throws
5368             // ObjectStreamException
5369 
5370             // Excluding abstract, could have a more complicated
5371             // rule based on abstract-ness of the class
5372             return isConcreteInstanceMethod(tree, method, warn) &&
5373                     isExpectedReturnType(tree, method, syms.objectType, warn) &&
5374                     hasNoArgs(tree, method, warn) &&
5375                     hasExpectedExceptions(tree, method, warn, syms.objectStreamExceptionType);
5376         }
5377 
5378         private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5379             // The "synchronized" modifier is seen in the wild on
5380             // readObject and writeObject methods and is generally
5381             // innocuous.
5382 
5383             // private void readObject(ObjectInputStream stream)
5384             //   throws IOException, ClassNotFoundException
5385             checkPrivateNonStaticMethod(tree, method);
5386             isExpectedReturnType(tree, method, syms.voidType, true);
5387             checkOneArg(tree, e, method, syms.objectInputStreamType);
5388             hasExpectedExceptions(tree, method, true, syms.ioExceptionType, syms.classNotFoundExceptionType);
5389             checkExternalizable(tree, e, method);
5390         }
5391 
5392         private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5393             // private void readObjectNoData() throws ObjectStreamException
5394             checkPrivateNonStaticMethod(tree, method);
5395             isExpectedReturnType(tree, method, syms.voidType, true);
5396             hasNoArgs(tree, method, true);
5397             hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5398             checkExternalizable(tree, e, method);
5399         }
5400 
5401         private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5402             // ANY-ACCESS-MODIFIER Object readResolve()
5403             // throws ObjectStreamException
5404 
5405             // Excluding abstract, could have a more complicated
5406             // rule based on abstract-ness of the class
5407             isConcreteInstanceMethod(tree, method, true);
5408             isExpectedReturnType(tree, method, syms.objectType, true);
5409             hasNoArgs(tree, method, true);
5410             hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5411         }
5412 
5413         private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5414             //public void writeExternal(ObjectOutput) throws IOException
5415             checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5416         }
5417 
5418         private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5419             // public void readExternal(ObjectInput) throws IOException
5420             checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5421          }
5422 
5423         private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5424                                              boolean isExtern) {
5425             if (isExtern && isExternMethod(tree, e, method, argType)) {
5426                 log.warning(
5427                         TreeInfo.diagnosticPositionFor(method, tree),
5428                             LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5429             }
5430         }

5640                     case FIELD -> {
5641                         var field = (VarSymbol)enclosed;
5642                         switch(name) {
5643                         case "serialPersistentFields" -> {
5644                             log.warning(
5645                                     TreeInfo.diagnosticPositionFor(field, tree),
5646                                         LintWarnings.IneffectualSerialFieldRecord);
5647                         }
5648 
5649                         case "serialVersionUID" -> {
5650                             // Could generate additional warning that
5651                             // svuid value is not checked to match for
5652                             // records.
5653                             checkSerialVersionUID(tree, e, field);
5654                         }}
5655                     }
5656 
5657                     case METHOD -> {
5658                         var method = (MethodSymbol)enclosed;
5659                         switch(name) {
5660                         case "writeReplace" -> hasAppropriateWriteReplace(tree, method, true);
5661                         case "readResolve"  -> checkReadResolve(tree, e, method);
5662 
5663                         case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5664                         case "readExternal"  -> checkReadExternalRecord(tree, e, method, isExtern);
5665 
5666                         default -> {
5667                             if (serialMethodNames.contains(name)) {
5668                                 log.warning(
5669                                         TreeInfo.diagnosticPositionFor(method, tree),
5670                                             LintWarnings.IneffectualSerialMethodRecord(name));
5671                             }
5672                         }}
5673                     }}});
5674             }
5675             return null;
5676         }
5677 
5678         boolean isConcreteInstanceMethod(JCClassDecl tree,
5679                                          MethodSymbol method,
5680                                          boolean warn) {
5681             if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5682                 if (warn) {
5683                     log.warning(
5684                             TreeInfo.diagnosticPositionFor(method, tree),
5685                                 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5686                 }
5687                 return false;
5688             }
5689             return true;
5690         }
5691 
5692         private boolean isExpectedReturnType(JCClassDecl tree,
5693                                           MethodSymbol method,
5694                                           Type expectedReturnType,
5695                                           boolean warn) {
5696             // Note: there may be complications checking writeReplace
5697             // and readResolve since they return Object and could, in
5698             // principle, have covariant overrides and any synthetic
5699             // bridge method would not be represented here for
5700             // checking.
5701             Type rtype = method.getReturnType();
5702             if (!types.isSameType(expectedReturnType, rtype)) {
5703                 if (warn) {
5704                     log.warning(
5705                             TreeInfo.diagnosticPositionFor(method, tree),
5706                             LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5707                                                                       rtype, expectedReturnType));
5708                 }
5709                 return false;
5710             }
5711             return true;
5712         }
5713 
5714         private void checkOneArg(JCClassDecl tree,
5715                                  Element enclosing,
5716                                  MethodSymbol method,
5717                                  Type expectedType) {
5718             String name = method.getSimpleName().toString();
5719 
5720             var parameters= method.getParameters();
5721 
5722             if (parameters.size() != 1) {
5723                 log.warning(
5724                         TreeInfo.diagnosticPositionFor(method, tree),
5725                             LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5726                 return;
5727             }
5728 
5729             Type parameterType = parameters.get(0).asType();
5730             if (!types.isSameType(parameterType, expectedType)) {
5731                 log.warning(
5732                         TreeInfo.diagnosticPositionFor(method, tree),
5733                             LintWarnings.SerialMethodParameterType(method.getSimpleName(),
5734                                                                expectedType,
5735                                                                parameterType));
5736             }
5737         }
5738 
5739         private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5740                                                  Element enclosing,
5741                                                  MethodSymbol method,
5742                                                  Type expectedType) {
5743             var parameters = method.getParameters();
5744             return (parameters.size() == 1) &&
5745                 types.isSameType(parameters.get(0).asType(), expectedType);
5746         }
5747 
5748 
5749         boolean hasNoArgs(JCClassDecl tree, MethodSymbol method, boolean warn) {
5750             var parameters = method.getParameters();
5751             if (!parameters.isEmpty()) {
5752                 if (warn) {
5753                     log.warning(
5754                             TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5755                             LintWarnings.SerialMethodNoArgs(method.getSimpleName()));
5756                 }
5757                 return false;
5758             }
5759             return true;
5760         }
5761 
5762         private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5763             // If the enclosing class is externalizable, warn for the method
5764             if (isExternalizable((Type)enclosing.asType())) {
5765                 log.warning(
5766                         TreeInfo.diagnosticPositionFor(method, tree),
5767                             LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5768             }
5769             return;
5770         }
5771 
5772         private boolean hasExpectedExceptions(JCClassDecl tree,
5773                                               MethodSymbol method,
5774                                               boolean warn,
5775                                               Type... declaredExceptions) {
5776             for (Type thrownType: method.getThrownTypes()) {
5777                 // For each exception in the throws clause of the
5778                 // method, if not an Error and not a RuntimeException,
5779                 // check if the exception is a subtype of a declared
5780                 // exception from the throws clause of the
5781                 // serialization method in question.
5782                 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5783                     types.isSubtype(thrownType, syms.errorType) ) {
5784                     continue;
5785                 } else {
5786                     boolean declared = false;
5787                     for (Type declaredException : declaredExceptions) {
5788                         if (types.isSubtype(thrownType, declaredException)) {
5789                             declared = true;
5790                             continue;
5791                         }
5792                     }
5793                     if (!declared) {
5794                         if (warn) {
5795                             log.warning(
5796                                     TreeInfo.diagnosticPositionFor(method, tree),
5797                                     LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5798                                                                              thrownType));
5799                         }
5800                         return false;
5801                     }
5802                 }
5803             }
5804             return true;
5805         }
5806 
5807         private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5808             Lint prevLint = lint;
5809             try {
5810                 lint = lint.augment((Symbol) symbol);
5811 
5812                 if (lint.isEnabled(LintCategory.SERIAL)) {
5813                     task.accept(symbol, p);
5814                 }
5815 
5816                 return null;
5817             } finally {
5818                 lint = prevLint;
5819             }
5820         }
5821 
5822     }
5823 
5824 }
< prev index next >