164 profile = Profile.instance(context);
165 preview = Preview.instance(context);
166
167 boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
168 boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
169 boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
170 boolean enforceMandatoryWarnings = true;
171
172 deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated,
173 enforceMandatoryWarnings, LintCategory.DEPRECATION, "deprecated");
174 removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
175 enforceMandatoryWarnings, LintCategory.REMOVAL);
176 uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
177 enforceMandatoryWarnings, LintCategory.UNCHECKED);
178
179 deferredLintHandler = DeferredLintHandler.instance(context);
180
181 allowModules = Feature.MODULES.allowedInSource(source);
182 allowRecords = Feature.RECORDS.allowedInSource(source);
183 allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
184 }
185
186 /** Character for synthetic names
187 */
188 char syntheticNameChar;
189
190 /** A table mapping flat names of all compiled classes for each module in this run
191 * to their symbols; maintained from outside.
192 */
193 private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
194
195 /** A handler for messages about deprecated usage.
196 */
197 private MandatoryWarningHandler deprecationHandler;
198
199 /** A handler for messages about deprecated-for-removal usage.
200 */
201 private MandatoryWarningHandler removalHandler;
202
203 /** A handler for messages about unchecked or unsafe usage.
204 */
205 private MandatoryWarningHandler uncheckedHandler;
206
207 /** A handler for deferred lint warnings.
208 */
209 private DeferredLintHandler deferredLintHandler;
210
211 /** Are modules allowed
212 */
213 private final boolean allowModules;
214
215 /** Are records allowed
216 */
217 private final boolean allowRecords;
218
219 /** Are sealed classes allowed
220 */
221 private final boolean allowSealed;
222
223 /** Whether to force suppression of deprecation and preview warnings.
224 * This happens when attributing import statements for JDK 9+.
225 * @see Feature#DEPRECATION_ON_IMPORT
226 */
227 private boolean importSuppression;
228
229 /* *************************************************************************
230 * Errors and Warnings
231 **************************************************************************/
232
233 Lint setLint(Lint newLint) {
234 Lint prev = lint;
235 lint = newLint;
236 return prev;
237 }
238
239 boolean setImportSuppression(boolean newImportSuppression) {
240 boolean prev = importSuppression;
241 importSuppression = newImportSuppression;
242 return prev;
713 /** Check that type is a class or interface type.
714 * @param pos Position to be used for error reporting.
715 * @param t The type to be checked.
716 */
717 Type checkClassType(DiagnosticPosition pos, Type t) {
718 if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
719 return typeTagError(pos,
720 diags.fragment(Fragments.TypeReqClass),
721 asTypeParam(t));
722 } else {
723 return t;
724 }
725 }
726 //where
727 private Object asTypeParam(Type t) {
728 return (t.hasTag(TYPEVAR))
729 ? diags.fragment(Fragments.TypeParameter(t))
730 : t;
731 }
732
733 /** Check that type is a valid qualifier for a constructor reference expression
734 */
735 Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
736 t = checkClassOrArrayType(pos, t);
737 if (t.hasTag(CLASS)) {
738 if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
739 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
740 t = types.createErrorType(t);
741 } else if ((t.tsym.flags() & ENUM) != 0) {
742 log.error(pos, Errors.EnumCantBeInstantiated);
743 t = types.createErrorType(t);
744 } else {
745 t = checkClassType(pos, t, true);
746 }
747 } else if (t.hasTag(ARRAY)) {
748 if (!types.isReifiable(((ArrayType)t).elemtype)) {
749 log.error(pos, Errors.GenericArrayCreation);
750 t = types.createErrorType(t);
751 }
752 }
770 args = args.tail;
771 }
772 }
773 return t;
774 }
775
776 /** Check that type is a reference type, i.e. a class, interface or array type
777 * or a type variable.
778 * @param pos Position to be used for error reporting.
779 * @param t The type to be checked.
780 */
781 Type checkRefType(DiagnosticPosition pos, Type t) {
782 if (t.isReference())
783 return t;
784 else
785 return typeTagError(pos,
786 diags.fragment(Fragments.TypeReqRef),
787 t);
788 }
789
790 /** Check that each type is a reference type, i.e. a class, interface or array type
791 * or a type variable.
792 * @param trees Original trees, used for error reporting.
793 * @param types The types to be checked.
794 */
795 List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
796 List<JCExpression> tl = trees;
797 for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
798 l.head = checkRefType(tl.head.pos(), l.head);
799 tl = tl.tail;
800 }
801 return types;
802 }
803
804 /** Check that type is a null or reference type.
805 * @param pos Position to be used for error reporting.
806 * @param t The type to be checked.
807 */
808 Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
809 if (t.isReference() || t.hasTag(BOT))
1161 * Warning: we can't use flags() here since this method
1162 * is called during class enter, when flags() would cause a premature
1163 * completion.
1164 * @param flags The set of modifiers given in a definition.
1165 * @param sym The defined symbol.
1166 * @param tree The declaration
1167 */
1168 long checkFlags(long flags, Symbol sym, JCTree tree) {
1169 final DiagnosticPosition pos = tree.pos();
1170 long mask;
1171 long implicit = 0;
1172
1173 switch (sym.kind) {
1174 case VAR:
1175 if (TreeInfo.isReceiverParam(tree))
1176 mask = ReceiverParamFlags;
1177 else if (sym.owner.kind != TYP)
1178 mask = LocalVarFlags;
1179 else if ((sym.owner.flags_field & INTERFACE) != 0)
1180 mask = implicit = InterfaceVarFlags;
1181 else
1182 mask = VarFlags;
1183 break;
1184 case MTH:
1185 if (sym.name == names.init) {
1186 if ((sym.owner.flags_field & ENUM) != 0) {
1187 // enum constructors cannot be declared public or
1188 // protected and must be implicitly or explicitly
1189 // private
1190 implicit = PRIVATE;
1191 mask = PRIVATE;
1192 } else
1193 mask = ConstructorFlags;
1194 } else if ((sym.owner.flags_field & INTERFACE) != 0) {
1195 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1196 mask = AnnotationTypeElementMask;
1197 implicit = PUBLIC | ABSTRACT;
1198 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1199 mask = InterfaceMethodMask;
1200 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1201 if ((flags & DEFAULT) != 0) {
1202 implicit |= ABSTRACT;
1203 }
1204 } else {
1205 mask = implicit = InterfaceMethodFlags;
1206 }
1207 } else if ((sym.owner.flags_field & RECORD) != 0) {
1208 mask = RecordMethodFlags;
1209 } else {
1210 mask = MethodFlags;
1211 }
1212 if ((flags & STRICTFP) != 0) {
1213 warnOnExplicitStrictfp(tree);
1214 }
1215 // Imply STRICTFP if owner has STRICTFP set.
1216 if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1217 ((flags) & Flags.DEFAULT) != 0)
1218 implicit |= sym.owner.flags_field & STRICTFP;
1219 break;
1220 case TYP:
1221 if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1222 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1223 boolean implicitlyStatic = !sym.isAnonymous() &&
1224 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1225 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1226 // local statics are allowed only if records are allowed too
1227 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
1228 implicit = implicitlyStatic ? STATIC : implicit;
1229 } else if (sym.owner.kind == TYP) {
1230 // statics in inner classes are allowed only if records are allowed too
1231 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1232 if (sym.owner.owner.kind == PCK ||
1233 (sym.owner.flags_field & STATIC) != 0) {
1234 mask |= STATIC;
1235 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1236 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1237 }
1238 // Nested interfaces and enums are always STATIC (Spec ???)
1239 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1240 } else {
1241 mask = ExtendedClassFlags;
1242 }
1243 // Interfaces are always ABSTRACT
1244 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1245
1246 if ((flags & ENUM) != 0) {
1247 // enums can't be declared abstract, final, sealed or non-sealed
1248 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
1249 implicit |= implicitEnumFinalFlag(tree);
1250 }
1251 if ((flags & RECORD) != 0) {
1252 // records can't be declared abstract
1253 mask &= ~ABSTRACT;
1254 implicit |= FINAL;
1255 }
1256 if ((flags & STRICTFP) != 0) {
1257 warnOnExplicitStrictfp(tree);
1258 }
1259 // Imply STRICTFP if owner has STRICTFP set.
1260 implicit |= sym.owner.flags_field & STRICTFP;
1261 break;
1262 default:
1263 throw new AssertionError();
1264 }
1265 long illegal = flags & ExtendedStandardFlags & ~mask;
1266 if (illegal != 0) {
1267 if ((illegal & INTERFACE) != 0) {
1268 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1269 mask |= INTERFACE;
1270 }
1271 else {
1272 log.error(pos,
1273 Errors.ModNotAllowedHere(asFlagSet(illegal)));
1274 }
1275 }
1276 else if ((sym.kind == TYP ||
1277 // ISSUE: Disallowing abstract&private is no longer appropriate
1278 // in the presence of inner classes. Should it be deleted here?
1279 checkDisjoint(pos, flags,
1280 ABSTRACT,
1281 PRIVATE | STATIC | DEFAULT))
1282 &&
1283 checkDisjoint(pos, flags,
1284 STATIC | PRIVATE,
1285 DEFAULT)
1286 &&
1287 checkDisjoint(pos, flags,
1288 ABSTRACT | INTERFACE,
1289 FINAL | NATIVE | SYNCHRONIZED)
1290 &&
1291 checkDisjoint(pos, flags,
1292 PUBLIC,
1293 PRIVATE | PROTECTED)
1294 &&
1295 checkDisjoint(pos, flags,
1296 PRIVATE,
1297 PUBLIC | PROTECTED)
1298 &&
1299 checkDisjoint(pos, flags,
1300 FINAL,
1301 VOLATILE)
1302 &&
1303 (sym.kind == TYP ||
1304 checkDisjoint(pos, flags,
1305 ABSTRACT | NATIVE,
1306 STRICTFP))
1307 && checkDisjoint(pos, flags,
1308 FINAL,
1309 SEALED | NON_SEALED)
1310 && checkDisjoint(pos, flags,
1311 SEALED,
1312 FINAL | NON_SEALED)
1313 && checkDisjoint(pos, flags,
1314 SEALED,
1315 ANNOTATION)) {
1316 // skip
1317 }
1318 return flags & (mask | ~ExtendedStandardFlags) | implicit;
1319 }
1320
1321 private void warnOnExplicitStrictfp(JCTree tree) {
1322 deferredLintHandler.push(tree);
1323 try {
1324 deferredLintHandler.report(_ -> lint.logIfEnabled(tree.pos(), LintWarnings.Strictfp));
1325 } finally {
1326 deferredLintHandler.pop();
1327 }
1328 }
1329
1330
1331 /** Determine if this enum should be implicitly final.
1332 *
1333 * If the enum has no specialized enum constants, it is final.
1334 *
1335 * If the enum does have specialized enum constants, it is
2107 return true;
2108 }
2109 }
2110 }
2111 return false;
2112 }
2113
2114 /** Check that a given method conforms with any method it overrides.
2115 * @param tree The tree from which positions are extracted
2116 * for errors.
2117 * @param m The overriding method.
2118 */
2119 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2120 ClassSymbol origin = (ClassSymbol)m.owner;
2121 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2122 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2123 log.error(tree.pos(), Errors.EnumNoFinalize);
2124 return;
2125 }
2126 }
2127 if (allowRecords && origin.isRecord()) {
2128 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2129 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2130 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2131 if (recordComponent.isPresent()) {
2132 return;
2133 }
2134 }
2135
2136 for (Type t = origin.type; t.hasTag(CLASS);
2137 t = types.supertype(t)) {
2138 if (t != origin.type) {
2139 checkOverride(tree, t, origin, m);
2140 }
2141 for (Type t2 : types.interfaces(t)) {
2142 checkOverride(tree, t2, origin, m);
2143 }
2144 }
2145
2146 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
2542 /** Check that all abstract methods implemented by a class are
2543 * mutually compatible.
2544 * @param pos Position to be used for error reporting.
2545 * @param c The class whose interfaces are checked.
2546 */
2547 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2548 List<Type> supertypes = types.interfaces(c);
2549 Type supertype = types.supertype(c);
2550 if (supertype.hasTag(CLASS) &&
2551 (supertype.tsym.flags() & ABSTRACT) != 0)
2552 supertypes = supertypes.prepend(supertype);
2553 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2554 if (!l.head.getTypeArguments().isEmpty() &&
2555 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2556 return;
2557 for (List<Type> m = supertypes; m != l; m = m.tail)
2558 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2559 return;
2560 }
2561 checkCompatibleConcretes(pos, c);
2562 }
2563
2564 /** Check that all non-override equivalent methods accessible from 'site'
2565 * are mutually compatible (JLS 8.4.8/9.4.1).
2566 *
2567 * @param pos Position to be used for error reporting.
2568 * @param site The class whose methods are checked.
2569 * @param sym The method symbol to be checked.
2570 */
2571 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2572 ClashFilter cf = new ClashFilter(site);
2573 //for each method m1 that is overridden (directly or indirectly)
2574 //by method 'sym' in 'site'...
2575
2576 ArrayList<Symbol> symbolsByName = new ArrayList<>();
2577 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2578 for (Symbol m1 : symbolsByName) {
2579 if (!sym.overrides(m1, site.tsym, types, false)) {
2580 continue;
2581 }
4894 }
4895 } else {
4896 Assert.error("Unknown pattern: " + currentPattern.getTag());
4897 }
4898 return false;
4899 }
4900
4901 /** check if a type is a subtype of Externalizable, if that is available. */
4902 boolean isExternalizable(Type t) {
4903 try {
4904 syms.externalizableType.complete();
4905 } catch (CompletionFailure e) {
4906 return false;
4907 }
4908 return types.isSubtype(t, syms.externalizableType);
4909 }
4910
4911 /**
4912 * Check structure of serialization declarations.
4913 */
4914 public void checkSerialStructure(JCClassDecl tree, ClassSymbol c) {
4915 (new SerialTypeVisitor()).visit(c, tree);
4916 }
4917
4918 /**
4919 * This visitor will warn if a serialization-related field or
4920 * method is declared in a suspicious or incorrect way. In
4921 * particular, it will warn for cases where the runtime
4922 * serialization mechanism will silently ignore a mis-declared
4923 * entity.
4924 *
4925 * Distinguished serialization-related fields and methods:
4926 *
4927 * Methods:
4928 *
4929 * private void writeObject(ObjectOutputStream stream) throws IOException
4930 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
4931 *
4932 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
4933 * private void readObjectNoData() throws ObjectStreamException
4934 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
4935 *
4936 * Fields:
4937 *
4938 * private static final long serialVersionUID
4939 * private static final ObjectStreamField[] serialPersistentFields
4940 *
4941 * Externalizable: methods defined on the interface
4942 * public void writeExternal(ObjectOutput) throws IOException
4943 * public void readExternal(ObjectInput) throws IOException
4944 */
4945 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
4946 SerialTypeVisitor() {
4947 this.lint = Check.this.lint;
4948 }
4949
4950 private static final Set<String> serialMethodNames =
4951 Set.of("writeObject", "writeReplace",
4952 "readObject", "readObjectNoData",
4953 "readResolve");
4954
4955 private static final Set<String> serialFieldNames =
4956 Set.of("serialVersionUID", "serialPersistentFields");
4957
4958 // Type of serialPersistentFields
4959 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
4960
4961 Lint lint;
4962
4963 @Override
4964 public Void defaultAction(Element e, JCClassDecl p) {
4965 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
4966 }
4967
4987 if (sym.kind == VAR) {
4988 svuidSym = (VarSymbol)sym;
4989 break;
4990 }
4991 }
4992
4993 if (svuidSym == null) {
4994 log.warning(p.pos(), LintWarnings.MissingSVUID(c));
4995 }
4996
4997 // Check for serialPersistentFields to gate checks for
4998 // non-serializable non-transient instance fields
4999 boolean serialPersistentFieldsPresent =
5000 c.members()
5001 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
5002 .iterator()
5003 .hasNext();
5004
5005 // Check declarations of serialization-related methods and
5006 // fields
5007 for(Symbol el : c.getEnclosedElements()) {
5008 runUnderLint(el, p, (enclosed, tree) -> {
5009 String name = null;
5010 switch(enclosed.getKind()) {
5011 case FIELD -> {
5012 if (!serialPersistentFieldsPresent) {
5013 var flags = enclosed.flags();
5014 if ( ((flags & TRANSIENT) == 0) &&
5015 ((flags & STATIC) == 0)) {
5016 Type varType = enclosed.asType();
5017 if (!canBeSerialized(varType)) {
5018 // Note per JLS arrays are
5019 // serializable even if the
5020 // component type is not.
5021 log.warning(
5022 TreeInfo.diagnosticPositionFor(enclosed, tree),
5023 LintWarnings.NonSerializableInstanceField);
5024 } else if (varType.hasTag(ARRAY)) {
5025 ArrayType arrayType = (ArrayType)varType;
5026 Type elementType = arrayType.elemtype;
5061 // will also pull in default methods from
5062 // superinterfaces. In other words, the runtime checks
5063 // (which long predate default methods on interfaces)
5064 // do not admit the possibility of inheriting methods
5065 // this way, a difference from general inheritance.
5066
5067 // The current implementation just checks the enclosed
5068 // elements and does not directly check the inherited
5069 // methods. If all the types are being checked this is
5070 // less of a concern; however, there are cases that
5071 // could be missed. In particular, readResolve and
5072 // writeReplace could, in principle, by inherited from
5073 // a non-serializable superclass and thus not checked
5074 // even if compiled with a serializable child class.
5075 case METHOD -> {
5076 var method = (MethodSymbol)enclosed;
5077 name = method.getSimpleName().toString();
5078 if (serialMethodNames.contains(name)) {
5079 switch (name) {
5080 case "writeObject" -> checkWriteObject(tree, e, method);
5081 case "writeReplace" -> checkWriteReplace(tree,e, method);
5082 case "readObject" -> checkReadObject(tree,e, method);
5083 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
5084 case "readResolve" -> checkReadResolve(tree, e, method);
5085 default -> throw new AssertionError();
5086 }
5087 }
5088 }
5089 }
5090 });
5091 }
5092
5093 return null;
5094 }
5095
5096 boolean canBeSerialized(Type type) {
5097 return type.isPrimitive() || rs.isSerializable(type);
5098 }
5099
5100 /**
5101 * Check that Externalizable class needs a public no-arg
5102 * constructor.
5103 *
5104 * Check that a Serializable class has access to the no-arg
5105 * constructor of its first nonserializable superclass.
5106 */
5107 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5108 if (isExternalizable(c.type)) {
5109 for(var sym : c.getEnclosedElements()) {
5110 if (sym.isConstructor() &&
5111 ((sym.flags() & PUBLIC) == PUBLIC)) {
5112 if (((MethodSymbol)sym).getParameters().isEmpty()) {
5113 return;
5114 }
5115 }
5116 }
5117 log.warning(tree.pos(),
5118 LintWarnings.ExternalizableMissingPublicNoArgCtor);
5119 } else {
5203 // Warn if serialPersistentFields is initialized to a
5204 // literal null.
5205 JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5206 if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5207 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5208 JCExpression initExpr = variableDef.init;
5209 if (initExpr != null && TreeInfo.isNull(initExpr)) {
5210 log.warning(initExpr.pos(),
5211 LintWarnings.SPFNullInit);
5212 }
5213 }
5214 }
5215
5216 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5217 // The "synchronized" modifier is seen in the wild on
5218 // readObject and writeObject methods and is generally
5219 // innocuous.
5220
5221 // private void writeObject(ObjectOutputStream stream) throws IOException
5222 checkPrivateNonStaticMethod(tree, method);
5223 checkReturnType(tree, e, method, syms.voidType);
5224 checkOneArg(tree, e, method, syms.objectOutputStreamType);
5225 checkExceptions(tree, e, method, syms.ioExceptionType);
5226 checkExternalizable(tree, e, method);
5227 }
5228
5229 private void checkWriteReplace(JCClassDecl tree, Element e, MethodSymbol method) {
5230 // ANY-ACCESS-MODIFIER Object writeReplace() throws
5231 // ObjectStreamException
5232
5233 // Excluding abstract, could have a more complicated
5234 // rule based on abstract-ness of the class
5235 checkConcreteInstanceMethod(tree, e, method);
5236 checkReturnType(tree, e, method, syms.objectType);
5237 checkNoArgs(tree, e, method);
5238 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5239 }
5240
5241 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5242 // The "synchronized" modifier is seen in the wild on
5243 // readObject and writeObject methods and is generally
5244 // innocuous.
5245
5246 // private void readObject(ObjectInputStream stream)
5247 // throws IOException, ClassNotFoundException
5248 checkPrivateNonStaticMethod(tree, method);
5249 checkReturnType(tree, e, method, syms.voidType);
5250 checkOneArg(tree, e, method, syms.objectInputStreamType);
5251 checkExceptions(tree, e, method, syms.ioExceptionType, syms.classNotFoundExceptionType);
5252 checkExternalizable(tree, e, method);
5253 }
5254
5255 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5256 // private void readObjectNoData() throws ObjectStreamException
5257 checkPrivateNonStaticMethod(tree, method);
5258 checkReturnType(tree, e, method, syms.voidType);
5259 checkNoArgs(tree, e, method);
5260 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5261 checkExternalizable(tree, e, method);
5262 }
5263
5264 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5265 // ANY-ACCESS-MODIFIER Object readResolve()
5266 // throws ObjectStreamException
5267
5268 // Excluding abstract, could have a more complicated
5269 // rule based on abstract-ness of the class
5270 checkConcreteInstanceMethod(tree, e, method);
5271 checkReturnType(tree,e, method, syms.objectType);
5272 checkNoArgs(tree, e, method);
5273 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5274 }
5275
5276 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5277 //public void writeExternal(ObjectOutput) throws IOException
5278 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5279 }
5280
5281 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5282 // public void readExternal(ObjectInput) throws IOException
5283 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5284 }
5285
5286 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5287 boolean isExtern) {
5288 if (isExtern && isExternMethod(tree, e, method, argType)) {
5289 log.warning(
5290 TreeInfo.diagnosticPositionFor(method, tree),
5291 LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5292 }
5293 }
5503 case FIELD -> {
5504 var field = (VarSymbol)enclosed;
5505 switch(name) {
5506 case "serialPersistentFields" -> {
5507 log.warning(
5508 TreeInfo.diagnosticPositionFor(field, tree),
5509 LintWarnings.IneffectualSerialFieldRecord);
5510 }
5511
5512 case "serialVersionUID" -> {
5513 // Could generate additional warning that
5514 // svuid value is not checked to match for
5515 // records.
5516 checkSerialVersionUID(tree, e, field);
5517 }}
5518 }
5519
5520 case METHOD -> {
5521 var method = (MethodSymbol)enclosed;
5522 switch(name) {
5523 case "writeReplace" -> checkWriteReplace(tree, e, method);
5524 case "readResolve" -> checkReadResolve(tree, e, method);
5525
5526 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5527 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern);
5528
5529 default -> {
5530 if (serialMethodNames.contains(name)) {
5531 log.warning(
5532 TreeInfo.diagnosticPositionFor(method, tree),
5533 LintWarnings.IneffectualSerialMethodRecord(name));
5534 }
5535 }}
5536 }}});
5537 }
5538 return null;
5539 }
5540
5541 void checkConcreteInstanceMethod(JCClassDecl tree,
5542 Element enclosing,
5543 MethodSymbol method) {
5544 if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5545 log.warning(
5546 TreeInfo.diagnosticPositionFor(method, tree),
5547 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5548 }
5549 }
5550
5551 private void checkReturnType(JCClassDecl tree,
5552 Element enclosing,
5553 MethodSymbol method,
5554 Type expectedReturnType) {
5555 // Note: there may be complications checking writeReplace
5556 // and readResolve since they return Object and could, in
5557 // principle, have covariant overrides and any synthetic
5558 // bridge method would not be represented here for
5559 // checking.
5560 Type rtype = method.getReturnType();
5561 if (!types.isSameType(expectedReturnType, rtype)) {
5562 log.warning(
5563 TreeInfo.diagnosticPositionFor(method, tree),
5564 LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5565 rtype, expectedReturnType));
5566 }
5567 }
5568
5569 private void checkOneArg(JCClassDecl tree,
5570 Element enclosing,
5571 MethodSymbol method,
5572 Type expectedType) {
5573 String name = method.getSimpleName().toString();
5574
5575 var parameters= method.getParameters();
5576
5577 if (parameters.size() != 1) {
5578 log.warning(
5579 TreeInfo.diagnosticPositionFor(method, tree),
5580 LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5581 return;
5582 }
5583
5584 Type parameterType = parameters.get(0).asType();
5585 if (!types.isSameType(parameterType, expectedType)) {
5586 log.warning(
5587 TreeInfo.diagnosticPositionFor(method, tree),
5588 LintWarnings.SerialMethodParameterType(method.getSimpleName(),
5589 expectedType,
5590 parameterType));
5591 }
5592 }
5593
5594 private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5595 Element enclosing,
5596 MethodSymbol method,
5597 Type expectedType) {
5598 var parameters = method.getParameters();
5599 return (parameters.size() == 1) &&
5600 types.isSameType(parameters.get(0).asType(), expectedType);
5601 }
5602
5603
5604 private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5605 var parameters = method.getParameters();
5606 if (!parameters.isEmpty()) {
5607 log.warning(
5608 TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5609 LintWarnings.SerialMethodNoArgs(method.getSimpleName()));
5610 }
5611 }
5612
5613 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5614 // If the enclosing class is externalizable, warn for the method
5615 if (isExternalizable((Type)enclosing.asType())) {
5616 log.warning(
5617 TreeInfo.diagnosticPositionFor(method, tree),
5618 LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5619 }
5620 return;
5621 }
5622
5623 private void checkExceptions(JCClassDecl tree,
5624 Element enclosing,
5625 MethodSymbol method,
5626 Type... declaredExceptions) {
5627 for (Type thrownType: method.getThrownTypes()) {
5628 // For each exception in the throws clause of the
5629 // method, if not an Error and not a RuntimeException,
5630 // check if the exception is a subtype of a declared
5631 // exception from the throws clause of the
5632 // serialization method in question.
5633 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5634 types.isSubtype(thrownType, syms.errorType) ) {
5635 continue;
5636 } else {
5637 boolean declared = false;
5638 for (Type declaredException : declaredExceptions) {
5639 if (types.isSubtype(thrownType, declaredException)) {
5640 declared = true;
5641 continue;
5642 }
5643 }
5644 if (!declared) {
5645 log.warning(
5646 TreeInfo.diagnosticPositionFor(method, tree),
5647 LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5648 thrownType));
5649 }
5650 }
5651 }
5652 return;
5653 }
5654
5655 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5656 Lint prevLint = lint;
5657 try {
5658 lint = lint.augment((Symbol) symbol);
5659
5660 if (lint.isEnabled(LintCategory.SERIAL)) {
5661 task.accept(symbol, p);
5662 }
5663
5664 return null;
5665 } finally {
5666 lint = prevLint;
5667 }
5668 }
5669
5670 }
5671
5672 void checkRequiresIdentity(JCTree tree, Lint lint) {
|
164 profile = Profile.instance(context);
165 preview = Preview.instance(context);
166
167 boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
168 boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
169 boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
170 boolean enforceMandatoryWarnings = true;
171
172 deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated,
173 enforceMandatoryWarnings, LintCategory.DEPRECATION, "deprecated");
174 removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
175 enforceMandatoryWarnings, LintCategory.REMOVAL);
176 uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
177 enforceMandatoryWarnings, LintCategory.UNCHECKED);
178
179 deferredLintHandler = DeferredLintHandler.instance(context);
180
181 allowModules = Feature.MODULES.allowedInSource(source);
182 allowRecords = Feature.RECORDS.allowedInSource(source);
183 allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
184 allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
185 Feature.VALUE_CLASSES.allowedInSource(source);
186 }
187
188 /** Character for synthetic names
189 */
190 char syntheticNameChar;
191
192 /** A table mapping flat names of all compiled classes for each module in this run
193 * to their symbols; maintained from outside.
194 */
195 private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
196
197 /** A handler for messages about deprecated usage.
198 */
199 private MandatoryWarningHandler deprecationHandler;
200
201 /** A handler for messages about deprecated-for-removal usage.
202 */
203 private MandatoryWarningHandler removalHandler;
204
205 /** A handler for messages about unchecked or unsafe usage.
206 */
207 private MandatoryWarningHandler uncheckedHandler;
208
209 /** A handler for deferred lint warnings.
210 */
211 private DeferredLintHandler deferredLintHandler;
212
213 /** Are modules allowed
214 */
215 private final boolean allowModules;
216
217 /** Are records allowed
218 */
219 private final boolean allowRecords;
220
221 /** Are sealed classes allowed
222 */
223 private final boolean allowSealed;
224
225 /** Are value classes allowed
226 */
227 private final boolean allowValueClasses;
228
229 /** Whether to force suppression of deprecation and preview warnings.
230 * This happens when attributing import statements for JDK 9+.
231 * @see Feature#DEPRECATION_ON_IMPORT
232 */
233 private boolean importSuppression;
234
235 /* *************************************************************************
236 * Errors and Warnings
237 **************************************************************************/
238
239 Lint setLint(Lint newLint) {
240 Lint prev = lint;
241 lint = newLint;
242 return prev;
243 }
244
245 boolean setImportSuppression(boolean newImportSuppression) {
246 boolean prev = importSuppression;
247 importSuppression = newImportSuppression;
248 return prev;
719 /** Check that type is a class or interface type.
720 * @param pos Position to be used for error reporting.
721 * @param t The type to be checked.
722 */
723 Type checkClassType(DiagnosticPosition pos, Type t) {
724 if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
725 return typeTagError(pos,
726 diags.fragment(Fragments.TypeReqClass),
727 asTypeParam(t));
728 } else {
729 return t;
730 }
731 }
732 //where
733 private Object asTypeParam(Type t) {
734 return (t.hasTag(TYPEVAR))
735 ? diags.fragment(Fragments.TypeParameter(t))
736 : t;
737 }
738
739 void checkConstraintsOfValueClass(JCClassDecl tree, ClassSymbol c) {
740 DiagnosticPosition pos = tree.pos();
741 for (Type st : types.closure(c.type)) {
742 if (st == null || st.tsym == null || st.tsym.kind == ERR)
743 continue;
744 if (st.tsym == syms.objectType.tsym || st.tsym == syms.recordType.tsym || st.isInterface())
745 continue;
746 if (!st.tsym.isAbstract()) {
747 if (c != st.tsym) {
748 log.error(pos, Errors.ConcreteSupertypeForValueClass(c, st));
749 }
750 continue;
751 }
752 // dealing with an abstract value or value super class below.
753 for (Symbol s : st.tsym.members().getSymbols(NON_RECURSIVE)) {
754 if (s.kind == MTH) {
755 if ((s.flags() & (SYNCHRONIZED | STATIC)) == SYNCHRONIZED) {
756 log.error(pos, Errors.SuperClassMethodCannotBeSynchronized(s, c, st));
757 }
758 break;
759 }
760 }
761 }
762 }
763
764 /** Check that type is a valid qualifier for a constructor reference expression
765 */
766 Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
767 t = checkClassOrArrayType(pos, t);
768 if (t.hasTag(CLASS)) {
769 if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
770 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
771 t = types.createErrorType(t);
772 } else if ((t.tsym.flags() & ENUM) != 0) {
773 log.error(pos, Errors.EnumCantBeInstantiated);
774 t = types.createErrorType(t);
775 } else {
776 t = checkClassType(pos, t, true);
777 }
778 } else if (t.hasTag(ARRAY)) {
779 if (!types.isReifiable(((ArrayType)t).elemtype)) {
780 log.error(pos, Errors.GenericArrayCreation);
781 t = types.createErrorType(t);
782 }
783 }
801 args = args.tail;
802 }
803 }
804 return t;
805 }
806
807 /** Check that type is a reference type, i.e. a class, interface or array type
808 * or a type variable.
809 * @param pos Position to be used for error reporting.
810 * @param t The type to be checked.
811 */
812 Type checkRefType(DiagnosticPosition pos, Type t) {
813 if (t.isReference())
814 return t;
815 else
816 return typeTagError(pos,
817 diags.fragment(Fragments.TypeReqRef),
818 t);
819 }
820
821 /** Check that type is an identity type, i.e. not a value type.
822 * When not discernible statically, give it the benefit of doubt
823 * and defer to runtime.
824 *
825 * @param pos Position to be used for error reporting.
826 * @param t The type to be checked.
827 */
828 boolean checkIdentityType(DiagnosticPosition pos, Type t) {
829 if (t.hasTag(TYPEVAR)) {
830 t = types.skipTypeVars(t, false);
831 }
832 if (t.isIntersection()) {
833 IntersectionClassType ict = (IntersectionClassType)t;
834 boolean result = true;
835 for (Type component : ict.getExplicitComponents()) {
836 result &= checkIdentityType(pos, component);
837 }
838 return result;
839 }
840 if (t.isPrimitive() || (t.isValueClass() && !t.tsym.isAbstract())) {
841 typeTagError(pos, diags.fragment(Fragments.TypeReqIdentity), t);
842 return false;
843 }
844 return true;
845 }
846
847 /** Check that each type is a reference type, i.e. a class, interface or array type
848 * or a type variable.
849 * @param trees Original trees, used for error reporting.
850 * @param types The types to be checked.
851 */
852 List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
853 List<JCExpression> tl = trees;
854 for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
855 l.head = checkRefType(tl.head.pos(), l.head);
856 tl = tl.tail;
857 }
858 return types;
859 }
860
861 /** Check that type is a null or reference type.
862 * @param pos Position to be used for error reporting.
863 * @param t The type to be checked.
864 */
865 Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
866 if (t.isReference() || t.hasTag(BOT))
1218 * Warning: we can't use flags() here since this method
1219 * is called during class enter, when flags() would cause a premature
1220 * completion.
1221 * @param flags The set of modifiers given in a definition.
1222 * @param sym The defined symbol.
1223 * @param tree The declaration
1224 */
1225 long checkFlags(long flags, Symbol sym, JCTree tree) {
1226 final DiagnosticPosition pos = tree.pos();
1227 long mask;
1228 long implicit = 0;
1229
1230 switch (sym.kind) {
1231 case VAR:
1232 if (TreeInfo.isReceiverParam(tree))
1233 mask = ReceiverParamFlags;
1234 else if (sym.owner.kind != TYP)
1235 mask = LocalVarFlags;
1236 else if ((sym.owner.flags_field & INTERFACE) != 0)
1237 mask = implicit = InterfaceVarFlags;
1238 else {
1239 boolean isInstanceField = (flags & STATIC) == 0;
1240 boolean isInstanceFieldOfValueClass = isInstanceField && sym.owner.type.isValueClass();
1241 boolean isRecordField = isInstanceField && (sym.owner.flags_field & RECORD) != 0;
1242 if (allowValueClasses && (isInstanceFieldOfValueClass || isRecordField)) {
1243 implicit |= FINAL | STRICT;
1244 mask = ValueFieldFlags;
1245 } else {
1246 mask = VarFlags;
1247 }
1248 }
1249 break;
1250 case MTH:
1251 if (sym.name == names.init) {
1252 if ((sym.owner.flags_field & ENUM) != 0) {
1253 // enum constructors cannot be declared public or
1254 // protected and must be implicitly or explicitly
1255 // private
1256 implicit = PRIVATE;
1257 mask = PRIVATE;
1258 } else
1259 mask = ConstructorFlags;
1260 } else if ((sym.owner.flags_field & INTERFACE) != 0) {
1261 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1262 mask = AnnotationTypeElementMask;
1263 implicit = PUBLIC | ABSTRACT;
1264 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1265 mask = InterfaceMethodMask;
1266 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1267 if ((flags & DEFAULT) != 0) {
1268 implicit |= ABSTRACT;
1269 }
1270 } else {
1271 mask = implicit = InterfaceMethodFlags;
1272 }
1273 } else if ((sym.owner.flags_field & RECORD) != 0) {
1274 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1275 RecordMethodFlags & ~SYNCHRONIZED : RecordMethodFlags;
1276 } else {
1277 // value objects do not have an associated monitor/lock
1278 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1279 MethodFlags & ~SYNCHRONIZED : MethodFlags;
1280 }
1281 if ((flags & STRICTFP) != 0) {
1282 warnOnExplicitStrictfp(tree);
1283 }
1284 // Imply STRICTFP if owner has STRICTFP set.
1285 if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1286 ((flags) & Flags.DEFAULT) != 0)
1287 implicit |= sym.owner.flags_field & STRICTFP;
1288 break;
1289 case TYP:
1290 if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1291 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1292 boolean implicitlyStatic = !sym.isAnonymous() &&
1293 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1294 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1295 // local statics are allowed only if records are allowed too
1296 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedStaticLocalClassFlags : ExtendedLocalClassFlags;
1297 implicit = implicitlyStatic ? STATIC : implicit;
1298 } else if (sym.owner.kind == TYP) {
1299 // statics in inner classes are allowed only if records are allowed too
1300 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1301 if (sym.owner.owner.kind == PCK ||
1302 (sym.owner.flags_field & STATIC) != 0) {
1303 mask |= STATIC;
1304 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1305 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1306 }
1307 // Nested interfaces and enums are always STATIC (Spec ???)
1308 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1309 } else {
1310 mask = ExtendedClassFlags;
1311 }
1312 if ((flags & (VALUE_CLASS | SEALED | ABSTRACT)) == (VALUE_CLASS | SEALED) ||
1313 (flags & (VALUE_CLASS | NON_SEALED | ABSTRACT)) == (VALUE_CLASS | NON_SEALED)) {
1314 log.error(pos, Errors.NonAbstractValueClassCantBeSealedOrNonSealed);
1315 }
1316 // Interfaces are always ABSTRACT
1317 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1318
1319 if ((flags & (INTERFACE | VALUE_CLASS)) == 0) {
1320 implicit |= IDENTITY_TYPE;
1321 }
1322
1323 if ((flags & ENUM) != 0) {
1324 // enums can't be declared abstract, final, sealed or non-sealed or value
1325 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | VALUE_CLASS);
1326 implicit |= implicitEnumFinalFlag(tree);
1327 }
1328 if ((flags & RECORD) != 0) {
1329 // records can't be declared abstract
1330 mask &= ~ABSTRACT;
1331 implicit |= FINAL;
1332 }
1333 if ((flags & STRICTFP) != 0) {
1334 warnOnExplicitStrictfp(tree);
1335 }
1336 // Imply STRICTFP if owner has STRICTFP set.
1337 implicit |= sym.owner.flags_field & STRICTFP;
1338
1339 // concrete value classes are implicitly final
1340 if ((flags & (ABSTRACT | INTERFACE | VALUE_CLASS)) == VALUE_CLASS) {
1341 implicit |= FINAL;
1342 }
1343 break;
1344 default:
1345 throw new AssertionError();
1346 }
1347 long illegal = flags & ExtendedStandardFlags & ~mask;
1348 if (illegal != 0) {
1349 if ((illegal & INTERFACE) != 0) {
1350 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1351 mask |= INTERFACE;
1352 }
1353 else {
1354 log.error(pos,
1355 Errors.ModNotAllowedHere(asFlagSet(illegal)));
1356 }
1357 } else if ((sym.kind == TYP ||
1358 // ISSUE: Disallowing abstract&private is no longer appropriate
1359 // in the presence of inner classes. Should it be deleted here?
1360 checkDisjoint(pos, flags,
1361 ABSTRACT,
1362 PRIVATE | STATIC | DEFAULT))
1363 &&
1364 checkDisjoint(pos, flags,
1365 STATIC | PRIVATE,
1366 DEFAULT)
1367 &&
1368 checkDisjoint(pos, flags,
1369 ABSTRACT | INTERFACE,
1370 FINAL | NATIVE | SYNCHRONIZED)
1371 &&
1372 checkDisjoint(pos, flags,
1373 PUBLIC,
1374 PRIVATE | PROTECTED)
1375 &&
1376 checkDisjoint(pos, flags,
1377 PRIVATE,
1378 PUBLIC | PROTECTED)
1379 &&
1380 // we are using `implicit` here as instance fields of value classes are implicitly final
1381 checkDisjoint(pos, flags | implicit,
1382 FINAL,
1383 VOLATILE)
1384 &&
1385 (sym.kind == TYP ||
1386 checkDisjoint(pos, flags,
1387 ABSTRACT | NATIVE,
1388 STRICTFP))
1389 && checkDisjoint(pos, flags,
1390 FINAL,
1391 SEALED | NON_SEALED)
1392 && checkDisjoint(pos, flags,
1393 SEALED,
1394 FINAL | NON_SEALED)
1395 && checkDisjoint(pos, flags,
1396 SEALED,
1397 ANNOTATION)
1398 && checkDisjoint(pos, flags,
1399 VALUE_CLASS,
1400 ANNOTATION)
1401 && checkDisjoint(pos, flags,
1402 VALUE_CLASS,
1403 INTERFACE) ) {
1404 // skip
1405 }
1406 return flags & (mask | ~ExtendedStandardFlags) | implicit;
1407 }
1408
1409 private void warnOnExplicitStrictfp(JCTree tree) {
1410 deferredLintHandler.push(tree);
1411 try {
1412 deferredLintHandler.report(_ -> lint.logIfEnabled(tree.pos(), LintWarnings.Strictfp));
1413 } finally {
1414 deferredLintHandler.pop();
1415 }
1416 }
1417
1418
1419 /** Determine if this enum should be implicitly final.
1420 *
1421 * If the enum has no specialized enum constants, it is final.
1422 *
1423 * If the enum does have specialized enum constants, it is
2195 return true;
2196 }
2197 }
2198 }
2199 return false;
2200 }
2201
2202 /** Check that a given method conforms with any method it overrides.
2203 * @param tree The tree from which positions are extracted
2204 * for errors.
2205 * @param m The overriding method.
2206 */
2207 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2208 ClassSymbol origin = (ClassSymbol)m.owner;
2209 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2210 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2211 log.error(tree.pos(), Errors.EnumNoFinalize);
2212 return;
2213 }
2214 }
2215 if (allowValueClasses && origin.isValueClass() && names.finalize.equals(m.name)) {
2216 if (m.overrides(syms.objectFinalize, origin, types, false)) {
2217 log.warning(tree.pos(), Warnings.ValueFinalize);
2218 }
2219 }
2220 if (allowRecords && origin.isRecord()) {
2221 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2222 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2223 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2224 if (recordComponent.isPresent()) {
2225 return;
2226 }
2227 }
2228
2229 for (Type t = origin.type; t.hasTag(CLASS);
2230 t = types.supertype(t)) {
2231 if (t != origin.type) {
2232 checkOverride(tree, t, origin, m);
2233 }
2234 for (Type t2 : types.interfaces(t)) {
2235 checkOverride(tree, t2, origin, m);
2236 }
2237 }
2238
2239 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
2635 /** Check that all abstract methods implemented by a class are
2636 * mutually compatible.
2637 * @param pos Position to be used for error reporting.
2638 * @param c The class whose interfaces are checked.
2639 */
2640 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2641 List<Type> supertypes = types.interfaces(c);
2642 Type supertype = types.supertype(c);
2643 if (supertype.hasTag(CLASS) &&
2644 (supertype.tsym.flags() & ABSTRACT) != 0)
2645 supertypes = supertypes.prepend(supertype);
2646 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2647 if (!l.head.getTypeArguments().isEmpty() &&
2648 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2649 return;
2650 for (List<Type> m = supertypes; m != l; m = m.tail)
2651 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2652 return;
2653 }
2654 checkCompatibleConcretes(pos, c);
2655
2656 Type identitySuper = null;
2657 for (Type t : types.closure(c)) {
2658 if (t != c) {
2659 if (t.isIdentityClass() && (t.tsym.flags() & VALUE_BASED) == 0)
2660 identitySuper = t;
2661 if (c.isValueClass() && identitySuper != null && identitySuper.tsym != syms.objectType.tsym) { // Object is special
2662 log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, identitySuper));
2663 break;
2664 }
2665 }
2666 }
2667 }
2668
2669 /** Check that all non-override equivalent methods accessible from 'site'
2670 * are mutually compatible (JLS 8.4.8/9.4.1).
2671 *
2672 * @param pos Position to be used for error reporting.
2673 * @param site The class whose methods are checked.
2674 * @param sym The method symbol to be checked.
2675 */
2676 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2677 ClashFilter cf = new ClashFilter(site);
2678 //for each method m1 that is overridden (directly or indirectly)
2679 //by method 'sym' in 'site'...
2680
2681 ArrayList<Symbol> symbolsByName = new ArrayList<>();
2682 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2683 for (Symbol m1 : symbolsByName) {
2684 if (!sym.overrides(m1, site.tsym, types, false)) {
2685 continue;
2686 }
4999 }
5000 } else {
5001 Assert.error("Unknown pattern: " + currentPattern.getTag());
5002 }
5003 return false;
5004 }
5005
5006 /** check if a type is a subtype of Externalizable, if that is available. */
5007 boolean isExternalizable(Type t) {
5008 try {
5009 syms.externalizableType.complete();
5010 } catch (CompletionFailure e) {
5011 return false;
5012 }
5013 return types.isSubtype(t, syms.externalizableType);
5014 }
5015
5016 /**
5017 * Check structure of serialization declarations.
5018 */
5019 public void checkSerialStructure(Env<AttrContext> env, JCClassDecl tree, ClassSymbol c) {
5020 (new SerialTypeVisitor(env)).visit(c, tree);
5021 }
5022
5023 /**
5024 * This visitor will warn if a serialization-related field or
5025 * method is declared in a suspicious or incorrect way. In
5026 * particular, it will warn for cases where the runtime
5027 * serialization mechanism will silently ignore a mis-declared
5028 * entity.
5029 *
5030 * Distinguished serialization-related fields and methods:
5031 *
5032 * Methods:
5033 *
5034 * private void writeObject(ObjectOutputStream stream) throws IOException
5035 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
5036 *
5037 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
5038 * private void readObjectNoData() throws ObjectStreamException
5039 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
5040 *
5041 * Fields:
5042 *
5043 * private static final long serialVersionUID
5044 * private static final ObjectStreamField[] serialPersistentFields
5045 *
5046 * Externalizable: methods defined on the interface
5047 * public void writeExternal(ObjectOutput) throws IOException
5048 * public void readExternal(ObjectInput) throws IOException
5049 */
5050 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
5051 Env<AttrContext> env;
5052 SerialTypeVisitor(Env<AttrContext> env) {
5053 this.lint = Check.this.lint;
5054 this.env = env;
5055 }
5056
5057 private static final Set<String> serialMethodNames =
5058 Set.of("writeObject", "writeReplace",
5059 "readObject", "readObjectNoData",
5060 "readResolve");
5061
5062 private static final Set<String> serialFieldNames =
5063 Set.of("serialVersionUID", "serialPersistentFields");
5064
5065 // Type of serialPersistentFields
5066 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
5067
5068 Lint lint;
5069
5070 @Override
5071 public Void defaultAction(Element e, JCClassDecl p) {
5072 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
5073 }
5074
5094 if (sym.kind == VAR) {
5095 svuidSym = (VarSymbol)sym;
5096 break;
5097 }
5098 }
5099
5100 if (svuidSym == null) {
5101 log.warning(p.pos(), LintWarnings.MissingSVUID(c));
5102 }
5103
5104 // Check for serialPersistentFields to gate checks for
5105 // non-serializable non-transient instance fields
5106 boolean serialPersistentFieldsPresent =
5107 c.members()
5108 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
5109 .iterator()
5110 .hasNext();
5111
5112 // Check declarations of serialization-related methods and
5113 // fields
5114 final boolean[] hasWriteReplace = {false};
5115 for(Symbol el : c.getEnclosedElements()) {
5116 runUnderLint(el, p, (enclosed, tree) -> {
5117 String name = null;
5118 switch(enclosed.getKind()) {
5119 case FIELD -> {
5120 if (!serialPersistentFieldsPresent) {
5121 var flags = enclosed.flags();
5122 if ( ((flags & TRANSIENT) == 0) &&
5123 ((flags & STATIC) == 0)) {
5124 Type varType = enclosed.asType();
5125 if (!canBeSerialized(varType)) {
5126 // Note per JLS arrays are
5127 // serializable even if the
5128 // component type is not.
5129 log.warning(
5130 TreeInfo.diagnosticPositionFor(enclosed, tree),
5131 LintWarnings.NonSerializableInstanceField);
5132 } else if (varType.hasTag(ARRAY)) {
5133 ArrayType arrayType = (ArrayType)varType;
5134 Type elementType = arrayType.elemtype;
5169 // will also pull in default methods from
5170 // superinterfaces. In other words, the runtime checks
5171 // (which long predate default methods on interfaces)
5172 // do not admit the possibility of inheriting methods
5173 // this way, a difference from general inheritance.
5174
5175 // The current implementation just checks the enclosed
5176 // elements and does not directly check the inherited
5177 // methods. If all the types are being checked this is
5178 // less of a concern; however, there are cases that
5179 // could be missed. In particular, readResolve and
5180 // writeReplace could, in principle, by inherited from
5181 // a non-serializable superclass and thus not checked
5182 // even if compiled with a serializable child class.
5183 case METHOD -> {
5184 var method = (MethodSymbol)enclosed;
5185 name = method.getSimpleName().toString();
5186 if (serialMethodNames.contains(name)) {
5187 switch (name) {
5188 case "writeObject" -> checkWriteObject(tree, e, method);
5189 case "writeReplace" -> {hasWriteReplace[0] = true; hasAppropriateWriteReplace(tree, method, true);}
5190 case "readObject" -> checkReadObject(tree,e, method);
5191 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
5192 case "readResolve" -> checkReadResolve(tree, e, method);
5193 default -> throw new AssertionError();
5194 }
5195 }
5196 }
5197 }
5198 });
5199 }
5200 if (!hasWriteReplace[0] &&
5201 (c.isValueClass() || hasAbstractValueSuperClass(c, Set.of(syms.numberType.tsym))) &&
5202 !c.isAbstract() && !c.isRecord() &&
5203 types.unboxedType(c.type) == Type.noType) {
5204 // we need to check if the class is inheriting an appropriate writeReplace method
5205 MethodSymbol ms = null;
5206 Log.DiagnosticHandler discardHandler = log.new DiscardDiagnosticHandler();
5207 try {
5208 ms = rs.resolveInternalMethod(env.tree, env, c.type, names.writeReplace, List.nil(), List.nil());
5209 } catch (FatalError fe) {
5210 // ignore no method was found
5211 } finally {
5212 log.popDiagnosticHandler(discardHandler);
5213 }
5214 if (ms == null || !hasAppropriateWriteReplace(p, ms, false)) {
5215 log.warning(p.pos(),
5216 c.isValueClass() ? LintWarnings.SerializableValueClassWithoutWriteReplace1 :
5217 LintWarnings.SerializableValueClassWithoutWriteReplace2);
5218 }
5219 }
5220 return null;
5221 }
5222
5223 boolean canBeSerialized(Type type) {
5224 return type.isPrimitive() || rs.isSerializable(type);
5225 }
5226
5227 private boolean hasAbstractValueSuperClass(Symbol c, Set<Symbol> excluding) {
5228 while (c.getKind() == ElementKind.CLASS) {
5229 Type sup = ((ClassSymbol)c).getSuperclass();
5230 if (!sup.hasTag(CLASS) || sup.isErroneous() ||
5231 sup.tsym == syms.objectType.tsym) {
5232 return false;
5233 }
5234 // if it is a value super class it has to be abstract
5235 if (sup.isValueClass() && !excluding.contains(sup.tsym)) {
5236 return true;
5237 }
5238 c = sup.tsym;
5239 }
5240 return false;
5241 }
5242
5243 /**
5244 * Check that Externalizable class needs a public no-arg
5245 * constructor.
5246 *
5247 * Check that a Serializable class has access to the no-arg
5248 * constructor of its first nonserializable superclass.
5249 */
5250 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5251 if (isExternalizable(c.type)) {
5252 for(var sym : c.getEnclosedElements()) {
5253 if (sym.isConstructor() &&
5254 ((sym.flags() & PUBLIC) == PUBLIC)) {
5255 if (((MethodSymbol)sym).getParameters().isEmpty()) {
5256 return;
5257 }
5258 }
5259 }
5260 log.warning(tree.pos(),
5261 LintWarnings.ExternalizableMissingPublicNoArgCtor);
5262 } else {
5346 // Warn if serialPersistentFields is initialized to a
5347 // literal null.
5348 JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5349 if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5350 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5351 JCExpression initExpr = variableDef.init;
5352 if (initExpr != null && TreeInfo.isNull(initExpr)) {
5353 log.warning(initExpr.pos(),
5354 LintWarnings.SPFNullInit);
5355 }
5356 }
5357 }
5358
5359 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5360 // The "synchronized" modifier is seen in the wild on
5361 // readObject and writeObject methods and is generally
5362 // innocuous.
5363
5364 // private void writeObject(ObjectOutputStream stream) throws IOException
5365 checkPrivateNonStaticMethod(tree, method);
5366 isExpectedReturnType(tree, method, syms.voidType, true);
5367 checkOneArg(tree, e, method, syms.objectOutputStreamType);
5368 hasExpectedExceptions(tree, method, true, syms.ioExceptionType);
5369 checkExternalizable(tree, e, method);
5370 }
5371
5372 private boolean hasAppropriateWriteReplace(JCClassDecl tree, MethodSymbol method, boolean warn) {
5373 // ANY-ACCESS-MODIFIER Object writeReplace() throws
5374 // ObjectStreamException
5375
5376 // Excluding abstract, could have a more complicated
5377 // rule based on abstract-ness of the class
5378 return isConcreteInstanceMethod(tree, method, warn) &&
5379 isExpectedReturnType(tree, method, syms.objectType, warn) &&
5380 hasNoArgs(tree, method, warn) &&
5381 hasExpectedExceptions(tree, method, warn, syms.objectStreamExceptionType);
5382 }
5383
5384 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5385 // The "synchronized" modifier is seen in the wild on
5386 // readObject and writeObject methods and is generally
5387 // innocuous.
5388
5389 // private void readObject(ObjectInputStream stream)
5390 // throws IOException, ClassNotFoundException
5391 checkPrivateNonStaticMethod(tree, method);
5392 isExpectedReturnType(tree, method, syms.voidType, true);
5393 checkOneArg(tree, e, method, syms.objectInputStreamType);
5394 hasExpectedExceptions(tree, method, true, syms.ioExceptionType, syms.classNotFoundExceptionType);
5395 checkExternalizable(tree, e, method);
5396 }
5397
5398 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5399 // private void readObjectNoData() throws ObjectStreamException
5400 checkPrivateNonStaticMethod(tree, method);
5401 isExpectedReturnType(tree, method, syms.voidType, true);
5402 hasNoArgs(tree, method, true);
5403 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5404 checkExternalizable(tree, e, method);
5405 }
5406
5407 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5408 // ANY-ACCESS-MODIFIER Object readResolve()
5409 // throws ObjectStreamException
5410
5411 // Excluding abstract, could have a more complicated
5412 // rule based on abstract-ness of the class
5413 isConcreteInstanceMethod(tree, method, true);
5414 isExpectedReturnType(tree, method, syms.objectType, true);
5415 hasNoArgs(tree, method, true);
5416 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5417 }
5418
5419 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5420 //public void writeExternal(ObjectOutput) throws IOException
5421 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5422 }
5423
5424 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5425 // public void readExternal(ObjectInput) throws IOException
5426 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5427 }
5428
5429 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5430 boolean isExtern) {
5431 if (isExtern && isExternMethod(tree, e, method, argType)) {
5432 log.warning(
5433 TreeInfo.diagnosticPositionFor(method, tree),
5434 LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5435 }
5436 }
5646 case FIELD -> {
5647 var field = (VarSymbol)enclosed;
5648 switch(name) {
5649 case "serialPersistentFields" -> {
5650 log.warning(
5651 TreeInfo.diagnosticPositionFor(field, tree),
5652 LintWarnings.IneffectualSerialFieldRecord);
5653 }
5654
5655 case "serialVersionUID" -> {
5656 // Could generate additional warning that
5657 // svuid value is not checked to match for
5658 // records.
5659 checkSerialVersionUID(tree, e, field);
5660 }}
5661 }
5662
5663 case METHOD -> {
5664 var method = (MethodSymbol)enclosed;
5665 switch(name) {
5666 case "writeReplace" -> hasAppropriateWriteReplace(tree, method, true);
5667 case "readResolve" -> checkReadResolve(tree, e, method);
5668
5669 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5670 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern);
5671
5672 default -> {
5673 if (serialMethodNames.contains(name)) {
5674 log.warning(
5675 TreeInfo.diagnosticPositionFor(method, tree),
5676 LintWarnings.IneffectualSerialMethodRecord(name));
5677 }
5678 }}
5679 }}});
5680 }
5681 return null;
5682 }
5683
5684 boolean isConcreteInstanceMethod(JCClassDecl tree,
5685 MethodSymbol method,
5686 boolean warn) {
5687 if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5688 if (warn) {
5689 log.warning(
5690 TreeInfo.diagnosticPositionFor(method, tree),
5691 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5692 }
5693 return false;
5694 }
5695 return true;
5696 }
5697
5698 private boolean isExpectedReturnType(JCClassDecl tree,
5699 MethodSymbol method,
5700 Type expectedReturnType,
5701 boolean warn) {
5702 // Note: there may be complications checking writeReplace
5703 // and readResolve since they return Object and could, in
5704 // principle, have covariant overrides and any synthetic
5705 // bridge method would not be represented here for
5706 // checking.
5707 Type rtype = method.getReturnType();
5708 if (!types.isSameType(expectedReturnType, rtype)) {
5709 if (warn) {
5710 log.warning(
5711 TreeInfo.diagnosticPositionFor(method, tree),
5712 LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5713 rtype, expectedReturnType));
5714 }
5715 return false;
5716 }
5717 return true;
5718 }
5719
5720 private void checkOneArg(JCClassDecl tree,
5721 Element enclosing,
5722 MethodSymbol method,
5723 Type expectedType) {
5724 String name = method.getSimpleName().toString();
5725
5726 var parameters= method.getParameters();
5727
5728 if (parameters.size() != 1) {
5729 log.warning(
5730 TreeInfo.diagnosticPositionFor(method, tree),
5731 LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5732 return;
5733 }
5734
5735 Type parameterType = parameters.get(0).asType();
5736 if (!types.isSameType(parameterType, expectedType)) {
5737 log.warning(
5738 TreeInfo.diagnosticPositionFor(method, tree),
5739 LintWarnings.SerialMethodParameterType(method.getSimpleName(),
5740 expectedType,
5741 parameterType));
5742 }
5743 }
5744
5745 private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5746 Element enclosing,
5747 MethodSymbol method,
5748 Type expectedType) {
5749 var parameters = method.getParameters();
5750 return (parameters.size() == 1) &&
5751 types.isSameType(parameters.get(0).asType(), expectedType);
5752 }
5753
5754
5755 boolean hasNoArgs(JCClassDecl tree, MethodSymbol method, boolean warn) {
5756 var parameters = method.getParameters();
5757 if (!parameters.isEmpty()) {
5758 if (warn) {
5759 log.warning(
5760 TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5761 LintWarnings.SerialMethodNoArgs(method.getSimpleName()));
5762 }
5763 return false;
5764 }
5765 return true;
5766 }
5767
5768 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5769 // If the enclosing class is externalizable, warn for the method
5770 if (isExternalizable((Type)enclosing.asType())) {
5771 log.warning(
5772 TreeInfo.diagnosticPositionFor(method, tree),
5773 LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5774 }
5775 return;
5776 }
5777
5778 private boolean hasExpectedExceptions(JCClassDecl tree,
5779 MethodSymbol method,
5780 boolean warn,
5781 Type... declaredExceptions) {
5782 for (Type thrownType: method.getThrownTypes()) {
5783 // For each exception in the throws clause of the
5784 // method, if not an Error and not a RuntimeException,
5785 // check if the exception is a subtype of a declared
5786 // exception from the throws clause of the
5787 // serialization method in question.
5788 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5789 types.isSubtype(thrownType, syms.errorType) ) {
5790 continue;
5791 } else {
5792 boolean declared = false;
5793 for (Type declaredException : declaredExceptions) {
5794 if (types.isSubtype(thrownType, declaredException)) {
5795 declared = true;
5796 continue;
5797 }
5798 }
5799 if (!declared) {
5800 if (warn) {
5801 log.warning(
5802 TreeInfo.diagnosticPositionFor(method, tree),
5803 LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5804 thrownType));
5805 }
5806 return false;
5807 }
5808 }
5809 }
5810 return true;
5811 }
5812
5813 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5814 Lint prevLint = lint;
5815 try {
5816 lint = lint.augment((Symbol) symbol);
5817
5818 if (lint.isEnabled(LintCategory.SERIAL)) {
5819 task.accept(symbol, p);
5820 }
5821
5822 return null;
5823 } finally {
5824 lint = prevLint;
5825 }
5826 }
5827
5828 }
5829
5830 void checkRequiresIdentity(JCTree tree, Lint lint) {
|