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 isInstanceFieldOfValueClass = sym.owner.type.isValueClass() && (flags & STATIC) == 0;
1238 mask = !isInstanceFieldOfValueClass ? VarFlags : ValueFieldFlags;
1239 if (isInstanceFieldOfValueClass) {
1240 implicit |= FINAL | STRICT;
1241 }
1242 }
1243 break;
1244 case MTH:
1245 if (sym.name == names.init) {
1246 if ((sym.owner.flags_field & ENUM) != 0) {
1247 // enum constructors cannot be declared public or
1248 // protected and must be implicitly or explicitly
1249 // private
1250 implicit = PRIVATE;
1251 mask = PRIVATE;
1252 } else
1253 mask = ConstructorFlags;
1254 } else if ((sym.owner.flags_field & INTERFACE) != 0) {
1255 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1256 mask = AnnotationTypeElementMask;
1257 implicit = PUBLIC | ABSTRACT;
1258 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1259 mask = InterfaceMethodMask;
1260 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1261 if ((flags & DEFAULT) != 0) {
1262 implicit |= ABSTRACT;
1263 }
1264 } else {
1265 mask = implicit = InterfaceMethodFlags;
1266 }
1267 } else if ((sym.owner.flags_field & RECORD) != 0) {
1268 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1269 RecordMethodFlags & ~SYNCHRONIZED : RecordMethodFlags;
1270 } else {
1271 // value objects do not have an associated monitor/lock
1272 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1273 MethodFlags & ~SYNCHRONIZED : MethodFlags;
1274 }
1275 if ((flags & STRICTFP) != 0) {
1276 warnOnExplicitStrictfp(tree);
1277 }
1278 // Imply STRICTFP if owner has STRICTFP set.
1279 if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1280 ((flags) & Flags.DEFAULT) != 0)
1281 implicit |= sym.owner.flags_field & STRICTFP;
1282 break;
1283 case TYP:
1284 if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1285 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1286 boolean implicitlyStatic = !sym.isAnonymous() &&
1287 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1288 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1289 // local statics are allowed only if records are allowed too
1290 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedStaticLocalClassFlags : ExtendedLocalClassFlags;
1291 implicit = implicitlyStatic ? STATIC : implicit;
1292 } else if (sym.owner.kind == TYP) {
1293 // statics in inner classes are allowed only if records are allowed too
1294 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1295 if (sym.owner.owner.kind == PCK ||
1296 (sym.owner.flags_field & STATIC) != 0) {
1297 mask |= STATIC;
1298 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1299 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1300 }
1301 // Nested interfaces and enums are always STATIC (Spec ???)
1302 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1303 } else {
1304 mask = ExtendedClassFlags;
1305 }
1306 if ((flags & (VALUE_CLASS | SEALED | ABSTRACT)) == (VALUE_CLASS | SEALED) ||
1307 (flags & (VALUE_CLASS | NON_SEALED | ABSTRACT)) == (VALUE_CLASS | NON_SEALED)) {
1308 log.error(pos, Errors.NonAbstractValueClassCantBeSealedOrNonSealed);
1309 }
1310 // Interfaces are always ABSTRACT
1311 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1312
1313 if ((flags & (INTERFACE | VALUE_CLASS)) == 0) {
1314 implicit |= IDENTITY_TYPE;
1315 }
1316
1317 if ((flags & ENUM) != 0) {
1318 // enums can't be declared abstract, final, sealed or non-sealed or value
1319 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | VALUE_CLASS);
1320 implicit |= implicitEnumFinalFlag(tree);
1321 }
1322 if ((flags & RECORD) != 0) {
1323 // records can't be declared abstract
1324 mask &= ~ABSTRACT;
1325 implicit |= FINAL;
1326 }
1327 if ((flags & STRICTFP) != 0) {
1328 warnOnExplicitStrictfp(tree);
1329 }
1330 // Imply STRICTFP if owner has STRICTFP set.
1331 implicit |= sym.owner.flags_field & STRICTFP;
1332
1333 // concrete value classes are implicitly final
1334 if ((flags & (ABSTRACT | INTERFACE | VALUE_CLASS)) == VALUE_CLASS) {
1335 implicit |= FINAL;
1336 }
1337 break;
1338 default:
1339 throw new AssertionError();
1340 }
1341 long illegal = flags & ExtendedStandardFlags & ~mask;
1342 if (illegal != 0) {
1343 if ((illegal & INTERFACE) != 0) {
1344 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1345 mask |= INTERFACE;
1346 }
1347 else {
1348 log.error(pos,
1349 Errors.ModNotAllowedHere(asFlagSet(illegal)));
1350 }
1351 } else if ((sym.kind == TYP ||
1352 // ISSUE: Disallowing abstract&private is no longer appropriate
1353 // in the presence of inner classes. Should it be deleted here?
1354 checkDisjoint(pos, flags,
1355 ABSTRACT,
1356 PRIVATE | STATIC | DEFAULT))
1357 &&
1358 checkDisjoint(pos, flags,
1359 STATIC | PRIVATE,
1360 DEFAULT)
1361 &&
1362 checkDisjoint(pos, flags,
1363 ABSTRACT | INTERFACE,
1364 FINAL | NATIVE | SYNCHRONIZED)
1365 &&
1366 checkDisjoint(pos, flags,
1367 PUBLIC,
1368 PRIVATE | PROTECTED)
1369 &&
1370 checkDisjoint(pos, flags,
1371 PRIVATE,
1372 PUBLIC | PROTECTED)
1373 &&
1374 // we are using `implicit` here as instance fields of value classes are implicitly final
1375 checkDisjoint(pos, flags | implicit,
1376 FINAL,
1377 VOLATILE)
1378 &&
1379 (sym.kind == TYP ||
1380 checkDisjoint(pos, flags,
1381 ABSTRACT | NATIVE,
1382 STRICTFP))
1383 && checkDisjoint(pos, flags,
1384 FINAL,
1385 SEALED | NON_SEALED)
1386 && checkDisjoint(pos, flags,
1387 SEALED,
1388 FINAL | NON_SEALED)
1389 && checkDisjoint(pos, flags,
1390 SEALED,
1391 ANNOTATION)
1392 && checkDisjoint(pos, flags,
1393 VALUE_CLASS,
1394 ANNOTATION)
1395 && checkDisjoint(pos, flags,
1396 VALUE_CLASS,
1397 INTERFACE) ) {
1398 // skip
1399 }
1400 return flags & (mask | ~ExtendedStandardFlags) | implicit;
1401 }
1402
1403 private void warnOnExplicitStrictfp(JCTree tree) {
1404 deferredLintHandler.push(tree);
1405 try {
1406 deferredLintHandler.report(_ -> lint.logIfEnabled(tree.pos(), LintWarnings.Strictfp));
1407 } finally {
1408 deferredLintHandler.pop();
1409 }
1410 }
1411
1412
1413 /** Determine if this enum should be implicitly final.
1414 *
1415 * If the enum has no specialized enum constants, it is final.
1416 *
1417 * If the enum does have specialized enum constants, it is
2189 return true;
2190 }
2191 }
2192 }
2193 return false;
2194 }
2195
2196 /** Check that a given method conforms with any method it overrides.
2197 * @param tree The tree from which positions are extracted
2198 * for errors.
2199 * @param m The overriding method.
2200 */
2201 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2202 ClassSymbol origin = (ClassSymbol)m.owner;
2203 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2204 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2205 log.error(tree.pos(), Errors.EnumNoFinalize);
2206 return;
2207 }
2208 }
2209 if (allowValueClasses && origin.isValueClass() && names.finalize.equals(m.name)) {
2210 if (m.overrides(syms.objectFinalize, origin, types, false)) {
2211 log.warning(tree.pos(), Warnings.ValueFinalize);
2212 }
2213 }
2214 if (allowRecords && origin.isRecord()) {
2215 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2216 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2217 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2218 if (recordComponent.isPresent()) {
2219 return;
2220 }
2221 }
2222
2223 for (Type t = origin.type; t.hasTag(CLASS);
2224 t = types.supertype(t)) {
2225 if (t != origin.type) {
2226 checkOverride(tree, t, origin, m);
2227 }
2228 for (Type t2 : types.interfaces(t)) {
2229 checkOverride(tree, t2, origin, m);
2230 }
2231 }
2232
2233 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
2629 /** Check that all abstract methods implemented by a class are
2630 * mutually compatible.
2631 * @param pos Position to be used for error reporting.
2632 * @param c The class whose interfaces are checked.
2633 */
2634 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2635 List<Type> supertypes = types.interfaces(c);
2636 Type supertype = types.supertype(c);
2637 if (supertype.hasTag(CLASS) &&
2638 (supertype.tsym.flags() & ABSTRACT) != 0)
2639 supertypes = supertypes.prepend(supertype);
2640 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2641 if (!l.head.getTypeArguments().isEmpty() &&
2642 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2643 return;
2644 for (List<Type> m = supertypes; m != l; m = m.tail)
2645 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2646 return;
2647 }
2648 checkCompatibleConcretes(pos, c);
2649
2650 Type identitySuper = null;
2651 for (Type t : types.closure(c)) {
2652 if (t != c) {
2653 if (t.isIdentityClass() && (t.tsym.flags() & VALUE_BASED) == 0)
2654 identitySuper = t;
2655 if (c.isValueClass() && identitySuper != null && identitySuper.tsym != syms.objectType.tsym) { // Object is special
2656 log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, identitySuper));
2657 break;
2658 }
2659 }
2660 }
2661 }
2662
2663 /** Check that all non-override equivalent methods accessible from 'site'
2664 * are mutually compatible (JLS 8.4.8/9.4.1).
2665 *
2666 * @param pos Position to be used for error reporting.
2667 * @param site The class whose methods are checked.
2668 * @param sym The method symbol to be checked.
2669 */
2670 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2671 ClashFilter cf = new ClashFilter(site);
2672 //for each method m1 that is overridden (directly or indirectly)
2673 //by method 'sym' in 'site'...
2674
2675 ArrayList<Symbol> symbolsByName = new ArrayList<>();
2676 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2677 for (Symbol m1 : symbolsByName) {
2678 if (!sym.overrides(m1, site.tsym, types, false)) {
2679 continue;
2680 }
4993 }
4994 } else {
4995 Assert.error("Unknown pattern: " + currentPattern.getTag());
4996 }
4997 return false;
4998 }
4999
5000 /** check if a type is a subtype of Externalizable, if that is available. */
5001 boolean isExternalizable(Type t) {
5002 try {
5003 syms.externalizableType.complete();
5004 } catch (CompletionFailure e) {
5005 return false;
5006 }
5007 return types.isSubtype(t, syms.externalizableType);
5008 }
5009
5010 /**
5011 * Check structure of serialization declarations.
5012 */
5013 public void checkSerialStructure(Env<AttrContext> env, JCClassDecl tree, ClassSymbol c) {
5014 (new SerialTypeVisitor(env)).visit(c, tree);
5015 }
5016
5017 /**
5018 * This visitor will warn if a serialization-related field or
5019 * method is declared in a suspicious or incorrect way. In
5020 * particular, it will warn for cases where the runtime
5021 * serialization mechanism will silently ignore a mis-declared
5022 * entity.
5023 *
5024 * Distinguished serialization-related fields and methods:
5025 *
5026 * Methods:
5027 *
5028 * private void writeObject(ObjectOutputStream stream) throws IOException
5029 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
5030 *
5031 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
5032 * private void readObjectNoData() throws ObjectStreamException
5033 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
5034 *
5035 * Fields:
5036 *
5037 * private static final long serialVersionUID
5038 * private static final ObjectStreamField[] serialPersistentFields
5039 *
5040 * Externalizable: methods defined on the interface
5041 * public void writeExternal(ObjectOutput) throws IOException
5042 * public void readExternal(ObjectInput) throws IOException
5043 */
5044 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
5045 Env<AttrContext> env;
5046 SerialTypeVisitor(Env<AttrContext> env) {
5047 this.lint = Check.this.lint;
5048 this.env = env;
5049 }
5050
5051 private static final Set<String> serialMethodNames =
5052 Set.of("writeObject", "writeReplace",
5053 "readObject", "readObjectNoData",
5054 "readResolve");
5055
5056 private static final Set<String> serialFieldNames =
5057 Set.of("serialVersionUID", "serialPersistentFields");
5058
5059 // Type of serialPersistentFields
5060 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
5061
5062 Lint lint;
5063
5064 @Override
5065 public Void defaultAction(Element e, JCClassDecl p) {
5066 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
5067 }
5068
5088 if (sym.kind == VAR) {
5089 svuidSym = (VarSymbol)sym;
5090 break;
5091 }
5092 }
5093
5094 if (svuidSym == null) {
5095 log.warning(p.pos(), LintWarnings.MissingSVUID(c));
5096 }
5097
5098 // Check for serialPersistentFields to gate checks for
5099 // non-serializable non-transient instance fields
5100 boolean serialPersistentFieldsPresent =
5101 c.members()
5102 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
5103 .iterator()
5104 .hasNext();
5105
5106 // Check declarations of serialization-related methods and
5107 // fields
5108 final boolean[] hasWriteReplace = {false};
5109 for(Symbol el : c.getEnclosedElements()) {
5110 runUnderLint(el, p, (enclosed, tree) -> {
5111 String name = null;
5112 switch(enclosed.getKind()) {
5113 case FIELD -> {
5114 if (!serialPersistentFieldsPresent) {
5115 var flags = enclosed.flags();
5116 if ( ((flags & TRANSIENT) == 0) &&
5117 ((flags & STATIC) == 0)) {
5118 Type varType = enclosed.asType();
5119 if (!canBeSerialized(varType)) {
5120 // Note per JLS arrays are
5121 // serializable even if the
5122 // component type is not.
5123 log.warning(
5124 TreeInfo.diagnosticPositionFor(enclosed, tree),
5125 LintWarnings.NonSerializableInstanceField);
5126 } else if (varType.hasTag(ARRAY)) {
5127 ArrayType arrayType = (ArrayType)varType;
5128 Type elementType = arrayType.elemtype;
5163 // will also pull in default methods from
5164 // superinterfaces. In other words, the runtime checks
5165 // (which long predate default methods on interfaces)
5166 // do not admit the possibility of inheriting methods
5167 // this way, a difference from general inheritance.
5168
5169 // The current implementation just checks the enclosed
5170 // elements and does not directly check the inherited
5171 // methods. If all the types are being checked this is
5172 // less of a concern; however, there are cases that
5173 // could be missed. In particular, readResolve and
5174 // writeReplace could, in principle, by inherited from
5175 // a non-serializable superclass and thus not checked
5176 // even if compiled with a serializable child class.
5177 case METHOD -> {
5178 var method = (MethodSymbol)enclosed;
5179 name = method.getSimpleName().toString();
5180 if (serialMethodNames.contains(name)) {
5181 switch (name) {
5182 case "writeObject" -> checkWriteObject(tree, e, method);
5183 case "writeReplace" -> {hasWriteReplace[0] = true; hasAppropriateWriteReplace(tree, method, true);}
5184 case "readObject" -> checkReadObject(tree,e, method);
5185 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
5186 case "readResolve" -> checkReadResolve(tree, e, method);
5187 default -> throw new AssertionError();
5188 }
5189 }
5190 }
5191 }
5192 });
5193 }
5194 if (!hasWriteReplace[0] &&
5195 (c.isValueClass() || hasAbstractValueSuperClass(c, Set.of(syms.numberType.tsym))) &&
5196 !c.isAbstract() && !c.isRecord() &&
5197 types.unboxedType(c.type) == Type.noType) {
5198 // we need to check if the class is inheriting an appropriate writeReplace method
5199 MethodSymbol ms = null;
5200 Log.DiagnosticHandler discardHandler = log.new DiscardDiagnosticHandler();
5201 try {
5202 ms = rs.resolveInternalMethod(env.tree, env, c.type, names.writeReplace, List.nil(), List.nil());
5203 } catch (FatalError fe) {
5204 // ignore no method was found
5205 } finally {
5206 log.popDiagnosticHandler(discardHandler);
5207 }
5208 if (ms == null || !hasAppropriateWriteReplace(p, ms, false)) {
5209 log.warning(p.pos(),
5210 c.isValueClass() ? LintWarnings.SerializableValueClassWithoutWriteReplace1 :
5211 LintWarnings.SerializableValueClassWithoutWriteReplace2);
5212 }
5213 }
5214 return null;
5215 }
5216
5217 boolean canBeSerialized(Type type) {
5218 return type.isPrimitive() || rs.isSerializable(type);
5219 }
5220
5221 private boolean hasAbstractValueSuperClass(Symbol c, Set<Symbol> excluding) {
5222 while (c.getKind() == ElementKind.CLASS) {
5223 Type sup = ((ClassSymbol)c).getSuperclass();
5224 if (!sup.hasTag(CLASS) || sup.isErroneous() ||
5225 sup.tsym == syms.objectType.tsym) {
5226 return false;
5227 }
5228 // if it is a value super class it has to be abstract
5229 if (sup.isValueClass() && !excluding.contains(sup.tsym)) {
5230 return true;
5231 }
5232 c = sup.tsym;
5233 }
5234 return false;
5235 }
5236
5237 /**
5238 * Check that Externalizable class needs a public no-arg
5239 * constructor.
5240 *
5241 * Check that a Serializable class has access to the no-arg
5242 * constructor of its first nonserializable superclass.
5243 */
5244 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5245 if (isExternalizable(c.type)) {
5246 for(var sym : c.getEnclosedElements()) {
5247 if (sym.isConstructor() &&
5248 ((sym.flags() & PUBLIC) == PUBLIC)) {
5249 if (((MethodSymbol)sym).getParameters().isEmpty()) {
5250 return;
5251 }
5252 }
5253 }
5254 log.warning(tree.pos(),
5255 LintWarnings.ExternalizableMissingPublicNoArgCtor);
5256 } else {
5340 // Warn if serialPersistentFields is initialized to a
5341 // literal null.
5342 JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5343 if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5344 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5345 JCExpression initExpr = variableDef.init;
5346 if (initExpr != null && TreeInfo.isNull(initExpr)) {
5347 log.warning(initExpr.pos(),
5348 LintWarnings.SPFNullInit);
5349 }
5350 }
5351 }
5352
5353 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5354 // The "synchronized" modifier is seen in the wild on
5355 // readObject and writeObject methods and is generally
5356 // innocuous.
5357
5358 // private void writeObject(ObjectOutputStream stream) throws IOException
5359 checkPrivateNonStaticMethod(tree, method);
5360 isExpectedReturnType(tree, method, syms.voidType, true);
5361 checkOneArg(tree, e, method, syms.objectOutputStreamType);
5362 hasExpectedExceptions(tree, method, true, syms.ioExceptionType);
5363 checkExternalizable(tree, e, method);
5364 }
5365
5366 private boolean hasAppropriateWriteReplace(JCClassDecl tree, MethodSymbol method, boolean warn) {
5367 // ANY-ACCESS-MODIFIER Object writeReplace() throws
5368 // ObjectStreamException
5369
5370 // Excluding abstract, could have a more complicated
5371 // rule based on abstract-ness of the class
5372 return isConcreteInstanceMethod(tree, method, warn) &&
5373 isExpectedReturnType(tree, method, syms.objectType, warn) &&
5374 hasNoArgs(tree, method, warn) &&
5375 hasExpectedExceptions(tree, method, warn, syms.objectStreamExceptionType);
5376 }
5377
5378 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5379 // The "synchronized" modifier is seen in the wild on
5380 // readObject and writeObject methods and is generally
5381 // innocuous.
5382
5383 // private void readObject(ObjectInputStream stream)
5384 // throws IOException, ClassNotFoundException
5385 checkPrivateNonStaticMethod(tree, method);
5386 isExpectedReturnType(tree, method, syms.voidType, true);
5387 checkOneArg(tree, e, method, syms.objectInputStreamType);
5388 hasExpectedExceptions(tree, method, true, syms.ioExceptionType, syms.classNotFoundExceptionType);
5389 checkExternalizable(tree, e, method);
5390 }
5391
5392 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5393 // private void readObjectNoData() throws ObjectStreamException
5394 checkPrivateNonStaticMethod(tree, method);
5395 isExpectedReturnType(tree, method, syms.voidType, true);
5396 hasNoArgs(tree, method, true);
5397 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5398 checkExternalizable(tree, e, method);
5399 }
5400
5401 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5402 // ANY-ACCESS-MODIFIER Object readResolve()
5403 // throws ObjectStreamException
5404
5405 // Excluding abstract, could have a more complicated
5406 // rule based on abstract-ness of the class
5407 isConcreteInstanceMethod(tree, method, true);
5408 isExpectedReturnType(tree, method, syms.objectType, true);
5409 hasNoArgs(tree, method, true);
5410 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5411 }
5412
5413 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5414 //public void writeExternal(ObjectOutput) throws IOException
5415 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5416 }
5417
5418 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5419 // public void readExternal(ObjectInput) throws IOException
5420 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5421 }
5422
5423 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5424 boolean isExtern) {
5425 if (isExtern && isExternMethod(tree, e, method, argType)) {
5426 log.warning(
5427 TreeInfo.diagnosticPositionFor(method, tree),
5428 LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5429 }
5430 }
5640 case FIELD -> {
5641 var field = (VarSymbol)enclosed;
5642 switch(name) {
5643 case "serialPersistentFields" -> {
5644 log.warning(
5645 TreeInfo.diagnosticPositionFor(field, tree),
5646 LintWarnings.IneffectualSerialFieldRecord);
5647 }
5648
5649 case "serialVersionUID" -> {
5650 // Could generate additional warning that
5651 // svuid value is not checked to match for
5652 // records.
5653 checkSerialVersionUID(tree, e, field);
5654 }}
5655 }
5656
5657 case METHOD -> {
5658 var method = (MethodSymbol)enclosed;
5659 switch(name) {
5660 case "writeReplace" -> hasAppropriateWriteReplace(tree, method, true);
5661 case "readResolve" -> checkReadResolve(tree, e, method);
5662
5663 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5664 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern);
5665
5666 default -> {
5667 if (serialMethodNames.contains(name)) {
5668 log.warning(
5669 TreeInfo.diagnosticPositionFor(method, tree),
5670 LintWarnings.IneffectualSerialMethodRecord(name));
5671 }
5672 }}
5673 }}});
5674 }
5675 return null;
5676 }
5677
5678 boolean isConcreteInstanceMethod(JCClassDecl tree,
5679 MethodSymbol method,
5680 boolean warn) {
5681 if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5682 if (warn) {
5683 log.warning(
5684 TreeInfo.diagnosticPositionFor(method, tree),
5685 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5686 }
5687 return false;
5688 }
5689 return true;
5690 }
5691
5692 private boolean isExpectedReturnType(JCClassDecl tree,
5693 MethodSymbol method,
5694 Type expectedReturnType,
5695 boolean warn) {
5696 // Note: there may be complications checking writeReplace
5697 // and readResolve since they return Object and could, in
5698 // principle, have covariant overrides and any synthetic
5699 // bridge method would not be represented here for
5700 // checking.
5701 Type rtype = method.getReturnType();
5702 if (!types.isSameType(expectedReturnType, rtype)) {
5703 if (warn) {
5704 log.warning(
5705 TreeInfo.diagnosticPositionFor(method, tree),
5706 LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5707 rtype, expectedReturnType));
5708 }
5709 return false;
5710 }
5711 return true;
5712 }
5713
5714 private void checkOneArg(JCClassDecl tree,
5715 Element enclosing,
5716 MethodSymbol method,
5717 Type expectedType) {
5718 String name = method.getSimpleName().toString();
5719
5720 var parameters= method.getParameters();
5721
5722 if (parameters.size() != 1) {
5723 log.warning(
5724 TreeInfo.diagnosticPositionFor(method, tree),
5725 LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5726 return;
5727 }
5728
5729 Type parameterType = parameters.get(0).asType();
5730 if (!types.isSameType(parameterType, expectedType)) {
5731 log.warning(
5732 TreeInfo.diagnosticPositionFor(method, tree),
5733 LintWarnings.SerialMethodParameterType(method.getSimpleName(),
5734 expectedType,
5735 parameterType));
5736 }
5737 }
5738
5739 private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5740 Element enclosing,
5741 MethodSymbol method,
5742 Type expectedType) {
5743 var parameters = method.getParameters();
5744 return (parameters.size() == 1) &&
5745 types.isSameType(parameters.get(0).asType(), expectedType);
5746 }
5747
5748
5749 boolean hasNoArgs(JCClassDecl tree, MethodSymbol method, boolean warn) {
5750 var parameters = method.getParameters();
5751 if (!parameters.isEmpty()) {
5752 if (warn) {
5753 log.warning(
5754 TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5755 LintWarnings.SerialMethodNoArgs(method.getSimpleName()));
5756 }
5757 return false;
5758 }
5759 return true;
5760 }
5761
5762 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5763 // If the enclosing class is externalizable, warn for the method
5764 if (isExternalizable((Type)enclosing.asType())) {
5765 log.warning(
5766 TreeInfo.diagnosticPositionFor(method, tree),
5767 LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5768 }
5769 return;
5770 }
5771
5772 private boolean hasExpectedExceptions(JCClassDecl tree,
5773 MethodSymbol method,
5774 boolean warn,
5775 Type... declaredExceptions) {
5776 for (Type thrownType: method.getThrownTypes()) {
5777 // For each exception in the throws clause of the
5778 // method, if not an Error and not a RuntimeException,
5779 // check if the exception is a subtype of a declared
5780 // exception from the throws clause of the
5781 // serialization method in question.
5782 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5783 types.isSubtype(thrownType, syms.errorType) ) {
5784 continue;
5785 } else {
5786 boolean declared = false;
5787 for (Type declaredException : declaredExceptions) {
5788 if (types.isSubtype(thrownType, declaredException)) {
5789 declared = true;
5790 continue;
5791 }
5792 }
5793 if (!declared) {
5794 if (warn) {
5795 log.warning(
5796 TreeInfo.diagnosticPositionFor(method, tree),
5797 LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5798 thrownType));
5799 }
5800 return false;
5801 }
5802 }
5803 }
5804 return true;
5805 }
5806
5807 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5808 Lint prevLint = lint;
5809 try {
5810 lint = lint.augment((Symbol) symbol);
5811
5812 if (lint.isEnabled(LintCategory.SERIAL)) {
5813 task.accept(symbol, p);
5814 }
5815
5816 return null;
5817 } finally {
5818 lint = prevLint;
5819 }
5820 }
5821
5822 }
5823
5824 }
|