< 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,

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(() -> {
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             }

4043                     break;
4044 
4045                 // super()/this() calls must only appear in a constructor
4046                 if (!constructor) {
4047                     log.error(apply.pos(), Errors.CallMustOnlyAppearInCtor);
4048                     break;
4049                 }
4050 
4051                 // super()/this() calls must be a top level statement
4052                 if (scanDepth != MATCH_SCAN_DEPTH) {
4053                     log.error(apply.pos(), Errors.CtorCallsNotAllowedHere);
4054                     break;
4055                 }
4056 
4057                 // super()/this() calls must not appear more than once
4058                 if (initCall != null) {
4059                     log.error(apply.pos(), Errors.RedundantSuperclassInit);
4060                     break;
4061                 }
4062 
4063                 // If super()/this() isn't first, require "statements before super()" feature
4064                 if (!firstStatement)
4065                     preview.checkSourceLevel(apply.pos(), Feature.SUPER_INIT);
4066 
4067                 // We found a legitimate super()/this() call; remember it
4068                 initCall = methodName;
4069             } while (false);
4070 
4071             // Proceed
4072             super.visitApply(apply);
4073         }
4074 
4075         @Override
4076         public void visitReturn(JCReturn tree) {
4077             if (constructor && initCall == null && earlyReturn == null)
4078                 earlyReturn = tree;             // we have seen a return but not (yet) a super()/this()
4079             super.visitReturn(tree);
4080         }
4081 
4082         @Override
4083         public void visitClassDef(JCClassDecl tree) {

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

4957             this.lint = Check.this.lint;

4958         }
4959 
4960         private static final Set<String> serialMethodNames =
4961             Set.of("writeObject", "writeReplace",
4962                    "readObject",  "readObjectNoData",
4963                    "readResolve");
4964 
4965         private static final Set<String> serialFieldNames =
4966             Set.of("serialVersionUID", "serialPersistentFields");
4967 
4968         // Type of serialPersistentFields
4969         private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
4970 
4971         Lint lint;
4972 
4973         @Override
4974         public Void defaultAction(Element e, JCClassDecl p) {
4975             throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
4976         }
4977 

4997                 if (sym.kind == VAR) {
4998                     svuidSym = (VarSymbol)sym;
4999                     break;
5000                 }
5001             }
5002 
5003             if (svuidSym == null) {
5004                 log.warning(LintCategory.SERIAL, p.pos(), Warnings.MissingSVUID(c));
5005             }
5006 
5007             // Check for serialPersistentFields to gate checks for
5008             // non-serializable non-transient instance fields
5009             boolean serialPersistentFieldsPresent =
5010                     c.members()
5011                      .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
5012                      .iterator()
5013                      .hasNext();
5014 
5015             // Check declarations of serialization-related methods and
5016             // fields

5017             for(Symbol el : c.getEnclosedElements()) {
5018                 runUnderLint(el, p, (enclosed, tree) -> {
5019                     String name = null;
5020                     switch(enclosed.getKind()) {
5021                     case FIELD -> {
5022                         if (!serialPersistentFieldsPresent) {
5023                             var flags = enclosed.flags();
5024                             if ( ((flags & TRANSIENT) == 0) &&
5025                                  ((flags & STATIC) == 0)) {
5026                                 Type varType = enclosed.asType();
5027                                 if (!canBeSerialized(varType)) {
5028                                     // Note per JLS arrays are
5029                                     // serializable even if the
5030                                     // component type is not.
5031                                     log.warning(LintCategory.SERIAL,
5032                                                 TreeInfo.diagnosticPositionFor(enclosed, tree),
5033                                                 Warnings.NonSerializableInstanceField);
5034                                 } else if (varType.hasTag(ARRAY)) {
5035                                     ArrayType arrayType = (ArrayType)varType;
5036                                     Type elementType = arrayType.elemtype;

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



















5103             return null;
5104         }
5105 
5106         boolean canBeSerialized(Type type) {
5107             return type.isPrimitive() || rs.isSerializable(type);
5108         }
5109 
















5110         /**
5111          * Check that Externalizable class needs a public no-arg
5112          * constructor.
5113          *
5114          * Check that a Serializable class has access to the no-arg
5115          * constructor of its first nonserializable superclass.
5116          */
5117         private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5118             if (isExternalizable(c.type)) {
5119                 for(var sym : c.getEnclosedElements()) {
5120                     if (sym.isConstructor() &&
5121                         ((sym.flags() & PUBLIC) == PUBLIC)) {
5122                         if (((MethodSymbol)sym).getParameters().isEmpty()) {
5123                             return;
5124                         }
5125                     }
5126                 }
5127                 log.warning(LintCategory.SERIAL, tree.pos(),
5128                             Warnings.ExternalizableMissingPublicNoArgCtor);
5129             } else {

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

5513                     case FIELD -> {
5514                         var field = (VarSymbol)enclosed;
5515                         switch(name) {
5516                         case "serialPersistentFields" -> {
5517                             log.warning(LintCategory.SERIAL,
5518                                         TreeInfo.diagnosticPositionFor(field, tree),
5519                                         Warnings.IneffectualSerialFieldRecord);
5520                         }
5521 
5522                         case "serialVersionUID" -> {
5523                             // Could generate additional warning that
5524                             // svuid value is not checked to match for
5525                             // records.
5526                             checkSerialVersionUID(tree, e, field);
5527                         }}
5528                     }
5529 
5530                     case METHOD -> {
5531                         var method = (MethodSymbol)enclosed;
5532                         switch(name) {
5533                         case "writeReplace" -> checkWriteReplace(tree, e, method);
5534                         case "readResolve"  -> checkReadResolve(tree, e, method);
5535 
5536                         case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5537                         case "readExternal"  -> checkReadExternalRecord(tree, e, method, isExtern);
5538 
5539                         default -> {
5540                             if (serialMethodNames.contains(name)) {
5541                                 log.warning(LintCategory.SERIAL,
5542                                             TreeInfo.diagnosticPositionFor(method, tree),
5543                                             Warnings.IneffectualSerialMethodRecord(name));
5544                             }
5545                         }}
5546                     }}});
5547             }
5548             return null;
5549         }
5550 
5551         void checkConcreteInstanceMethod(JCClassDecl tree,
5552                                          Element enclosing,
5553                                          MethodSymbol method) {
5554             if ((method.flags() & (STATIC | ABSTRACT)) != 0) {

5555                     log.warning(LintCategory.SERIAL,
5556                                 TreeInfo.diagnosticPositionFor(method, tree),
5557                                 Warnings.SerialConcreteInstanceMethod(method.getSimpleName()));


5558             }

5559         }
5560 
5561         private void checkReturnType(JCClassDecl tree,
5562                                      Element enclosing,
5563                                      MethodSymbol method,
5564                                      Type expectedReturnType) {
5565             // Note: there may be complications checking writeReplace
5566             // and readResolve since they return Object and could, in
5567             // principle, have covariant overrides and any synthetic
5568             // bridge method would not be represented here for
5569             // checking.
5570             Type rtype = method.getReturnType();
5571             if (!types.isSameType(expectedReturnType, rtype)) {
5572                 log.warning(LintCategory.SERIAL,

5573                             TreeInfo.diagnosticPositionFor(method, tree),
5574                             Warnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5575                                                                       rtype, expectedReturnType));


5576             }

5577         }
5578 
5579         private void checkOneArg(JCClassDecl tree,
5580                                  Element enclosing,
5581                                  MethodSymbol method,
5582                                  Type expectedType) {
5583             String name = method.getSimpleName().toString();
5584 
5585             var parameters= method.getParameters();
5586 
5587             if (parameters.size() != 1) {
5588                 log.warning(LintCategory.SERIAL,
5589                             TreeInfo.diagnosticPositionFor(method, tree),
5590                             Warnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5591                 return;
5592             }
5593 
5594             Type parameterType = parameters.get(0).asType();
5595             if (!types.isSameType(parameterType, expectedType)) {
5596                 log.warning(LintCategory.SERIAL,
5597                             TreeInfo.diagnosticPositionFor(method, tree),
5598                             Warnings.SerialMethodParameterType(method.getSimpleName(),
5599                                                                expectedType,
5600                                                                parameterType));
5601             }
5602         }
5603 
5604         private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5605                                                  Element enclosing,
5606                                                  MethodSymbol method,
5607                                                  Type expectedType) {
5608             var parameters = method.getParameters();
5609             return (parameters.size() == 1) &&
5610                 types.isSameType(parameters.get(0).asType(), expectedType);
5611         }
5612 
5613 
5614         private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5615             var parameters = method.getParameters();
5616             if (!parameters.isEmpty()) {
5617                 log.warning(LintCategory.SERIAL,

5618                             TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5619                             Warnings.SerialMethodNoArgs(method.getSimpleName()));


5620             }

5621         }
5622 
5623         private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5624             // If the enclosing class is externalizable, warn for the method
5625             if (isExternalizable((Type)enclosing.asType())) {
5626                 log.warning(LintCategory.SERIAL,
5627                             TreeInfo.diagnosticPositionFor(method, tree),
5628                             Warnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5629             }
5630             return;
5631         }
5632 
5633         private void checkExceptions(JCClassDecl tree,
5634                                      Element enclosing,
5635                                      MethodSymbol method,
5636                                      Type... declaredExceptions) {
5637             for (Type thrownType: method.getThrownTypes()) {
5638                 // For each exception in the throws clause of the
5639                 // method, if not an Error and not a RuntimeException,
5640                 // check if the exception is a subtype of a declared
5641                 // exception from the throws clause of the
5642                 // serialization method in question.
5643                 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5644                     types.isSubtype(thrownType, syms.errorType) ) {
5645                     continue;
5646                 } else {
5647                     boolean declared = false;
5648                     for (Type declaredException : declaredExceptions) {
5649                         if (types.isSubtype(thrownType, declaredException)) {
5650                             declared = true;
5651                             continue;
5652                         }
5653                     }
5654                     if (!declared) {
5655                         log.warning(LintCategory.SERIAL,

5656                                     TreeInfo.diagnosticPositionFor(method, tree),
5657                                     Warnings.SerialMethodUnexpectedException(method.getSimpleName(),
5658                                                                              thrownType));


5659                     }
5660                 }
5661             }
5662             return;
5663         }
5664 
5665         private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5666             Lint prevLint = lint;
5667             try {
5668                 lint = lint.augment((Symbol) symbol);
5669 
5670                 if (lint.isEnabled(LintCategory.SERIAL)) {
5671                     task.accept(symbol, p);
5672                 }
5673 
5674                 return null;
5675             } finally {
5676                 lint = prevLint;
5677             }
5678         }
5679 
5680     }
5681 
5682 }

  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 : ExtendedVarFlags;
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             // Interfaces are always ABSTRACT
1334             if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1335 
1336             if ((flags & (INTERFACE | VALUE_CLASS)) == 0) {
1337                 implicit |= IDENTITY_TYPE;
1338             }
1339 
1340             if ((flags & ENUM) != 0) {
1341                 // enums can't be declared abstract, final, sealed or non-sealed or value
1342                 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | VALUE_CLASS);
1343                 implicit |= implicitEnumFinalFlag(tree);
1344             }
1345             if ((flags & RECORD) != 0) {
1346                 // records can't be declared abstract
1347                 mask &= ~ABSTRACT;
1348                 implicit |= FINAL;
1349             }
1350             if ((flags & STRICTFP) != 0) {
1351                 warnOnExplicitStrictfp(pos);
1352             }
1353             // Imply STRICTFP if owner has STRICTFP set.
1354             implicit |= sym.owner.flags_field & STRICTFP;
1355 
1356             // concrete value classes are implicitly final
1357             if ((flags & (ABSTRACT | INTERFACE | VALUE_CLASS)) == VALUE_CLASS) {
1358                 implicit |= FINAL;
1359             }
1360             break;
1361         default:
1362             throw new AssertionError();
1363         }
1364         long illegal = flags & ExtendedStandardFlags & ~mask;
1365         if (illegal != 0) {
1366             if ((illegal & INTERFACE) != 0) {
1367                 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1368                 mask |= INTERFACE;
1369             }
1370             else {
1371                 log.error(pos,
1372                         Errors.ModNotAllowedHere(asFlagSet(illegal)));
1373             }
1374         }
1375         else if ((sym.kind == TYP ||
1376                   // ISSUE: Disallowing abstract&private is no longer appropriate
1377                   // in the presence of inner classes. Should it be deleted here?
1378                   checkDisjoint(pos, flags,
1379                                 ABSTRACT,

1394                  checkDisjoint(pos, flags,
1395                                PRIVATE,
1396                                PUBLIC | PROTECTED)
1397                  &&
1398                  checkDisjoint(pos, flags,
1399                                FINAL,
1400                                VOLATILE)
1401                  &&
1402                  (sym.kind == TYP ||
1403                   checkDisjoint(pos, flags,
1404                                 ABSTRACT | NATIVE,
1405                                 STRICTFP))
1406                  && checkDisjoint(pos, flags,
1407                                 FINAL,
1408                            SEALED | NON_SEALED)
1409                  && checkDisjoint(pos, flags,
1410                                 SEALED,
1411                            FINAL | NON_SEALED)
1412                  && checkDisjoint(pos, flags,
1413                                 SEALED,
1414                                 ANNOTATION)
1415                 && checkDisjoint(pos, flags,
1416                                 VALUE_CLASS,
1417                                 ANNOTATION)
1418                 && checkDisjoint(pos, flags,
1419                                 VALUE_CLASS,
1420                                 NON_SEALED)
1421                 && checkDisjoint(pos, flags,
1422                                 VALUE_CLASS,
1423                                 INTERFACE) ) {
1424             // skip
1425         }
1426         return flags & (mask | ~ExtendedStandardFlags) | implicit;
1427     }
1428 
1429     private void warnOnExplicitStrictfp(DiagnosticPosition pos) {
1430         DiagnosticPosition prevLintPos = deferredLintHandler.setPos(pos);
1431         try {
1432             deferredLintHandler.report(() -> {
1433                                            if (lint.isEnabled(LintCategory.STRICTFP)) {
1434                                                log.warning(LintCategory.STRICTFP,
1435                                                            pos, Warnings.Strictfp); }
1436                                        });
1437         } finally {
1438             deferredLintHandler.setPos(prevLintPos);
1439         }
1440     }
1441 
1442 
1443     /** Determine if this enum should be implicitly final.

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

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

4139                     break;
4140 
4141                 // super()/this() calls must only appear in a constructor
4142                 if (!constructor) {
4143                     log.error(apply.pos(), Errors.CallMustOnlyAppearInCtor);
4144                     break;
4145                 }
4146 
4147                 // super()/this() calls must be a top level statement
4148                 if (scanDepth != MATCH_SCAN_DEPTH) {
4149                     log.error(apply.pos(), Errors.CtorCallsNotAllowedHere);
4150                     break;
4151                 }
4152 
4153                 // super()/this() calls must not appear more than once
4154                 if (initCall != null) {
4155                     log.error(apply.pos(), Errors.RedundantSuperclassInit);
4156                     break;
4157                 }
4158 
4159                 // If super()/this() isn't first, require flexible constructors feature
4160                 if (!firstStatement)
4161                     preview.checkSourceLevel(apply.pos(), Feature.SUPER_INIT);
4162 
4163                 // We found a legitimate super()/this() call; remember it
4164                 initCall = methodName;
4165             } while (false);
4166 
4167             // Proceed
4168             super.visitApply(apply);
4169         }
4170 
4171         @Override
4172         public void visitReturn(JCReturn tree) {
4173             if (constructor && initCall == null && earlyReturn == null)
4174                 earlyReturn = tree;             // we have seen a return but not (yet) a super()/this()
4175             super.visitReturn(tree);
4176         }
4177 
4178         @Override
4179         public void visitClassDef(JCClassDecl tree) {

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

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

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

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

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