< 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 /* *************************************************************************
 222  * Errors and Warnings
 223  **************************************************************************/
 224 
 225     Lint setLint(Lint newLint) {
 226         Lint prev = lint;
 227         lint = newLint;
 228         return prev;
 229     }
 230 
 231     MethodSymbol setMethod(MethodSymbol newMethod) {
 232         MethodSymbol prev = method;
 233         method = newMethod;
 234         return prev;
 235     }
 236 
 237     /** Warn about deprecated symbol.
 238      *  @param pos        Position to be used for error reporting.
 239      *  @param sym        The deprecated symbol.
 240      */

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

























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

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


























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

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





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

1204             } else {
1205                 mask = MethodFlags;


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




1238             // Interfaces are always ABSTRACT
1239             if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1240 




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





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

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






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

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





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

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












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

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

4942             this.lint = Check.this.lint;

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

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

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

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



















5088             return null;
5089         }
5090 
5091         boolean canBeSerialized(Type type) {
5092             return type.isPrimitive() || rs.isSerializable(type);
5093         }
5094 
















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

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

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

5540                     log.warning(
5541                             TreeInfo.diagnosticPositionFor(method, tree),
5542                                 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));


5543             }

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

5559                             LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5560                                                                       rtype, expectedReturnType));


5561             }

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

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


5605             }

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

5642                                     LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5643                                                                              thrownType));


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

 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 /* *************************************************************************
 228  * Errors and Warnings
 229  **************************************************************************/
 230 
 231     Lint setLint(Lint newLint) {
 232         Lint prev = lint;
 233         lint = newLint;
 234         return prev;
 235     }
 236 
 237     MethodSymbol setMethod(MethodSymbol newMethod) {
 238         MethodSymbol prev = method;
 239         method = newMethod;
 240         return prev;
 241     }
 242 
 243     /** Warn about deprecated symbol.
 244      *  @param pos        Position to be used for error reporting.
 245      *  @param sym        The deprecated symbol.
 246      */

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

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

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

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

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

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

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

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

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

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

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