< prev index next >

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

Print this page

  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 
  28 import java.util.*;
  29 import java.util.function.BiConsumer;
  30 import java.util.function.BiPredicate;
  31 import java.util.function.Consumer;
  32 import java.util.function.Predicate;
  33 import java.util.function.Supplier;
  34 import java.util.function.ToIntBiFunction;
  35 import java.util.stream.Collectors;
  36 import java.util.stream.StreamSupport;
  37 
  38 import javax.lang.model.element.ElementKind;
  39 import javax.lang.model.element.NestingKind;
  40 import javax.tools.JavaFileManager;
  41 
  42 import com.sun.source.tree.CaseTree;
  43 import com.sun.tools.javac.code.*;
  44 import com.sun.tools.javac.code.Attribute.Compound;
  45 import com.sun.tools.javac.code.Directive.ExportsDirective;
  46 import com.sun.tools.javac.code.Directive.RequiresDirective;
  47 import com.sun.tools.javac.code.Source.Feature;
  48 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
  49 import com.sun.tools.javac.jvm.*;
  50 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  51 import com.sun.tools.javac.resources.CompilerProperties.Fragments;

  62 import com.sun.tools.javac.code.Lint;
  63 import com.sun.tools.javac.code.Lint.LintCategory;
  64 import com.sun.tools.javac.code.Scope.WriteableScope;
  65 import com.sun.tools.javac.code.Type.*;
  66 import com.sun.tools.javac.code.Symbol.*;
  67 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
  68 import com.sun.tools.javac.tree.JCTree.*;
  69 
  70 import static com.sun.tools.javac.code.Flags.*;
  71 import static com.sun.tools.javac.code.Flags.ANNOTATION;
  72 import static com.sun.tools.javac.code.Flags.SYNCHRONIZED;
  73 import static com.sun.tools.javac.code.Kinds.*;
  74 import static com.sun.tools.javac.code.Kinds.Kind.*;
  75 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  76 import static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE;
  77 import static com.sun.tools.javac.code.TypeTag.*;
  78 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
  79 
  80 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  81 import javax.lang.model.element.Element;
  82 import javax.lang.model.element.ExecutableElement;
  83 import javax.lang.model.element.TypeElement;
  84 import javax.lang.model.type.DeclaredType;
  85 import javax.lang.model.type.TypeMirror;
  86 import javax.lang.model.util.ElementFilter;
  87 import javax.lang.model.util.ElementKindVisitor14;
  88 
  89 /** Type checking helper class for the attribution phase.
  90  *
  91  *  <p><b>This is NOT part of any supported API.
  92  *  If you write code that depends on this, you do so at your own risk.
  93  *  This code and its internal interfaces are subject to change or
  94  *  deletion without notice.</b>
  95  */
  96 public class Check {
  97     protected static final Context.Key<Check> checkKey = new Context.Key<>();
  98 
  99     // Flag bits indicating which item(s) chosen from a pair of items
 100     private static final int FIRST = 0x01;
 101     private static final int SECOND = 0x02;
 102 
 103     private final Names names;
 104     private final Log log;
 105     private final Resolve rs;
 106     private final Symtab syms;

 167 
 168         boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
 169         boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
 170         boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
 171         boolean enforceMandatoryWarnings = true;
 172 
 173         deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated,
 174                 enforceMandatoryWarnings, "deprecated", LintCategory.DEPRECATION);
 175         removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
 176                 enforceMandatoryWarnings, "removal", LintCategory.REMOVAL);
 177         uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
 178                 enforceMandatoryWarnings, "unchecked", LintCategory.UNCHECKED);
 179         sunApiHandler = new MandatoryWarningHandler(log, null, false,
 180                 enforceMandatoryWarnings, "sunapi", null);
 181 
 182         deferredLintHandler = DeferredLintHandler.instance(context);
 183 
 184         allowModules = Feature.MODULES.allowedInSource(source);
 185         allowRecords = Feature.RECORDS.allowedInSource(source);
 186         allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);


 187     }
 188 
 189     /** Character for synthetic names
 190      */
 191     char syntheticNameChar;
 192 
 193     /** A table mapping flat names of all compiled classes for each module in this run
 194      *  to their symbols; maintained from outside.
 195      */
 196     private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
 197 
 198     /** A handler for messages about deprecated usage.
 199      */
 200     private MandatoryWarningHandler deprecationHandler;
 201 
 202     /** A handler for messages about deprecated-for-removal usage.
 203      */
 204     private MandatoryWarningHandler removalHandler;
 205 
 206     /** A handler for messages about unchecked or unsafe usage.

 210     /** A handler for messages about using proprietary API.
 211      */
 212     private MandatoryWarningHandler sunApiHandler;
 213 
 214     /** A handler for deferred lint warnings.
 215      */
 216     private DeferredLintHandler deferredLintHandler;
 217 
 218     /** Are modules allowed
 219      */
 220     private final boolean allowModules;
 221 
 222     /** Are records allowed
 223      */
 224     private final boolean allowRecords;
 225 
 226     /** Are sealed classes allowed
 227      */
 228     private final boolean allowSealed;
 229 




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

 743     /** Check that type is a class or interface type.
 744      *  @param pos           Position to be used for error reporting.
 745      *  @param t             The type to be checked.
 746      */
 747     Type checkClassType(DiagnosticPosition pos, Type t) {
 748         if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
 749             return typeTagError(pos,
 750                                 diags.fragment(Fragments.TypeReqClass),
 751                                 asTypeParam(t));
 752         } else {
 753             return t;
 754         }
 755     }
 756     //where
 757         private Object asTypeParam(Type t) {
 758             return (t.hasTag(TYPEVAR))
 759                                     ? diags.fragment(Fragments.TypeParameter(t))
 760                                     : t;
 761         }
 762 

























 763     /** Check that type is a valid qualifier for a constructor reference expression
 764      */
 765     Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
 766         t = checkClassOrArrayType(pos, t);
 767         if (t.hasTag(CLASS)) {
 768             if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
 769                 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
 770                 t = types.createErrorType(t);
 771             } else if ((t.tsym.flags() & ENUM) != 0) {
 772                 log.error(pos, Errors.EnumCantBeInstantiated);
 773                 t = types.createErrorType(t);
 774             } else {
 775                 t = checkClassType(pos, t, true);
 776             }
 777         } else if (t.hasTag(ARRAY)) {
 778             if (!types.isReifiable(((ArrayType)t).elemtype)) {
 779                 log.error(pos, Errors.GenericArrayCreation);
 780                 t = types.createErrorType(t);
 781             }
 782         }

 800                 args = args.tail;
 801             }
 802         }
 803         return t;
 804     }
 805 
 806     /** Check that type is a reference type, i.e. a class, interface or array type
 807      *  or a type variable.
 808      *  @param pos           Position to be used for error reporting.
 809      *  @param t             The type to be checked.
 810      */
 811     Type checkRefType(DiagnosticPosition pos, Type t) {
 812         if (t.isReference())
 813             return t;
 814         else
 815             return typeTagError(pos,
 816                                 diags.fragment(Fragments.TypeReqRef),
 817                                 t);
 818     }
 819 


























 820     /** Check that each type is a reference type, i.e. a class, interface or array type
 821      *  or a type variable.
 822      *  @param trees         Original trees, used for error reporting.
 823      *  @param types         The types to be checked.
 824      */
 825     List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
 826         List<JCExpression> tl = trees;
 827         for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
 828             l.head = checkRefType(tl.head.pos(), l.head);
 829             tl = tl.tail;
 830         }
 831         return types;
 832     }
 833 
 834     /** Check that type is a null or reference type.
 835      *  @param pos           Position to be used for error reporting.
 836      *  @param t             The type to be checked.
 837      */
 838     Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
 839         if (t.isReference() || t.hasTag(BOT))

1190      *  return modifiers together with any implicit modifiers for that symbol.
1191      *  Warning: we can't use flags() here since this method
1192      *  is called during class enter, when flags() would cause a premature
1193      *  completion.
1194      *  @param pos           Position to be used for error reporting.
1195      *  @param flags         The set of modifiers given in a definition.
1196      *  @param sym           The defined symbol.
1197      */
1198     long checkFlags(DiagnosticPosition pos, long flags, Symbol sym, JCTree tree) {
1199         long mask;
1200         long implicit = 0;
1201 
1202         switch (sym.kind) {
1203         case VAR:
1204             if (TreeInfo.isReceiverParam(tree))
1205                 mask = ReceiverParamFlags;
1206             else if (sym.owner.kind != TYP)
1207                 mask = LocalVarFlags;
1208             else if ((sym.owner.flags_field & INTERFACE) != 0)
1209                 mask = implicit = InterfaceVarFlags;
1210             else
1211                 mask = VarFlags;





1212             break;
1213         case MTH:
1214             if (sym.name == names.init) {
1215                 if ((sym.owner.flags_field & ENUM) != 0) {
1216                     // enum constructors cannot be declared public or
1217                     // protected and must be implicitly or explicitly
1218                     // private
1219                     implicit = PRIVATE;
1220                     mask = PRIVATE;
1221                 } else
1222                     mask = ConstructorFlags;
1223             }  else if ((sym.owner.flags_field & INTERFACE) != 0) {
1224                 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1225                     mask = AnnotationTypeElementMask;
1226                     implicit = PUBLIC | ABSTRACT;
1227                 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1228                     mask = InterfaceMethodMask;
1229                     implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1230                     if ((flags & DEFAULT) != 0) {
1231                         implicit |= ABSTRACT;
1232                     }
1233                 } else {
1234                     mask = implicit = InterfaceMethodFlags;
1235                 }
1236             } else if ((sym.owner.flags_field & RECORD) != 0) {
1237                 mask = RecordMethodFlags;

1238             } else {
1239                 mask = MethodFlags;


1240             }
1241             if ((flags & STRICTFP) != 0) {
1242                 warnOnExplicitStrictfp(pos);
1243             }
1244             // Imply STRICTFP if owner has STRICTFP set.
1245             if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1246                 ((flags) & Flags.DEFAULT) != 0)
1247                 implicit |= sym.owner.flags_field & STRICTFP;
1248             break;
1249         case TYP:
1250             if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1251                     (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1252                 boolean implicitlyStatic = !sym.isAnonymous() &&
1253                         ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1254                 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1255                 // local statics are allowed only if records are allowed too
1256                 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
1257                 implicit = implicitlyStatic ? STATIC : implicit;
1258             } else if (sym.owner.kind == TYP) {
1259                 // statics in inner classes are allowed only if records are allowed too
1260                 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1261                 if (sym.owner.owner.kind == PCK ||
1262                     (sym.owner.flags_field & STATIC) != 0) {
1263                     mask |= STATIC;
1264                 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1265                     log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1266                 }
1267                 // Nested interfaces and enums are always STATIC (Spec ???)
1268                 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1269             } else {
1270                 mask = ExtendedClassFlags;
1271             }




1272             // Interfaces are always ABSTRACT
1273             if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1274 




1275             if ((flags & ENUM) != 0) {
1276                 // enums can't be declared abstract, final, sealed or non-sealed
1277                 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
1278                 implicit |= implicitEnumFinalFlag(tree);
1279             }
1280             if ((flags & RECORD) != 0) {
1281                 // records can't be declared abstract
1282                 mask &= ~ABSTRACT;
1283                 implicit |= FINAL;
1284             }
1285             if ((flags & STRICTFP) != 0) {
1286                 warnOnExplicitStrictfp(pos);
1287             }
1288             // Imply STRICTFP if owner has STRICTFP set.
1289             implicit |= sym.owner.flags_field & STRICTFP;





1290             break;
1291         default:
1292             throw new AssertionError();
1293         }
1294         long illegal = flags & ExtendedStandardFlags & ~mask;
1295         if (illegal != 0) {
1296             if ((illegal & INTERFACE) != 0) {
1297                 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1298                 mask |= INTERFACE;
1299             }
1300             else {
1301                 log.error(pos,
1302                         Errors.ModNotAllowedHere(asFlagSet(illegal)));
1303             }
1304         }
1305         else if ((sym.kind == TYP ||
1306                   // ISSUE: Disallowing abstract&private is no longer appropriate
1307                   // in the presence of inner classes. Should it be deleted here?
1308                   checkDisjoint(pos, flags,
1309                                 ABSTRACT,
1310                                 PRIVATE | STATIC | DEFAULT))
1311                  &&
1312                  checkDisjoint(pos, flags,
1313                                 STATIC | PRIVATE,
1314                                 DEFAULT)
1315                  &&
1316                  checkDisjoint(pos, flags,
1317                                ABSTRACT | INTERFACE,
1318                                FINAL | NATIVE | SYNCHRONIZED)
1319                  &&
1320                  checkDisjoint(pos, flags,
1321                                PUBLIC,
1322                                PRIVATE | PROTECTED)
1323                  &&
1324                  checkDisjoint(pos, flags,
1325                                PRIVATE,
1326                                PUBLIC | PROTECTED)
1327                  &&
1328                  checkDisjoint(pos, flags,

1329                                FINAL,
1330                                VOLATILE)
1331                  &&
1332                  (sym.kind == TYP ||
1333                   checkDisjoint(pos, flags,
1334                                 ABSTRACT | NATIVE,
1335                                 STRICTFP))
1336                  && checkDisjoint(pos, flags,
1337                                 FINAL,
1338                            SEALED | NON_SEALED)
1339                  && checkDisjoint(pos, flags,
1340                                 SEALED,
1341                            FINAL | NON_SEALED)
1342                  && checkDisjoint(pos, flags,
1343                                 SEALED,
1344                                 ANNOTATION)) {






1345             // skip
1346         }
1347         return flags & (mask | ~ExtendedStandardFlags) | implicit;
1348     }
1349 
1350     private void warnOnExplicitStrictfp(DiagnosticPosition pos) {
1351         DiagnosticPosition prevLintPos = deferredLintHandler.setPos(pos);
1352         try {
1353             deferredLintHandler.report(_l -> {
1354                                            if (lint.isEnabled(LintCategory.STRICTFP)) {
1355                                                log.warning(LintCategory.STRICTFP,
1356                                                            pos, Warnings.Strictfp); }
1357                                        });
1358         } finally {
1359             deferredLintHandler.setPos(prevLintPos);
1360         }
1361     }
1362 
1363 
1364     /** Determine if this enum should be implicitly final.

2141                     return true;
2142                 }
2143             }
2144         }
2145         return false;
2146     }
2147 
2148     /** Check that a given method conforms with any method it overrides.
2149      *  @param tree         The tree from which positions are extracted
2150      *                      for errors.
2151      *  @param m            The overriding method.
2152      */
2153     void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2154         ClassSymbol origin = (ClassSymbol)m.owner;
2155         if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2156             if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2157                 log.error(tree.pos(), Errors.EnumNoFinalize);
2158                 return;
2159             }
2160         }





2161         if (allowRecords && origin.isRecord()) {
2162             // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2163             Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2164                     .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2165             if (recordComponent.isPresent()) {
2166                 return;
2167             }
2168         }
2169 
2170         for (Type t = origin.type; t.hasTag(CLASS);
2171              t = types.supertype(t)) {
2172             if (t != origin.type) {
2173                 checkOverride(tree, t, origin, m);
2174             }
2175             for (Type t2 : types.interfaces(t)) {
2176                 checkOverride(tree, t2, origin, m);
2177             }
2178         }
2179 
2180         final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;

2569     /** Check that all abstract methods implemented by a class are
2570      *  mutually compatible.
2571      *  @param pos          Position to be used for error reporting.
2572      *  @param c            The class whose interfaces are checked.
2573      */
2574     void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2575         List<Type> supertypes = types.interfaces(c);
2576         Type supertype = types.supertype(c);
2577         if (supertype.hasTag(CLASS) &&
2578             (supertype.tsym.flags() & ABSTRACT) != 0)
2579             supertypes = supertypes.prepend(supertype);
2580         for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2581             if (!l.head.getTypeArguments().isEmpty() &&
2582                 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2583                 return;
2584             for (List<Type> m = supertypes; m != l; m = m.tail)
2585                 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2586                     return;
2587         }
2588         checkCompatibleConcretes(pos, c);












2589     }
2590 
2591     /** Check that all non-override equivalent methods accessible from 'site'
2592      *  are mutually compatible (JLS 8.4.8/9.4.1).
2593      *
2594      *  @param pos  Position to be used for error reporting.
2595      *  @param site The class whose methods are checked.
2596      *  @param sym  The method symbol to be checked.
2597      */
2598     void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2599          ClashFilter cf = new ClashFilter(site);
2600         //for each method m1 that is overridden (directly or indirectly)
2601         //by method 'sym' in 'site'...
2602 
2603         ArrayList<Symbol> symbolsByName = new ArrayList<>();
2604         types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2605         for (Symbol m1 : symbolsByName) {
2606             if (!sym.overrides(m1, site.tsym, types, false)) {
2607                 continue;
2608             }

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

4934             this.lint = Check.this.lint;

4935         }
4936 
4937         private static final Set<String> serialMethodNames =
4938             Set.of("writeObject", "writeReplace",
4939                    "readObject",  "readObjectNoData",
4940                    "readResolve");
4941 
4942         private static final Set<String> serialFieldNames =
4943             Set.of("serialVersionUID", "serialPersistentFields");
4944 
4945         // Type of serialPersistentFields
4946         private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
4947 
4948         Lint lint;
4949 
4950         @Override
4951         public Void defaultAction(Element e, JCClassDecl p) {
4952             throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
4953         }
4954 

4974                 if (sym.kind == VAR) {
4975                     svuidSym = (VarSymbol)sym;
4976                     break;
4977                 }
4978             }
4979 
4980             if (svuidSym == null) {
4981                 log.warning(LintCategory.SERIAL, p.pos(), Warnings.MissingSVUID(c));
4982             }
4983 
4984             // Check for serialPersistentFields to gate checks for
4985             // non-serializable non-transient instance fields
4986             boolean serialPersistentFieldsPresent =
4987                     c.members()
4988                      .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
4989                      .iterator()
4990                      .hasNext();
4991 
4992             // Check declarations of serialization-related methods and
4993             // fields

4994             for(Symbol el : c.getEnclosedElements()) {
4995                 runUnderLint(el, p, (enclosed, tree) -> {
4996                     String name = null;
4997                     switch(enclosed.getKind()) {
4998                     case FIELD -> {
4999                         if (!serialPersistentFieldsPresent) {
5000                             var flags = enclosed.flags();
5001                             if ( ((flags & TRANSIENT) == 0) &&
5002                                  ((flags & STATIC) == 0)) {
5003                                 Type varType = enclosed.asType();
5004                                 if (!canBeSerialized(varType)) {
5005                                     // Note per JLS arrays are
5006                                     // serializable even if the
5007                                     // component type is not.
5008                                     log.warning(LintCategory.SERIAL,
5009                                                 TreeInfo.diagnosticPositionFor(enclosed, tree),
5010                                                 Warnings.NonSerializableInstanceField);
5011                                 } else if (varType.hasTag(ARRAY)) {
5012                                     ArrayType arrayType = (ArrayType)varType;
5013                                     Type elementType = arrayType.elemtype;

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



















5080             return null;
5081         }
5082 
5083         boolean canBeSerialized(Type type) {
5084             return type.isPrimitive() || rs.isSerializable(type);
5085         }
5086 
















5087         /**
5088          * Check that Externalizable class needs a public no-arg
5089          * constructor.
5090          *
5091          * Check that a Serializable class has access to the no-arg
5092          * constructor of its first nonserializable superclass.
5093          */
5094         private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5095             if (isExternalizable(c.type)) {
5096                 for(var sym : c.getEnclosedElements()) {
5097                     if (sym.isConstructor() &&
5098                         ((sym.flags() & PUBLIC) == PUBLIC)) {
5099                         if (((MethodSymbol)sym).getParameters().isEmpty()) {
5100                             return;
5101                         }
5102                     }
5103                 }
5104                 log.warning(LintCategory.SERIAL, tree.pos(),
5105                             Warnings.ExternalizableMissingPublicNoArgCtor);
5106             } else {

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

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

5532                     log.warning(LintCategory.SERIAL,
5533                                 TreeInfo.diagnosticPositionFor(method, tree),
5534                                 Warnings.SerialConcreteInstanceMethod(method.getSimpleName()));


5535             }

5536         }
5537 
5538         private void checkReturnType(JCClassDecl tree,
5539                                      Element enclosing,
5540                                      MethodSymbol method,
5541                                      Type expectedReturnType) {
5542             // Note: there may be complications checking writeReplace
5543             // and readResolve since they return Object and could, in
5544             // principle, have covariant overrides and any synthetic
5545             // bridge method would not be represented here for
5546             // checking.
5547             Type rtype = method.getReturnType();
5548             if (!types.isSameType(expectedReturnType, rtype)) {
5549                 log.warning(LintCategory.SERIAL,

5550                             TreeInfo.diagnosticPositionFor(method, tree),
5551                             Warnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5552                                                                       rtype, expectedReturnType));


5553             }

5554         }
5555 
5556         private void checkOneArg(JCClassDecl tree,
5557                                  Element enclosing,
5558                                  MethodSymbol method,
5559                                  Type expectedType) {
5560             String name = method.getSimpleName().toString();
5561 
5562             var parameters= method.getParameters();
5563 
5564             if (parameters.size() != 1) {
5565                 log.warning(LintCategory.SERIAL,
5566                             TreeInfo.diagnosticPositionFor(method, tree),
5567                             Warnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5568                 return;
5569             }
5570 
5571             Type parameterType = parameters.get(0).asType();
5572             if (!types.isSameType(parameterType, expectedType)) {
5573                 log.warning(LintCategory.SERIAL,
5574                             TreeInfo.diagnosticPositionFor(method, tree),
5575                             Warnings.SerialMethodParameterType(method.getSimpleName(),
5576                                                                expectedType,
5577                                                                parameterType));
5578             }
5579         }
5580 
5581         private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5582                                                  Element enclosing,
5583                                                  MethodSymbol method,
5584                                                  Type expectedType) {
5585             var parameters = method.getParameters();
5586             return (parameters.size() == 1) &&
5587                 types.isSameType(parameters.get(0).asType(), expectedType);
5588         }
5589 
5590 
5591         private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5592             var parameters = method.getParameters();
5593             if (!parameters.isEmpty()) {
5594                 log.warning(LintCategory.SERIAL,

5595                             TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5596                             Warnings.SerialMethodNoArgs(method.getSimpleName()));


5597             }

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

5633                                     TreeInfo.diagnosticPositionFor(method, tree),
5634                                     Warnings.SerialMethodUnexpectedException(method.getSimpleName(),
5635                                                                              thrownType));


5636                     }
5637                 }
5638             }
5639             return;
5640         }
5641 
5642         private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5643             Lint prevLint = lint;
5644             try {
5645                 lint = lint.augment((Symbol) symbol);
5646 
5647                 if (lint.isEnabled(LintCategory.SERIAL)) {
5648                     task.accept(symbol, p);
5649                 }
5650 
5651                 return null;
5652             } finally {
5653                 lint = prevLint;
5654             }
5655         }
5656 
5657     }
5658 
5659 }

  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.comp;
  27 
  28 import java.util.*;
  29 import java.util.function.BiConsumer;
  30 import java.util.function.BiPredicate;

  31 import java.util.function.Predicate;
  32 import java.util.function.Supplier;
  33 import java.util.function.ToIntBiFunction;
  34 import java.util.stream.Collectors;
  35 import java.util.stream.StreamSupport;
  36 
  37 import javax.lang.model.element.ElementKind;
  38 import javax.lang.model.element.NestingKind;
  39 import javax.tools.JavaFileManager;
  40 
  41 import com.sun.source.tree.CaseTree;
  42 import com.sun.tools.javac.code.*;
  43 import com.sun.tools.javac.code.Attribute.Compound;
  44 import com.sun.tools.javac.code.Directive.ExportsDirective;
  45 import com.sun.tools.javac.code.Directive.RequiresDirective;
  46 import com.sun.tools.javac.code.Source.Feature;
  47 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
  48 import com.sun.tools.javac.jvm.*;
  49 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  50 import com.sun.tools.javac.resources.CompilerProperties.Fragments;

  61 import com.sun.tools.javac.code.Lint;
  62 import com.sun.tools.javac.code.Lint.LintCategory;
  63 import com.sun.tools.javac.code.Scope.WriteableScope;
  64 import com.sun.tools.javac.code.Type.*;
  65 import com.sun.tools.javac.code.Symbol.*;
  66 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
  67 import com.sun.tools.javac.tree.JCTree.*;
  68 
  69 import static com.sun.tools.javac.code.Flags.*;
  70 import static com.sun.tools.javac.code.Flags.ANNOTATION;
  71 import static com.sun.tools.javac.code.Flags.SYNCHRONIZED;
  72 import static com.sun.tools.javac.code.Kinds.*;
  73 import static com.sun.tools.javac.code.Kinds.Kind.*;
  74 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  75 import static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE;
  76 import static com.sun.tools.javac.code.TypeTag.*;
  77 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
  78 
  79 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  80 import javax.lang.model.element.Element;

  81 import javax.lang.model.element.TypeElement;
  82 import javax.lang.model.type.DeclaredType;


  83 import javax.lang.model.util.ElementKindVisitor14;
  84 
  85 /** Type checking helper class for the attribution phase.
  86  *
  87  *  <p><b>This is NOT part of any supported API.
  88  *  If you write code that depends on this, you do so at your own risk.
  89  *  This code and its internal interfaces are subject to change or
  90  *  deletion without notice.</b>
  91  */
  92 public class Check {
  93     protected static final Context.Key<Check> checkKey = new Context.Key<>();
  94 
  95     // Flag bits indicating which item(s) chosen from a pair of items
  96     private static final int FIRST = 0x01;
  97     private static final int SECOND = 0x02;
  98 
  99     private final Names names;
 100     private final Log log;
 101     private final Resolve rs;
 102     private final Symtab syms;

 163 
 164         boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
 165         boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
 166         boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
 167         boolean enforceMandatoryWarnings = true;
 168 
 169         deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated,
 170                 enforceMandatoryWarnings, "deprecated", LintCategory.DEPRECATION);
 171         removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
 172                 enforceMandatoryWarnings, "removal", LintCategory.REMOVAL);
 173         uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
 174                 enforceMandatoryWarnings, "unchecked", LintCategory.UNCHECKED);
 175         sunApiHandler = new MandatoryWarningHandler(log, null, false,
 176                 enforceMandatoryWarnings, "sunapi", null);
 177 
 178         deferredLintHandler = DeferredLintHandler.instance(context);
 179 
 180         allowModules = Feature.MODULES.allowedInSource(source);
 181         allowRecords = Feature.RECORDS.allowedInSource(source);
 182         allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
 183         allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
 184                 Feature.VALUE_CLASSES.allowedInSource(source);
 185     }
 186 
 187     /** Character for synthetic names
 188      */
 189     char syntheticNameChar;
 190 
 191     /** A table mapping flat names of all compiled classes for each module in this run
 192      *  to their symbols; maintained from outside.
 193      */
 194     private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
 195 
 196     /** A handler for messages about deprecated usage.
 197      */
 198     private MandatoryWarningHandler deprecationHandler;
 199 
 200     /** A handler for messages about deprecated-for-removal usage.
 201      */
 202     private MandatoryWarningHandler removalHandler;
 203 
 204     /** A handler for messages about unchecked or unsafe usage.

 208     /** A handler for messages about using proprietary API.
 209      */
 210     private MandatoryWarningHandler sunApiHandler;
 211 
 212     /** A handler for deferred lint warnings.
 213      */
 214     private DeferredLintHandler deferredLintHandler;
 215 
 216     /** Are modules allowed
 217      */
 218     private final boolean allowModules;
 219 
 220     /** Are records allowed
 221      */
 222     private final boolean allowRecords;
 223 
 224     /** Are sealed classes allowed
 225      */
 226     private final boolean allowSealed;
 227 
 228     /** Are value classes allowed
 229      */
 230     private final boolean allowValueClasses;
 231 
 232 /* *************************************************************************
 233  * Errors and Warnings
 234  **************************************************************************/
 235 
 236     Lint setLint(Lint newLint) {
 237         Lint prev = lint;
 238         lint = newLint;
 239         return prev;
 240     }
 241 
 242     MethodSymbol setMethod(MethodSymbol newMethod) {
 243         MethodSymbol prev = method;
 244         method = newMethod;
 245         return prev;
 246     }
 247 
 248     /** Warn about deprecated symbol.
 249      *  @param pos        Position to be used for error reporting.
 250      *  @param sym        The deprecated symbol.
 251      */

 745     /** Check that type is a class or interface type.
 746      *  @param pos           Position to be used for error reporting.
 747      *  @param t             The type to be checked.
 748      */
 749     Type checkClassType(DiagnosticPosition pos, Type t) {
 750         if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
 751             return typeTagError(pos,
 752                                 diags.fragment(Fragments.TypeReqClass),
 753                                 asTypeParam(t));
 754         } else {
 755             return t;
 756         }
 757     }
 758     //where
 759         private Object asTypeParam(Type t) {
 760             return (t.hasTag(TYPEVAR))
 761                                     ? diags.fragment(Fragments.TypeParameter(t))
 762                                     : t;
 763         }
 764 
 765     void checkConstraintsOfValueClass(JCClassDecl tree, ClassSymbol c) {
 766         DiagnosticPosition pos = tree.pos();
 767         for (Type st : types.closure(c.type)) {
 768             if (st == null || st.tsym == null || st.tsym.kind == ERR)
 769                 continue;
 770             if  (st.tsym == syms.objectType.tsym || st.tsym == syms.recordType.tsym || st.isInterface())
 771                 continue;
 772             if (!st.tsym.isAbstract()) {
 773                 if (c != st.tsym) {
 774                     log.error(pos, Errors.ConcreteSupertypeForValueClass(c, st));
 775                 }
 776                 continue;
 777             }
 778             // dealing with an abstract value or value super class below.
 779             for (Symbol s : st.tsym.members().getSymbols(NON_RECURSIVE)) {
 780                 if (s.kind == MTH) {
 781                     if ((s.flags() & (SYNCHRONIZED | STATIC)) == SYNCHRONIZED) {
 782                         log.error(pos, Errors.SuperClassMethodCannotBeSynchronized(s, c, st));
 783                     }
 784                     break;
 785                 }
 786             }
 787         }
 788     }
 789 
 790     /** Check that type is a valid qualifier for a constructor reference expression
 791      */
 792     Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
 793         t = checkClassOrArrayType(pos, t);
 794         if (t.hasTag(CLASS)) {
 795             if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
 796                 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
 797                 t = types.createErrorType(t);
 798             } else if ((t.tsym.flags() & ENUM) != 0) {
 799                 log.error(pos, Errors.EnumCantBeInstantiated);
 800                 t = types.createErrorType(t);
 801             } else {
 802                 t = checkClassType(pos, t, true);
 803             }
 804         } else if (t.hasTag(ARRAY)) {
 805             if (!types.isReifiable(((ArrayType)t).elemtype)) {
 806                 log.error(pos, Errors.GenericArrayCreation);
 807                 t = types.createErrorType(t);
 808             }
 809         }

 827                 args = args.tail;
 828             }
 829         }
 830         return t;
 831     }
 832 
 833     /** Check that type is a reference type, i.e. a class, interface or array type
 834      *  or a type variable.
 835      *  @param pos           Position to be used for error reporting.
 836      *  @param t             The type to be checked.
 837      */
 838     Type checkRefType(DiagnosticPosition pos, Type t) {
 839         if (t.isReference())
 840             return t;
 841         else
 842             return typeTagError(pos,
 843                                 diags.fragment(Fragments.TypeReqRef),
 844                                 t);
 845     }
 846 
 847     /** Check that type is an identity type, i.e. not a value type.
 848      *  When not discernible statically, give it the benefit of doubt
 849      *  and defer to runtime.
 850      *
 851      *  @param pos           Position to be used for error reporting.
 852      *  @param t             The type to be checked.
 853      */
 854     boolean checkIdentityType(DiagnosticPosition pos, Type t) {
 855         if (t.hasTag(TYPEVAR)) {
 856             t = types.skipTypeVars(t, false);
 857         }
 858         if (t.isIntersection()) {
 859             IntersectionClassType ict = (IntersectionClassType)t;
 860             boolean result = true;
 861             for (Type component : ict.getExplicitComponents()) {
 862                 result &= checkIdentityType(pos, component);
 863             }
 864             return result;
 865         }
 866         if (t.isPrimitive() || (t.isValueClass() && !t.tsym.isAbstract())) {
 867             typeTagError(pos, diags.fragment(Fragments.TypeReqIdentity), t);
 868             return false;
 869         }
 870         return true;
 871     }
 872 
 873     /** Check that each type is a reference type, i.e. a class, interface or array type
 874      *  or a type variable.
 875      *  @param trees         Original trees, used for error reporting.
 876      *  @param types         The types to be checked.
 877      */
 878     List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
 879         List<JCExpression> tl = trees;
 880         for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
 881             l.head = checkRefType(tl.head.pos(), l.head);
 882             tl = tl.tail;
 883         }
 884         return types;
 885     }
 886 
 887     /** Check that type is a null or reference type.
 888      *  @param pos           Position to be used for error reporting.
 889      *  @param t             The type to be checked.
 890      */
 891     Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
 892         if (t.isReference() || t.hasTag(BOT))

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

1379                   // ISSUE: Disallowing abstract&private is no longer appropriate
1380                   // in the presence of inner classes. Should it be deleted here?
1381                   checkDisjoint(pos, flags,
1382                                 ABSTRACT,
1383                                 PRIVATE | STATIC | DEFAULT))
1384                  &&
1385                  checkDisjoint(pos, flags,
1386                                 STATIC | PRIVATE,
1387                                 DEFAULT)
1388                  &&
1389                  checkDisjoint(pos, flags,
1390                                ABSTRACT | INTERFACE,
1391                                FINAL | NATIVE | SYNCHRONIZED)
1392                  &&
1393                  checkDisjoint(pos, flags,
1394                                PUBLIC,
1395                                PRIVATE | PROTECTED)
1396                  &&
1397                  checkDisjoint(pos, flags,
1398                                PRIVATE,
1399                                PUBLIC | PROTECTED)
1400                  &&
1401                  // we are using `implicit` here as instance fields of value classes are implicitly final
1402                  checkDisjoint(pos, flags | implicit,
1403                                FINAL,
1404                                VOLATILE)
1405                  &&
1406                  (sym.kind == TYP ||
1407                   checkDisjoint(pos, flags,
1408                                 ABSTRACT | NATIVE,
1409                                 STRICTFP))
1410                  && checkDisjoint(pos, flags,
1411                                 FINAL,
1412                            SEALED | NON_SEALED)
1413                  && checkDisjoint(pos, flags,
1414                                 SEALED,
1415                            FINAL | NON_SEALED)
1416                  && checkDisjoint(pos, flags,
1417                                 SEALED,
1418                                 ANNOTATION)
1419                 && checkDisjoint(pos, flags,
1420                                 VALUE_CLASS,
1421                                 ANNOTATION)
1422                 && checkDisjoint(pos, flags,
1423                                 VALUE_CLASS,
1424                                 INTERFACE) ) {
1425             // skip
1426         }
1427         return flags & (mask | ~ExtendedStandardFlags) | implicit;
1428     }
1429 
1430     private void warnOnExplicitStrictfp(DiagnosticPosition pos) {
1431         DiagnosticPosition prevLintPos = deferredLintHandler.setPos(pos);
1432         try {
1433             deferredLintHandler.report(_l -> {
1434                                            if (lint.isEnabled(LintCategory.STRICTFP)) {
1435                                                log.warning(LintCategory.STRICTFP,
1436                                                            pos, Warnings.Strictfp); }
1437                                        });
1438         } finally {
1439             deferredLintHandler.setPos(prevLintPos);
1440         }
1441     }
1442 
1443 
1444     /** Determine if this enum should be implicitly final.

2221                     return true;
2222                 }
2223             }
2224         }
2225         return false;
2226     }
2227 
2228     /** Check that a given method conforms with any method it overrides.
2229      *  @param tree         The tree from which positions are extracted
2230      *                      for errors.
2231      *  @param m            The overriding method.
2232      */
2233     void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2234         ClassSymbol origin = (ClassSymbol)m.owner;
2235         if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2236             if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2237                 log.error(tree.pos(), Errors.EnumNoFinalize);
2238                 return;
2239             }
2240         }
2241         if (allowValueClasses && origin.isValueClass() && names.finalize.equals(m.name)) {
2242             if (m.overrides(syms.objectFinalize, origin, types, false)) {
2243                 log.warning(tree.pos(), Warnings.ValueFinalize);
2244             }
2245         }
2246         if (allowRecords && origin.isRecord()) {
2247             // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2248             Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2249                     .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2250             if (recordComponent.isPresent()) {
2251                 return;
2252             }
2253         }
2254 
2255         for (Type t = origin.type; t.hasTag(CLASS);
2256              t = types.supertype(t)) {
2257             if (t != origin.type) {
2258                 checkOverride(tree, t, origin, m);
2259             }
2260             for (Type t2 : types.interfaces(t)) {
2261                 checkOverride(tree, t2, origin, m);
2262             }
2263         }
2264 
2265         final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;

2654     /** Check that all abstract methods implemented by a class are
2655      *  mutually compatible.
2656      *  @param pos          Position to be used for error reporting.
2657      *  @param c            The class whose interfaces are checked.
2658      */
2659     void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2660         List<Type> supertypes = types.interfaces(c);
2661         Type supertype = types.supertype(c);
2662         if (supertype.hasTag(CLASS) &&
2663             (supertype.tsym.flags() & ABSTRACT) != 0)
2664             supertypes = supertypes.prepend(supertype);
2665         for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2666             if (!l.head.getTypeArguments().isEmpty() &&
2667                 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2668                 return;
2669             for (List<Type> m = supertypes; m != l; m = m.tail)
2670                 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2671                     return;
2672         }
2673         checkCompatibleConcretes(pos, c);
2674 
2675         Type identitySuper = null;
2676         for (Type t : types.closure(c)) {
2677             if (t != c) {
2678                 if (t.isIdentityClass() && (t.tsym.flags() & VALUE_BASED) == 0)
2679                     identitySuper = t;
2680                 if (c.isValueClass() && identitySuper != null && identitySuper.tsym != syms.objectType.tsym) { // Object is special
2681                     log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, identitySuper));
2682                     break;
2683                 }
2684             }
2685         }
2686     }
2687 
2688     /** Check that all non-override equivalent methods accessible from 'site'
2689      *  are mutually compatible (JLS 8.4.8/9.4.1).
2690      *
2691      *  @param pos  Position to be used for error reporting.
2692      *  @param site The class whose methods are checked.
2693      *  @param sym  The method symbol to be checked.
2694      */
2695     void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2696          ClashFilter cf = new ClashFilter(site);
2697         //for each method m1 that is overridden (directly or indirectly)
2698         //by method 'sym' in 'site'...
2699 
2700         ArrayList<Symbol> symbolsByName = new ArrayList<>();
2701         types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2702         for (Symbol m1 : symbolsByName) {
2703             if (!sym.overrides(m1, site.tsym, types, false)) {
2704                 continue;
2705             }

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

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

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

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

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