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