11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.comp;
27
28 import java.util.*;
29 import java.util.function.BiConsumer;
30 import java.util.function.BiPredicate;
31 import java.util.function.Consumer;
32 import java.util.function.Predicate;
33 import java.util.function.Supplier;
34 import java.util.function.ToIntBiFunction;
35 import java.util.stream.Collectors;
36 import java.util.stream.StreamSupport;
37
38 import javax.lang.model.element.ElementKind;
39 import javax.lang.model.element.NestingKind;
40 import javax.tools.JavaFileManager;
41
42 import com.sun.source.tree.CaseTree;
43 import com.sun.tools.javac.code.*;
44 import com.sun.tools.javac.code.Attribute.Compound;
45 import com.sun.tools.javac.code.Directive.ExportsDirective;
46 import com.sun.tools.javac.code.Directive.RequiresDirective;
47 import com.sun.tools.javac.code.Source.Feature;
48 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
49 import com.sun.tools.javac.jvm.*;
50 import com.sun.tools.javac.resources.CompilerProperties.Errors;
51 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
62 import com.sun.tools.javac.code.Lint;
63 import com.sun.tools.javac.code.Lint.LintCategory;
64 import com.sun.tools.javac.code.Scope.WriteableScope;
65 import com.sun.tools.javac.code.Type.*;
66 import com.sun.tools.javac.code.Symbol.*;
67 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
68 import com.sun.tools.javac.tree.JCTree.*;
69
70 import static com.sun.tools.javac.code.Flags.*;
71 import static com.sun.tools.javac.code.Flags.ANNOTATION;
72 import static com.sun.tools.javac.code.Flags.SYNCHRONIZED;
73 import static com.sun.tools.javac.code.Kinds.*;
74 import static com.sun.tools.javac.code.Kinds.Kind.*;
75 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
76 import static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE;
77 import static com.sun.tools.javac.code.TypeTag.*;
78 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
79
80 import static com.sun.tools.javac.tree.JCTree.Tag.*;
81 import javax.lang.model.element.Element;
82 import javax.lang.model.element.ExecutableElement;
83 import javax.lang.model.element.TypeElement;
84 import javax.lang.model.type.DeclaredType;
85 import javax.lang.model.type.TypeMirror;
86 import javax.lang.model.util.ElementFilter;
87 import javax.lang.model.util.ElementKindVisitor14;
88
89 /** Type checking helper class for the attribution phase.
90 *
91 * <p><b>This is NOT part of any supported API.
92 * If you write code that depends on this, you do so at your own risk.
93 * This code and its internal interfaces are subject to change or
94 * deletion without notice.</b>
95 */
96 public class Check {
97 protected static final Context.Key<Check> checkKey = new Context.Key<>();
98
99 // Flag bits indicating which item(s) chosen from a pair of items
100 private static final int FIRST = 0x01;
101 private static final int SECOND = 0x02;
102
103 private final Names names;
104 private final Log log;
105 private final Resolve rs;
106 private final Symtab syms;
167
168 boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
169 boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
170 boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
171 boolean enforceMandatoryWarnings = true;
172
173 deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated,
174 enforceMandatoryWarnings, "deprecated", LintCategory.DEPRECATION);
175 removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
176 enforceMandatoryWarnings, "removal", LintCategory.REMOVAL);
177 uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
178 enforceMandatoryWarnings, "unchecked", LintCategory.UNCHECKED);
179 sunApiHandler = new MandatoryWarningHandler(log, null, false,
180 enforceMandatoryWarnings, "sunapi", null);
181
182 deferredLintHandler = DeferredLintHandler.instance(context);
183
184 allowModules = Feature.MODULES.allowedInSource(source);
185 allowRecords = Feature.RECORDS.allowedInSource(source);
186 allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
187 }
188
189 /** Character for synthetic names
190 */
191 char syntheticNameChar;
192
193 /** A table mapping flat names of all compiled classes for each module in this run
194 * to their symbols; maintained from outside.
195 */
196 private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
197
198 /** A handler for messages about deprecated usage.
199 */
200 private MandatoryWarningHandler deprecationHandler;
201
202 /** A handler for messages about deprecated-for-removal usage.
203 */
204 private MandatoryWarningHandler removalHandler;
205
206 /** A handler for messages about unchecked or unsafe usage.
210 /** A handler for messages about using proprietary API.
211 */
212 private MandatoryWarningHandler sunApiHandler;
213
214 /** A handler for deferred lint warnings.
215 */
216 private DeferredLintHandler deferredLintHandler;
217
218 /** Are modules allowed
219 */
220 private final boolean allowModules;
221
222 /** Are records allowed
223 */
224 private final boolean allowRecords;
225
226 /** Are sealed classes allowed
227 */
228 private final boolean allowSealed;
229
230 /* *************************************************************************
231 * Errors and Warnings
232 **************************************************************************/
233
234 Lint setLint(Lint newLint) {
235 Lint prev = lint;
236 lint = newLint;
237 return prev;
238 }
239
240 MethodSymbol setMethod(MethodSymbol newMethod) {
241 MethodSymbol prev = method;
242 method = newMethod;
243 return prev;
244 }
245
246 /** Warn about deprecated symbol.
247 * @param pos Position to be used for error reporting.
248 * @param sym The deprecated symbol.
249 */
743 /** Check that type is a class or interface type.
744 * @param pos Position to be used for error reporting.
745 * @param t The type to be checked.
746 */
747 Type checkClassType(DiagnosticPosition pos, Type t) {
748 if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
749 return typeTagError(pos,
750 diags.fragment(Fragments.TypeReqClass),
751 asTypeParam(t));
752 } else {
753 return t;
754 }
755 }
756 //where
757 private Object asTypeParam(Type t) {
758 return (t.hasTag(TYPEVAR))
759 ? diags.fragment(Fragments.TypeParameter(t))
760 : t;
761 }
762
763 /** Check that type is a valid qualifier for a constructor reference expression
764 */
765 Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
766 t = checkClassOrArrayType(pos, t);
767 if (t.hasTag(CLASS)) {
768 if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
769 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
770 t = types.createErrorType(t);
771 } else if ((t.tsym.flags() & ENUM) != 0) {
772 log.error(pos, Errors.EnumCantBeInstantiated);
773 t = types.createErrorType(t);
774 } else {
775 t = checkClassType(pos, t, true);
776 }
777 } else if (t.hasTag(ARRAY)) {
778 if (!types.isReifiable(((ArrayType)t).elemtype)) {
779 log.error(pos, Errors.GenericArrayCreation);
780 t = types.createErrorType(t);
781 }
782 }
800 args = args.tail;
801 }
802 }
803 return t;
804 }
805
806 /** Check that type is a reference type, i.e. a class, interface or array type
807 * or a type variable.
808 * @param pos Position to be used for error reporting.
809 * @param t The type to be checked.
810 */
811 Type checkRefType(DiagnosticPosition pos, Type t) {
812 if (t.isReference())
813 return t;
814 else
815 return typeTagError(pos,
816 diags.fragment(Fragments.TypeReqRef),
817 t);
818 }
819
820 /** Check that each type is a reference type, i.e. a class, interface or array type
821 * or a type variable.
822 * @param trees Original trees, used for error reporting.
823 * @param types The types to be checked.
824 */
825 List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
826 List<JCExpression> tl = trees;
827 for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
828 l.head = checkRefType(tl.head.pos(), l.head);
829 tl = tl.tail;
830 }
831 return types;
832 }
833
834 /** Check that type is a null or reference type.
835 * @param pos Position to be used for error reporting.
836 * @param t The type to be checked.
837 */
838 Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
839 if (t.isReference() || t.hasTag(BOT))
1190 * return modifiers together with any implicit modifiers for that symbol.
1191 * Warning: we can't use flags() here since this method
1192 * is called during class enter, when flags() would cause a premature
1193 * completion.
1194 * @param pos Position to be used for error reporting.
1195 * @param flags The set of modifiers given in a definition.
1196 * @param sym The defined symbol.
1197 */
1198 long checkFlags(DiagnosticPosition pos, long flags, Symbol sym, JCTree tree) {
1199 long mask;
1200 long implicit = 0;
1201
1202 switch (sym.kind) {
1203 case VAR:
1204 if (TreeInfo.isReceiverParam(tree))
1205 mask = ReceiverParamFlags;
1206 else if (sym.owner.kind != TYP)
1207 mask = LocalVarFlags;
1208 else if ((sym.owner.flags_field & INTERFACE) != 0)
1209 mask = implicit = InterfaceVarFlags;
1210 else
1211 mask = VarFlags;
1212 break;
1213 case MTH:
1214 if (sym.name == names.init) {
1215 if ((sym.owner.flags_field & ENUM) != 0) {
1216 // enum constructors cannot be declared public or
1217 // protected and must be implicitly or explicitly
1218 // private
1219 implicit = PRIVATE;
1220 mask = PRIVATE;
1221 } else
1222 mask = ConstructorFlags;
1223 } else if ((sym.owner.flags_field & INTERFACE) != 0) {
1224 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1225 mask = AnnotationTypeElementMask;
1226 implicit = PUBLIC | ABSTRACT;
1227 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1228 mask = InterfaceMethodMask;
1229 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1230 if ((flags & DEFAULT) != 0) {
1231 implicit |= ABSTRACT;
1232 }
1233 } else {
1234 mask = implicit = InterfaceMethodFlags;
1235 }
1236 } else if ((sym.owner.flags_field & RECORD) != 0) {
1237 mask = RecordMethodFlags;
1238 } else {
1239 mask = MethodFlags;
1240 }
1241 if ((flags & STRICTFP) != 0) {
1242 warnOnExplicitStrictfp(pos);
1243 }
1244 // Imply STRICTFP if owner has STRICTFP set.
1245 if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1246 ((flags) & Flags.DEFAULT) != 0)
1247 implicit |= sym.owner.flags_field & STRICTFP;
1248 break;
1249 case TYP:
1250 if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1251 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1252 boolean implicitlyStatic = !sym.isAnonymous() &&
1253 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1254 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1255 // local statics are allowed only if records are allowed too
1256 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
1257 implicit = implicitlyStatic ? STATIC : implicit;
1258 } else if (sym.owner.kind == TYP) {
1259 // statics in inner classes are allowed only if records are allowed too
1260 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1261 if (sym.owner.owner.kind == PCK ||
1262 (sym.owner.flags_field & STATIC) != 0) {
1263 mask |= STATIC;
1264 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1265 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1266 }
1267 // Nested interfaces and enums are always STATIC (Spec ???)
1268 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1269 } else {
1270 mask = ExtendedClassFlags;
1271 }
1272 // Interfaces are always ABSTRACT
1273 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1274
1275 if ((flags & ENUM) != 0) {
1276 // enums can't be declared abstract, final, sealed or non-sealed
1277 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
1278 implicit |= implicitEnumFinalFlag(tree);
1279 }
1280 if ((flags & RECORD) != 0) {
1281 // records can't be declared abstract
1282 mask &= ~ABSTRACT;
1283 implicit |= FINAL;
1284 }
1285 if ((flags & STRICTFP) != 0) {
1286 warnOnExplicitStrictfp(pos);
1287 }
1288 // Imply STRICTFP if owner has STRICTFP set.
1289 implicit |= sym.owner.flags_field & STRICTFP;
1290 break;
1291 default:
1292 throw new AssertionError();
1293 }
1294 long illegal = flags & ExtendedStandardFlags & ~mask;
1295 if (illegal != 0) {
1296 if ((illegal & INTERFACE) != 0) {
1297 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1298 mask |= INTERFACE;
1299 }
1300 else {
1301 log.error(pos,
1302 Errors.ModNotAllowedHere(asFlagSet(illegal)));
1303 }
1304 }
1305 else if ((sym.kind == TYP ||
1306 // ISSUE: Disallowing abstract&private is no longer appropriate
1307 // in the presence of inner classes. Should it be deleted here?
1308 checkDisjoint(pos, flags,
1309 ABSTRACT,
1324 checkDisjoint(pos, flags,
1325 PRIVATE,
1326 PUBLIC | PROTECTED)
1327 &&
1328 checkDisjoint(pos, flags,
1329 FINAL,
1330 VOLATILE)
1331 &&
1332 (sym.kind == TYP ||
1333 checkDisjoint(pos, flags,
1334 ABSTRACT | NATIVE,
1335 STRICTFP))
1336 && checkDisjoint(pos, flags,
1337 FINAL,
1338 SEALED | NON_SEALED)
1339 && checkDisjoint(pos, flags,
1340 SEALED,
1341 FINAL | NON_SEALED)
1342 && checkDisjoint(pos, flags,
1343 SEALED,
1344 ANNOTATION)) {
1345 // skip
1346 }
1347 return flags & (mask | ~ExtendedStandardFlags) | implicit;
1348 }
1349
1350 private void warnOnExplicitStrictfp(DiagnosticPosition pos) {
1351 DiagnosticPosition prevLintPos = deferredLintHandler.setPos(pos);
1352 try {
1353 deferredLintHandler.report(_l -> {
1354 if (lint.isEnabled(LintCategory.STRICTFP)) {
1355 log.warning(LintCategory.STRICTFP,
1356 pos, Warnings.Strictfp); }
1357 });
1358 } finally {
1359 deferredLintHandler.setPos(prevLintPos);
1360 }
1361 }
1362
1363
1364 /** Determine if this enum should be implicitly final.
2141 return true;
2142 }
2143 }
2144 }
2145 return false;
2146 }
2147
2148 /** Check that a given method conforms with any method it overrides.
2149 * @param tree The tree from which positions are extracted
2150 * for errors.
2151 * @param m The overriding method.
2152 */
2153 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2154 ClassSymbol origin = (ClassSymbol)m.owner;
2155 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2156 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2157 log.error(tree.pos(), Errors.EnumNoFinalize);
2158 return;
2159 }
2160 }
2161 if (allowRecords && origin.isRecord()) {
2162 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2163 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2164 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2165 if (recordComponent.isPresent()) {
2166 return;
2167 }
2168 }
2169
2170 for (Type t = origin.type; t.hasTag(CLASS);
2171 t = types.supertype(t)) {
2172 if (t != origin.type) {
2173 checkOverride(tree, t, origin, m);
2174 }
2175 for (Type t2 : types.interfaces(t)) {
2176 checkOverride(tree, t2, origin, m);
2177 }
2178 }
2179
2180 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
2569 /** Check that all abstract methods implemented by a class are
2570 * mutually compatible.
2571 * @param pos Position to be used for error reporting.
2572 * @param c The class whose interfaces are checked.
2573 */
2574 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2575 List<Type> supertypes = types.interfaces(c);
2576 Type supertype = types.supertype(c);
2577 if (supertype.hasTag(CLASS) &&
2578 (supertype.tsym.flags() & ABSTRACT) != 0)
2579 supertypes = supertypes.prepend(supertype);
2580 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2581 if (!l.head.getTypeArguments().isEmpty() &&
2582 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2583 return;
2584 for (List<Type> m = supertypes; m != l; m = m.tail)
2585 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2586 return;
2587 }
2588 checkCompatibleConcretes(pos, c);
2589 }
2590
2591 /** Check that all non-override equivalent methods accessible from 'site'
2592 * are mutually compatible (JLS 8.4.8/9.4.1).
2593 *
2594 * @param pos Position to be used for error reporting.
2595 * @param site The class whose methods are checked.
2596 * @param sym The method symbol to be checked.
2597 */
2598 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2599 ClashFilter cf = new ClashFilter(site);
2600 //for each method m1 that is overridden (directly or indirectly)
2601 //by method 'sym' in 'site'...
2602
2603 ArrayList<Symbol> symbolsByName = new ArrayList<>();
2604 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2605 for (Symbol m1 : symbolsByName) {
2606 if (!sym.overrides(m1, site.tsym, types, false)) {
2607 continue;
2608 }
4881 }
4882 } else {
4883 Assert.error("Unknown pattern: " + currentPattern.getTag());
4884 }
4885 return false;
4886 }
4887
4888 /** check if a type is a subtype of Externalizable, if that is available. */
4889 boolean isExternalizable(Type t) {
4890 try {
4891 syms.externalizableType.complete();
4892 } catch (CompletionFailure e) {
4893 return false;
4894 }
4895 return types.isSubtype(t, syms.externalizableType);
4896 }
4897
4898 /**
4899 * Check structure of serialization declarations.
4900 */
4901 public void checkSerialStructure(JCClassDecl tree, ClassSymbol c) {
4902 (new SerialTypeVisitor()).visit(c, tree);
4903 }
4904
4905 /**
4906 * This visitor will warn if a serialization-related field or
4907 * method is declared in a suspicious or incorrect way. In
4908 * particular, it will warn for cases where the runtime
4909 * serialization mechanism will silently ignore a mis-declared
4910 * entity.
4911 *
4912 * Distinguished serialization-related fields and methods:
4913 *
4914 * Methods:
4915 *
4916 * private void writeObject(ObjectOutputStream stream) throws IOException
4917 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
4918 *
4919 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
4920 * private void readObjectNoData() throws ObjectStreamException
4921 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
4922 *
4923 * Fields:
4924 *
4925 * private static final long serialVersionUID
4926 * private static final ObjectStreamField[] serialPersistentFields
4927 *
4928 * Externalizable: methods defined on the interface
4929 * public void writeExternal(ObjectOutput) throws IOException
4930 * public void readExternal(ObjectInput) throws IOException
4931 */
4932 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
4933 SerialTypeVisitor() {
4934 this.lint = Check.this.lint;
4935 }
4936
4937 private static final Set<String> serialMethodNames =
4938 Set.of("writeObject", "writeReplace",
4939 "readObject", "readObjectNoData",
4940 "readResolve");
4941
4942 private static final Set<String> serialFieldNames =
4943 Set.of("serialVersionUID", "serialPersistentFields");
4944
4945 // Type of serialPersistentFields
4946 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
4947
4948 Lint lint;
4949
4950 @Override
4951 public Void defaultAction(Element e, JCClassDecl p) {
4952 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
4953 }
4954
4974 if (sym.kind == VAR) {
4975 svuidSym = (VarSymbol)sym;
4976 break;
4977 }
4978 }
4979
4980 if (svuidSym == null) {
4981 log.warning(LintCategory.SERIAL, p.pos(), Warnings.MissingSVUID(c));
4982 }
4983
4984 // Check for serialPersistentFields to gate checks for
4985 // non-serializable non-transient instance fields
4986 boolean serialPersistentFieldsPresent =
4987 c.members()
4988 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
4989 .iterator()
4990 .hasNext();
4991
4992 // Check declarations of serialization-related methods and
4993 // fields
4994 for(Symbol el : c.getEnclosedElements()) {
4995 runUnderLint(el, p, (enclosed, tree) -> {
4996 String name = null;
4997 switch(enclosed.getKind()) {
4998 case FIELD -> {
4999 if (!serialPersistentFieldsPresent) {
5000 var flags = enclosed.flags();
5001 if ( ((flags & TRANSIENT) == 0) &&
5002 ((flags & STATIC) == 0)) {
5003 Type varType = enclosed.asType();
5004 if (!canBeSerialized(varType)) {
5005 // Note per JLS arrays are
5006 // serializable even if the
5007 // component type is not.
5008 log.warning(LintCategory.SERIAL,
5009 TreeInfo.diagnosticPositionFor(enclosed, tree),
5010 Warnings.NonSerializableInstanceField);
5011 } else if (varType.hasTag(ARRAY)) {
5012 ArrayType arrayType = (ArrayType)varType;
5013 Type elementType = arrayType.elemtype;
5048 // will also pull in default methods from
5049 // superinterfaces. In other words, the runtime checks
5050 // (which long predate default methods on interfaces)
5051 // do not admit the possibility of inheriting methods
5052 // this way, a difference from general inheritance.
5053
5054 // The current implementation just checks the enclosed
5055 // elements and does not directly check the inherited
5056 // methods. If all the types are being checked this is
5057 // less of a concern; however, there are cases that
5058 // could be missed. In particular, readResolve and
5059 // writeReplace could, in principle, by inherited from
5060 // a non-serializable superclass and thus not checked
5061 // even if compiled with a serializable child class.
5062 case METHOD -> {
5063 var method = (MethodSymbol)enclosed;
5064 name = method.getSimpleName().toString();
5065 if (serialMethodNames.contains(name)) {
5066 switch (name) {
5067 case "writeObject" -> checkWriteObject(tree, e, method);
5068 case "writeReplace" -> checkWriteReplace(tree,e, method);
5069 case "readObject" -> checkReadObject(tree,e, method);
5070 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
5071 case "readResolve" -> checkReadResolve(tree, e, method);
5072 default -> throw new AssertionError();
5073 }
5074 }
5075 }
5076 }
5077 });
5078 }
5079
5080 return null;
5081 }
5082
5083 boolean canBeSerialized(Type type) {
5084 return type.isPrimitive() || rs.isSerializable(type);
5085 }
5086
5087 /**
5088 * Check that Externalizable class needs a public no-arg
5089 * constructor.
5090 *
5091 * Check that a Serializable class has access to the no-arg
5092 * constructor of its first nonserializable superclass.
5093 */
5094 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5095 if (isExternalizable(c.type)) {
5096 for(var sym : c.getEnclosedElements()) {
5097 if (sym.isConstructor() &&
5098 ((sym.flags() & PUBLIC) == PUBLIC)) {
5099 if (((MethodSymbol)sym).getParameters().isEmpty()) {
5100 return;
5101 }
5102 }
5103 }
5104 log.warning(LintCategory.SERIAL, tree.pos(),
5105 Warnings.ExternalizableMissingPublicNoArgCtor);
5106 } else {
5190 // Warn if serialPersistentFields is initialized to a
5191 // literal null.
5192 JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5193 if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5194 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5195 JCExpression initExpr = variableDef.init;
5196 if (initExpr != null && TreeInfo.isNull(initExpr)) {
5197 log.warning(LintCategory.SERIAL, initExpr.pos(),
5198 Warnings.SPFNullInit);
5199 }
5200 }
5201 }
5202
5203 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5204 // The "synchronized" modifier is seen in the wild on
5205 // readObject and writeObject methods and is generally
5206 // innocuous.
5207
5208 // private void writeObject(ObjectOutputStream stream) throws IOException
5209 checkPrivateNonStaticMethod(tree, method);
5210 checkReturnType(tree, e, method, syms.voidType);
5211 checkOneArg(tree, e, method, syms.objectOutputStreamType);
5212 checkExceptions(tree, e, method, syms.ioExceptionType);
5213 checkExternalizable(tree, e, method);
5214 }
5215
5216 private void checkWriteReplace(JCClassDecl tree, Element e, MethodSymbol method) {
5217 // ANY-ACCESS-MODIFIER Object writeReplace() throws
5218 // ObjectStreamException
5219
5220 // Excluding abstract, could have a more complicated
5221 // rule based on abstract-ness of the class
5222 checkConcreteInstanceMethod(tree, e, method);
5223 checkReturnType(tree, e, method, syms.objectType);
5224 checkNoArgs(tree, e, method);
5225 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5226 }
5227
5228 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5229 // The "synchronized" modifier is seen in the wild on
5230 // readObject and writeObject methods and is generally
5231 // innocuous.
5232
5233 // private void readObject(ObjectInputStream stream)
5234 // throws IOException, ClassNotFoundException
5235 checkPrivateNonStaticMethod(tree, method);
5236 checkReturnType(tree, e, method, syms.voidType);
5237 checkOneArg(tree, e, method, syms.objectInputStreamType);
5238 checkExceptions(tree, e, method, syms.ioExceptionType, syms.classNotFoundExceptionType);
5239 checkExternalizable(tree, e, method);
5240 }
5241
5242 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5243 // private void readObjectNoData() throws ObjectStreamException
5244 checkPrivateNonStaticMethod(tree, method);
5245 checkReturnType(tree, e, method, syms.voidType);
5246 checkNoArgs(tree, e, method);
5247 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5248 checkExternalizable(tree, e, method);
5249 }
5250
5251 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5252 // ANY-ACCESS-MODIFIER Object readResolve()
5253 // throws ObjectStreamException
5254
5255 // Excluding abstract, could have a more complicated
5256 // rule based on abstract-ness of the class
5257 checkConcreteInstanceMethod(tree, e, method);
5258 checkReturnType(tree,e, method, syms.objectType);
5259 checkNoArgs(tree, e, method);
5260 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5261 }
5262
5263 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5264 //public void writeExternal(ObjectOutput) throws IOException
5265 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5266 }
5267
5268 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5269 // public void readExternal(ObjectInput) throws IOException
5270 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5271 }
5272
5273 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5274 boolean isExtern) {
5275 if (isExtern && isExternMethod(tree, e, method, argType)) {
5276 log.warning(LintCategory.SERIAL,
5277 TreeInfo.diagnosticPositionFor(method, tree),
5278 Warnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5279 }
5280 }
5490 case FIELD -> {
5491 var field = (VarSymbol)enclosed;
5492 switch(name) {
5493 case "serialPersistentFields" -> {
5494 log.warning(LintCategory.SERIAL,
5495 TreeInfo.diagnosticPositionFor(field, tree),
5496 Warnings.IneffectualSerialFieldRecord);
5497 }
5498
5499 case "serialVersionUID" -> {
5500 // Could generate additional warning that
5501 // svuid value is not checked to match for
5502 // records.
5503 checkSerialVersionUID(tree, e, field);
5504 }}
5505 }
5506
5507 case METHOD -> {
5508 var method = (MethodSymbol)enclosed;
5509 switch(name) {
5510 case "writeReplace" -> checkWriteReplace(tree, e, method);
5511 case "readResolve" -> checkReadResolve(tree, e, method);
5512
5513 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5514 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern);
5515
5516 default -> {
5517 if (serialMethodNames.contains(name)) {
5518 log.warning(LintCategory.SERIAL,
5519 TreeInfo.diagnosticPositionFor(method, tree),
5520 Warnings.IneffectualSerialMethodRecord(name));
5521 }
5522 }}
5523 }}});
5524 }
5525 return null;
5526 }
5527
5528 void checkConcreteInstanceMethod(JCClassDecl tree,
5529 Element enclosing,
5530 MethodSymbol method) {
5531 if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5532 log.warning(LintCategory.SERIAL,
5533 TreeInfo.diagnosticPositionFor(method, tree),
5534 Warnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5535 }
5536 }
5537
5538 private void checkReturnType(JCClassDecl tree,
5539 Element enclosing,
5540 MethodSymbol method,
5541 Type expectedReturnType) {
5542 // Note: there may be complications checking writeReplace
5543 // and readResolve since they return Object and could, in
5544 // principle, have covariant overrides and any synthetic
5545 // bridge method would not be represented here for
5546 // checking.
5547 Type rtype = method.getReturnType();
5548 if (!types.isSameType(expectedReturnType, rtype)) {
5549 log.warning(LintCategory.SERIAL,
5550 TreeInfo.diagnosticPositionFor(method, tree),
5551 Warnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5552 rtype, expectedReturnType));
5553 }
5554 }
5555
5556 private void checkOneArg(JCClassDecl tree,
5557 Element enclosing,
5558 MethodSymbol method,
5559 Type expectedType) {
5560 String name = method.getSimpleName().toString();
5561
5562 var parameters= method.getParameters();
5563
5564 if (parameters.size() != 1) {
5565 log.warning(LintCategory.SERIAL,
5566 TreeInfo.diagnosticPositionFor(method, tree),
5567 Warnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5568 return;
5569 }
5570
5571 Type parameterType = parameters.get(0).asType();
5572 if (!types.isSameType(parameterType, expectedType)) {
5573 log.warning(LintCategory.SERIAL,
5574 TreeInfo.diagnosticPositionFor(method, tree),
5575 Warnings.SerialMethodParameterType(method.getSimpleName(),
5576 expectedType,
5577 parameterType));
5578 }
5579 }
5580
5581 private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5582 Element enclosing,
5583 MethodSymbol method,
5584 Type expectedType) {
5585 var parameters = method.getParameters();
5586 return (parameters.size() == 1) &&
5587 types.isSameType(parameters.get(0).asType(), expectedType);
5588 }
5589
5590
5591 private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5592 var parameters = method.getParameters();
5593 if (!parameters.isEmpty()) {
5594 log.warning(LintCategory.SERIAL,
5595 TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5596 Warnings.SerialMethodNoArgs(method.getSimpleName()));
5597 }
5598 }
5599
5600 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5601 // If the enclosing class is externalizable, warn for the method
5602 if (isExternalizable((Type)enclosing.asType())) {
5603 log.warning(LintCategory.SERIAL,
5604 TreeInfo.diagnosticPositionFor(method, tree),
5605 Warnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5606 }
5607 return;
5608 }
5609
5610 private void checkExceptions(JCClassDecl tree,
5611 Element enclosing,
5612 MethodSymbol method,
5613 Type... declaredExceptions) {
5614 for (Type thrownType: method.getThrownTypes()) {
5615 // For each exception in the throws clause of the
5616 // method, if not an Error and not a RuntimeException,
5617 // check if the exception is a subtype of a declared
5618 // exception from the throws clause of the
5619 // serialization method in question.
5620 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5621 types.isSubtype(thrownType, syms.errorType) ) {
5622 continue;
5623 } else {
5624 boolean declared = false;
5625 for (Type declaredException : declaredExceptions) {
5626 if (types.isSubtype(thrownType, declaredException)) {
5627 declared = true;
5628 continue;
5629 }
5630 }
5631 if (!declared) {
5632 log.warning(LintCategory.SERIAL,
5633 TreeInfo.diagnosticPositionFor(method, tree),
5634 Warnings.SerialMethodUnexpectedException(method.getSimpleName(),
5635 thrownType));
5636 }
5637 }
5638 }
5639 return;
5640 }
5641
5642 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5643 Lint prevLint = lint;
5644 try {
5645 lint = lint.augment((Symbol) symbol);
5646
5647 if (lint.isEnabled(LintCategory.SERIAL)) {
5648 task.accept(symbol, p);
5649 }
5650
5651 return null;
5652 } finally {
5653 lint = prevLint;
5654 }
5655 }
5656
5657 }
5658
5659 }
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.tools.javac.comp;
27
28 import java.util.*;
29 import java.util.function.BiConsumer;
30 import java.util.function.BiPredicate;
31 import java.util.function.Predicate;
32 import java.util.function.Supplier;
33 import java.util.function.ToIntBiFunction;
34 import java.util.stream.Collectors;
35 import java.util.stream.StreamSupport;
36
37 import javax.lang.model.element.ElementKind;
38 import javax.lang.model.element.NestingKind;
39 import javax.tools.JavaFileManager;
40
41 import com.sun.source.tree.CaseTree;
42 import com.sun.tools.javac.code.*;
43 import com.sun.tools.javac.code.Attribute.Compound;
44 import com.sun.tools.javac.code.Directive.ExportsDirective;
45 import com.sun.tools.javac.code.Directive.RequiresDirective;
46 import com.sun.tools.javac.code.Source.Feature;
47 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
48 import com.sun.tools.javac.jvm.*;
49 import com.sun.tools.javac.resources.CompilerProperties.Errors;
50 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
61 import com.sun.tools.javac.code.Lint;
62 import com.sun.tools.javac.code.Lint.LintCategory;
63 import com.sun.tools.javac.code.Scope.WriteableScope;
64 import com.sun.tools.javac.code.Type.*;
65 import com.sun.tools.javac.code.Symbol.*;
66 import com.sun.tools.javac.comp.DeferredAttr.DeferredAttrContext;
67 import com.sun.tools.javac.tree.JCTree.*;
68
69 import static com.sun.tools.javac.code.Flags.*;
70 import static com.sun.tools.javac.code.Flags.ANNOTATION;
71 import static com.sun.tools.javac.code.Flags.SYNCHRONIZED;
72 import static com.sun.tools.javac.code.Kinds.*;
73 import static com.sun.tools.javac.code.Kinds.Kind.*;
74 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
75 import static com.sun.tools.javac.code.Scope.LookupKind.RECURSIVE;
76 import static com.sun.tools.javac.code.TypeTag.*;
77 import static com.sun.tools.javac.code.TypeTag.WILDCARD;
78
79 import static com.sun.tools.javac.tree.JCTree.Tag.*;
80 import javax.lang.model.element.Element;
81 import javax.lang.model.element.TypeElement;
82 import javax.lang.model.type.DeclaredType;
83 import javax.lang.model.util.ElementKindVisitor14;
84
85 /** Type checking helper class for the attribution phase.
86 *
87 * <p><b>This is NOT part of any supported API.
88 * If you write code that depends on this, you do so at your own risk.
89 * This code and its internal interfaces are subject to change or
90 * deletion without notice.</b>
91 */
92 public class Check {
93 protected static final Context.Key<Check> checkKey = new Context.Key<>();
94
95 // Flag bits indicating which item(s) chosen from a pair of items
96 private static final int FIRST = 0x01;
97 private static final int SECOND = 0x02;
98
99 private final Names names;
100 private final Log log;
101 private final Resolve rs;
102 private final Symtab syms;
163
164 boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
165 boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
166 boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
167 boolean enforceMandatoryWarnings = true;
168
169 deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated,
170 enforceMandatoryWarnings, "deprecated", LintCategory.DEPRECATION);
171 removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
172 enforceMandatoryWarnings, "removal", LintCategory.REMOVAL);
173 uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
174 enforceMandatoryWarnings, "unchecked", LintCategory.UNCHECKED);
175 sunApiHandler = new MandatoryWarningHandler(log, null, false,
176 enforceMandatoryWarnings, "sunapi", null);
177
178 deferredLintHandler = DeferredLintHandler.instance(context);
179
180 allowModules = Feature.MODULES.allowedInSource(source);
181 allowRecords = Feature.RECORDS.allowedInSource(source);
182 allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
183 allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
184 Feature.VALUE_CLASSES.allowedInSource(source);
185 }
186
187 /** Character for synthetic names
188 */
189 char syntheticNameChar;
190
191 /** A table mapping flat names of all compiled classes for each module in this run
192 * to their symbols; maintained from outside.
193 */
194 private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
195
196 /** A handler for messages about deprecated usage.
197 */
198 private MandatoryWarningHandler deprecationHandler;
199
200 /** A handler for messages about deprecated-for-removal usage.
201 */
202 private MandatoryWarningHandler removalHandler;
203
204 /** A handler for messages about unchecked or unsafe usage.
208 /** A handler for messages about using proprietary API.
209 */
210 private MandatoryWarningHandler sunApiHandler;
211
212 /** A handler for deferred lint warnings.
213 */
214 private DeferredLintHandler deferredLintHandler;
215
216 /** Are modules allowed
217 */
218 private final boolean allowModules;
219
220 /** Are records allowed
221 */
222 private final boolean allowRecords;
223
224 /** Are sealed classes allowed
225 */
226 private final boolean allowSealed;
227
228 /** Are value classes allowed
229 */
230 private final boolean allowValueClasses;
231
232 /* *************************************************************************
233 * Errors and Warnings
234 **************************************************************************/
235
236 Lint setLint(Lint newLint) {
237 Lint prev = lint;
238 lint = newLint;
239 return prev;
240 }
241
242 MethodSymbol setMethod(MethodSymbol newMethod) {
243 MethodSymbol prev = method;
244 method = newMethod;
245 return prev;
246 }
247
248 /** Warn about deprecated symbol.
249 * @param pos Position to be used for error reporting.
250 * @param sym The deprecated symbol.
251 */
745 /** Check that type is a class or interface type.
746 * @param pos Position to be used for error reporting.
747 * @param t The type to be checked.
748 */
749 Type checkClassType(DiagnosticPosition pos, Type t) {
750 if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
751 return typeTagError(pos,
752 diags.fragment(Fragments.TypeReqClass),
753 asTypeParam(t));
754 } else {
755 return t;
756 }
757 }
758 //where
759 private Object asTypeParam(Type t) {
760 return (t.hasTag(TYPEVAR))
761 ? diags.fragment(Fragments.TypeParameter(t))
762 : t;
763 }
764
765 void checkConstraintsOfValueClass(JCClassDecl tree, ClassSymbol c) {
766 DiagnosticPosition pos = tree.pos();
767 for (Type st : types.closure(c.type)) {
768 if (st == null || st.tsym == null || st.tsym.kind == ERR)
769 continue;
770 if (st.tsym == syms.objectType.tsym || st.tsym == syms.recordType.tsym || st.isInterface())
771 continue;
772 if (!st.tsym.isAbstract()) {
773 if (c != st.tsym) {
774 log.error(pos, Errors.ConcreteSupertypeForValueClass(c, st));
775 }
776 continue;
777 }
778 // dealing with an abstract value or value super class below.
779 for (Symbol s : st.tsym.members().getSymbols(NON_RECURSIVE)) {
780 if (s.kind == MTH) {
781 if ((s.flags() & (SYNCHRONIZED | STATIC)) == SYNCHRONIZED) {
782 log.error(pos, Errors.SuperClassMethodCannotBeSynchronized(s, c, st));
783 }
784 break;
785 }
786 }
787 }
788 }
789
790 /** Check that type is a valid qualifier for a constructor reference expression
791 */
792 Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
793 t = checkClassOrArrayType(pos, t);
794 if (t.hasTag(CLASS)) {
795 if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
796 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
797 t = types.createErrorType(t);
798 } else if ((t.tsym.flags() & ENUM) != 0) {
799 log.error(pos, Errors.EnumCantBeInstantiated);
800 t = types.createErrorType(t);
801 } else {
802 t = checkClassType(pos, t, true);
803 }
804 } else if (t.hasTag(ARRAY)) {
805 if (!types.isReifiable(((ArrayType)t).elemtype)) {
806 log.error(pos, Errors.GenericArrayCreation);
807 t = types.createErrorType(t);
808 }
809 }
827 args = args.tail;
828 }
829 }
830 return t;
831 }
832
833 /** Check that type is a reference type, i.e. a class, interface or array type
834 * or a type variable.
835 * @param pos Position to be used for error reporting.
836 * @param t The type to be checked.
837 */
838 Type checkRefType(DiagnosticPosition pos, Type t) {
839 if (t.isReference())
840 return t;
841 else
842 return typeTagError(pos,
843 diags.fragment(Fragments.TypeReqRef),
844 t);
845 }
846
847 /** Check that type is an identity type, i.e. not a value type.
848 * When not discernible statically, give it the benefit of doubt
849 * and defer to runtime.
850 *
851 * @param pos Position to be used for error reporting.
852 * @param t The type to be checked.
853 */
854 boolean checkIdentityType(DiagnosticPosition pos, Type t) {
855 if (t.hasTag(TYPEVAR)) {
856 t = types.skipTypeVars(t, false);
857 }
858 if (t.isIntersection()) {
859 IntersectionClassType ict = (IntersectionClassType)t;
860 boolean result = true;
861 for (Type component : ict.getExplicitComponents()) {
862 result &= checkIdentityType(pos, component);
863 }
864 return result;
865 }
866 if (t.isPrimitive() || (t.isValueClass() && !t.tsym.isAbstract())) {
867 typeTagError(pos, diags.fragment(Fragments.TypeReqIdentity), t);
868 return false;
869 }
870 return true;
871 }
872
873 /** Check that each type is a reference type, i.e. a class, interface or array type
874 * or a type variable.
875 * @param trees Original trees, used for error reporting.
876 * @param types The types to be checked.
877 */
878 List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
879 List<JCExpression> tl = trees;
880 for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
881 l.head = checkRefType(tl.head.pos(), l.head);
882 tl = tl.tail;
883 }
884 return types;
885 }
886
887 /** Check that type is a null or reference type.
888 * @param pos Position to be used for error reporting.
889 * @param t The type to be checked.
890 */
891 Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
892 if (t.isReference() || t.hasTag(BOT))
1243 * return modifiers together with any implicit modifiers for that symbol.
1244 * Warning: we can't use flags() here since this method
1245 * is called during class enter, when flags() would cause a premature
1246 * completion.
1247 * @param pos Position to be used for error reporting.
1248 * @param flags The set of modifiers given in a definition.
1249 * @param sym The defined symbol.
1250 */
1251 long checkFlags(DiagnosticPosition pos, long flags, Symbol sym, JCTree tree) {
1252 long mask;
1253 long implicit = 0;
1254
1255 switch (sym.kind) {
1256 case VAR:
1257 if (TreeInfo.isReceiverParam(tree))
1258 mask = ReceiverParamFlags;
1259 else if (sym.owner.kind != TYP)
1260 mask = LocalVarFlags;
1261 else if ((sym.owner.flags_field & INTERFACE) != 0)
1262 mask = implicit = InterfaceVarFlags;
1263 else {
1264 boolean isInstanceFieldOfValueClass = sym.owner.type.isValueClass() && (flags & STATIC) == 0;
1265 mask = !isInstanceFieldOfValueClass ? VarFlags : ExtendedVarFlags;
1266 if (isInstanceFieldOfValueClass) {
1267 implicit |= FINAL | STRICT;
1268 }
1269 }
1270 break;
1271 case MTH:
1272 if (sym.name == names.init) {
1273 if ((sym.owner.flags_field & ENUM) != 0) {
1274 // enum constructors cannot be declared public or
1275 // protected and must be implicitly or explicitly
1276 // private
1277 implicit = PRIVATE;
1278 mask = PRIVATE;
1279 } else
1280 mask = ConstructorFlags;
1281 } else if ((sym.owner.flags_field & INTERFACE) != 0) {
1282 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1283 mask = AnnotationTypeElementMask;
1284 implicit = PUBLIC | ABSTRACT;
1285 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1286 mask = InterfaceMethodMask;
1287 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1288 if ((flags & DEFAULT) != 0) {
1289 implicit |= ABSTRACT;
1290 }
1291 } else {
1292 mask = implicit = InterfaceMethodFlags;
1293 }
1294 } else if ((sym.owner.flags_field & RECORD) != 0) {
1295 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1296 RecordMethodFlags & ~SYNCHRONIZED : RecordMethodFlags;
1297 } else {
1298 // value objects do not have an associated monitor/lock
1299 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1300 MethodFlags & ~SYNCHRONIZED : MethodFlags;
1301 }
1302 if ((flags & STRICTFP) != 0) {
1303 warnOnExplicitStrictfp(pos);
1304 }
1305 // Imply STRICTFP if owner has STRICTFP set.
1306 if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1307 ((flags) & Flags.DEFAULT) != 0)
1308 implicit |= sym.owner.flags_field & STRICTFP;
1309 break;
1310 case TYP:
1311 if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1312 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1313 boolean implicitlyStatic = !sym.isAnonymous() &&
1314 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1315 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1316 // local statics are allowed only if records are allowed too
1317 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedStaticLocalClassFlags : ExtendedLocalClassFlags;
1318 implicit = implicitlyStatic ? STATIC : implicit;
1319 } else if (sym.owner.kind == TYP) {
1320 // statics in inner classes are allowed only if records are allowed too
1321 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1322 if (sym.owner.owner.kind == PCK ||
1323 (sym.owner.flags_field & STATIC) != 0) {
1324 mask |= STATIC;
1325 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1326 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1327 }
1328 // Nested interfaces and enums are always STATIC (Spec ???)
1329 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1330 } else {
1331 mask = ExtendedClassFlags;
1332 }
1333 // Interfaces are always ABSTRACT
1334 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1335
1336 if ((flags & (INTERFACE | VALUE_CLASS)) == 0) {
1337 implicit |= IDENTITY_TYPE;
1338 }
1339
1340 if ((flags & ENUM) != 0) {
1341 // enums can't be declared abstract, final, sealed or non-sealed or value
1342 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | VALUE_CLASS);
1343 implicit |= implicitEnumFinalFlag(tree);
1344 }
1345 if ((flags & RECORD) != 0) {
1346 // records can't be declared abstract
1347 mask &= ~ABSTRACT;
1348 implicit |= FINAL;
1349 }
1350 if ((flags & STRICTFP) != 0) {
1351 warnOnExplicitStrictfp(pos);
1352 }
1353 // Imply STRICTFP if owner has STRICTFP set.
1354 implicit |= sym.owner.flags_field & STRICTFP;
1355
1356 // concrete value classes are implicitly final
1357 if ((flags & (ABSTRACT | INTERFACE | VALUE_CLASS)) == VALUE_CLASS) {
1358 implicit |= FINAL;
1359 }
1360 break;
1361 default:
1362 throw new AssertionError();
1363 }
1364 long illegal = flags & ExtendedStandardFlags & ~mask;
1365 if (illegal != 0) {
1366 if ((illegal & INTERFACE) != 0) {
1367 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1368 mask |= INTERFACE;
1369 }
1370 else {
1371 log.error(pos,
1372 Errors.ModNotAllowedHere(asFlagSet(illegal)));
1373 }
1374 }
1375 else if ((sym.kind == TYP ||
1376 // ISSUE: Disallowing abstract&private is no longer appropriate
1377 // in the presence of inner classes. Should it be deleted here?
1378 checkDisjoint(pos, flags,
1379 ABSTRACT,
1394 checkDisjoint(pos, flags,
1395 PRIVATE,
1396 PUBLIC | PROTECTED)
1397 &&
1398 checkDisjoint(pos, flags,
1399 FINAL,
1400 VOLATILE)
1401 &&
1402 (sym.kind == TYP ||
1403 checkDisjoint(pos, flags,
1404 ABSTRACT | NATIVE,
1405 STRICTFP))
1406 && checkDisjoint(pos, flags,
1407 FINAL,
1408 SEALED | NON_SEALED)
1409 && checkDisjoint(pos, flags,
1410 SEALED,
1411 FINAL | NON_SEALED)
1412 && checkDisjoint(pos, flags,
1413 SEALED,
1414 ANNOTATION)
1415 && checkDisjoint(pos, flags,
1416 VALUE_CLASS,
1417 ANNOTATION)
1418 && checkDisjoint(pos, flags,
1419 VALUE_CLASS,
1420 NON_SEALED)
1421 && checkDisjoint(pos, flags,
1422 VALUE_CLASS,
1423 INTERFACE) ) {
1424 // skip
1425 }
1426 return flags & (mask | ~ExtendedStandardFlags) | implicit;
1427 }
1428
1429 private void warnOnExplicitStrictfp(DiagnosticPosition pos) {
1430 DiagnosticPosition prevLintPos = deferredLintHandler.setPos(pos);
1431 try {
1432 deferredLintHandler.report(_l -> {
1433 if (lint.isEnabled(LintCategory.STRICTFP)) {
1434 log.warning(LintCategory.STRICTFP,
1435 pos, Warnings.Strictfp); }
1436 });
1437 } finally {
1438 deferredLintHandler.setPos(prevLintPos);
1439 }
1440 }
1441
1442
1443 /** Determine if this enum should be implicitly final.
2220 return true;
2221 }
2222 }
2223 }
2224 return false;
2225 }
2226
2227 /** Check that a given method conforms with any method it overrides.
2228 * @param tree The tree from which positions are extracted
2229 * for errors.
2230 * @param m The overriding method.
2231 */
2232 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2233 ClassSymbol origin = (ClassSymbol)m.owner;
2234 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2235 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2236 log.error(tree.pos(), Errors.EnumNoFinalize);
2237 return;
2238 }
2239 }
2240 if (allowValueClasses && origin.isValueClass() && names.finalize.equals(m.name)) {
2241 if (m.overrides(syms.objectFinalize, origin, types, false)) {
2242 log.warning(tree.pos(), Warnings.ValueFinalize);
2243 }
2244 }
2245 if (allowRecords && origin.isRecord()) {
2246 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2247 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2248 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2249 if (recordComponent.isPresent()) {
2250 return;
2251 }
2252 }
2253
2254 for (Type t = origin.type; t.hasTag(CLASS);
2255 t = types.supertype(t)) {
2256 if (t != origin.type) {
2257 checkOverride(tree, t, origin, m);
2258 }
2259 for (Type t2 : types.interfaces(t)) {
2260 checkOverride(tree, t2, origin, m);
2261 }
2262 }
2263
2264 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
2653 /** Check that all abstract methods implemented by a class are
2654 * mutually compatible.
2655 * @param pos Position to be used for error reporting.
2656 * @param c The class whose interfaces are checked.
2657 */
2658 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2659 List<Type> supertypes = types.interfaces(c);
2660 Type supertype = types.supertype(c);
2661 if (supertype.hasTag(CLASS) &&
2662 (supertype.tsym.flags() & ABSTRACT) != 0)
2663 supertypes = supertypes.prepend(supertype);
2664 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2665 if (!l.head.getTypeArguments().isEmpty() &&
2666 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2667 return;
2668 for (List<Type> m = supertypes; m != l; m = m.tail)
2669 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2670 return;
2671 }
2672 checkCompatibleConcretes(pos, c);
2673
2674 Type identitySuper = null;
2675 for (Type t : types.closure(c)) {
2676 if (t != c) {
2677 if (t.isIdentityClass() && (t.tsym.flags() & VALUE_BASED) == 0)
2678 identitySuper = t;
2679 if (c.isValueClass() && identitySuper != null && identitySuper.tsym != syms.objectType.tsym) { // Object is special
2680 log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, identitySuper));
2681 break;
2682 }
2683 }
2684 }
2685 }
2686
2687 /** Check that all non-override equivalent methods accessible from 'site'
2688 * are mutually compatible (JLS 8.4.8/9.4.1).
2689 *
2690 * @param pos Position to be used for error reporting.
2691 * @param site The class whose methods are checked.
2692 * @param sym The method symbol to be checked.
2693 */
2694 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2695 ClashFilter cf = new ClashFilter(site);
2696 //for each method m1 that is overridden (directly or indirectly)
2697 //by method 'sym' in 'site'...
2698
2699 ArrayList<Symbol> symbolsByName = new ArrayList<>();
2700 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2701 for (Symbol m1 : symbolsByName) {
2702 if (!sym.overrides(m1, site.tsym, types, false)) {
2703 continue;
2704 }
4977 }
4978 } else {
4979 Assert.error("Unknown pattern: " + currentPattern.getTag());
4980 }
4981 return false;
4982 }
4983
4984 /** check if a type is a subtype of Externalizable, if that is available. */
4985 boolean isExternalizable(Type t) {
4986 try {
4987 syms.externalizableType.complete();
4988 } catch (CompletionFailure e) {
4989 return false;
4990 }
4991 return types.isSubtype(t, syms.externalizableType);
4992 }
4993
4994 /**
4995 * Check structure of serialization declarations.
4996 */
4997 public void checkSerialStructure(Env<AttrContext> env, JCClassDecl tree, ClassSymbol c) {
4998 (new SerialTypeVisitor(env)).visit(c, tree);
4999 }
5000
5001 /**
5002 * This visitor will warn if a serialization-related field or
5003 * method is declared in a suspicious or incorrect way. In
5004 * particular, it will warn for cases where the runtime
5005 * serialization mechanism will silently ignore a mis-declared
5006 * entity.
5007 *
5008 * Distinguished serialization-related fields and methods:
5009 *
5010 * Methods:
5011 *
5012 * private void writeObject(ObjectOutputStream stream) throws IOException
5013 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
5014 *
5015 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
5016 * private void readObjectNoData() throws ObjectStreamException
5017 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
5018 *
5019 * Fields:
5020 *
5021 * private static final long serialVersionUID
5022 * private static final ObjectStreamField[] serialPersistentFields
5023 *
5024 * Externalizable: methods defined on the interface
5025 * public void writeExternal(ObjectOutput) throws IOException
5026 * public void readExternal(ObjectInput) throws IOException
5027 */
5028 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
5029 Env<AttrContext> env;
5030 SerialTypeVisitor(Env<AttrContext> env) {
5031 this.lint = Check.this.lint;
5032 this.env = env;
5033 }
5034
5035 private static final Set<String> serialMethodNames =
5036 Set.of("writeObject", "writeReplace",
5037 "readObject", "readObjectNoData",
5038 "readResolve");
5039
5040 private static final Set<String> serialFieldNames =
5041 Set.of("serialVersionUID", "serialPersistentFields");
5042
5043 // Type of serialPersistentFields
5044 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
5045
5046 Lint lint;
5047
5048 @Override
5049 public Void defaultAction(Element e, JCClassDecl p) {
5050 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
5051 }
5052
5072 if (sym.kind == VAR) {
5073 svuidSym = (VarSymbol)sym;
5074 break;
5075 }
5076 }
5077
5078 if (svuidSym == null) {
5079 log.warning(LintCategory.SERIAL, p.pos(), Warnings.MissingSVUID(c));
5080 }
5081
5082 // Check for serialPersistentFields to gate checks for
5083 // non-serializable non-transient instance fields
5084 boolean serialPersistentFieldsPresent =
5085 c.members()
5086 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
5087 .iterator()
5088 .hasNext();
5089
5090 // Check declarations of serialization-related methods and
5091 // fields
5092 final boolean[] hasWriteReplace = {false};
5093 for(Symbol el : c.getEnclosedElements()) {
5094 runUnderLint(el, p, (enclosed, tree) -> {
5095 String name = null;
5096 switch(enclosed.getKind()) {
5097 case FIELD -> {
5098 if (!serialPersistentFieldsPresent) {
5099 var flags = enclosed.flags();
5100 if ( ((flags & TRANSIENT) == 0) &&
5101 ((flags & STATIC) == 0)) {
5102 Type varType = enclosed.asType();
5103 if (!canBeSerialized(varType)) {
5104 // Note per JLS arrays are
5105 // serializable even if the
5106 // component type is not.
5107 log.warning(LintCategory.SERIAL,
5108 TreeInfo.diagnosticPositionFor(enclosed, tree),
5109 Warnings.NonSerializableInstanceField);
5110 } else if (varType.hasTag(ARRAY)) {
5111 ArrayType arrayType = (ArrayType)varType;
5112 Type elementType = arrayType.elemtype;
5147 // will also pull in default methods from
5148 // superinterfaces. In other words, the runtime checks
5149 // (which long predate default methods on interfaces)
5150 // do not admit the possibility of inheriting methods
5151 // this way, a difference from general inheritance.
5152
5153 // The current implementation just checks the enclosed
5154 // elements and does not directly check the inherited
5155 // methods. If all the types are being checked this is
5156 // less of a concern; however, there are cases that
5157 // could be missed. In particular, readResolve and
5158 // writeReplace could, in principle, by inherited from
5159 // a non-serializable superclass and thus not checked
5160 // even if compiled with a serializable child class.
5161 case METHOD -> {
5162 var method = (MethodSymbol)enclosed;
5163 name = method.getSimpleName().toString();
5164 if (serialMethodNames.contains(name)) {
5165 switch (name) {
5166 case "writeObject" -> checkWriteObject(tree, e, method);
5167 case "writeReplace" -> {hasWriteReplace[0] = true; hasAppropriateWriteReplace(tree, method, true);}
5168 case "readObject" -> checkReadObject(tree,e, method);
5169 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
5170 case "readResolve" -> checkReadResolve(tree, e, method);
5171 default -> throw new AssertionError();
5172 }
5173 }
5174 }
5175 }
5176 });
5177 }
5178 if (!hasWriteReplace[0] &&
5179 (c.isValueClass() || hasAbstractValueSuperClass(c, Set.of(syms.numberType.tsym))) &&
5180 !c.isAbstract() && !c.isRecord() &&
5181 types.unboxedType(c.type) == Type.noType) {
5182 // we need to check if the class is inheriting an appropriate writeReplace method
5183 MethodSymbol ms = null;
5184 Log.DiagnosticHandler discardHandler = new Log.DiscardDiagnosticHandler(log);
5185 try {
5186 ms = rs.resolveInternalMethod(env.tree, env, c.type, names.writeReplace, List.nil(), List.nil());
5187 } catch (FatalError fe) {
5188 // ignore no method was found
5189 } finally {
5190 log.popDiagnosticHandler(discardHandler);
5191 }
5192 if (ms == null || !hasAppropriateWriteReplace(p, ms, false)) {
5193 log.warning(LintCategory.SERIAL, p,
5194 c.isValueClass() ? Warnings.SerializableValueClassWithoutWriteReplace1 :
5195 Warnings.SerializableValueClassWithoutWriteReplace2);
5196 }
5197 }
5198 return null;
5199 }
5200
5201 boolean canBeSerialized(Type type) {
5202 return type.isPrimitive() || rs.isSerializable(type);
5203 }
5204
5205 private boolean hasAbstractValueSuperClass(Symbol c, Set<Symbol> excluding) {
5206 while (c.getKind() == ElementKind.CLASS) {
5207 Type sup = ((ClassSymbol)c).getSuperclass();
5208 if (!sup.hasTag(CLASS) || sup.isErroneous() ||
5209 sup.tsym == syms.objectType.tsym) {
5210 return false;
5211 }
5212 // if it is a value super class it has to be abstract
5213 if (sup.isValueClass() && !excluding.contains(sup.tsym)) {
5214 return true;
5215 }
5216 c = sup.tsym;
5217 }
5218 return false;
5219 }
5220
5221 /**
5222 * Check that Externalizable class needs a public no-arg
5223 * constructor.
5224 *
5225 * Check that a Serializable class has access to the no-arg
5226 * constructor of its first nonserializable superclass.
5227 */
5228 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5229 if (isExternalizable(c.type)) {
5230 for(var sym : c.getEnclosedElements()) {
5231 if (sym.isConstructor() &&
5232 ((sym.flags() & PUBLIC) == PUBLIC)) {
5233 if (((MethodSymbol)sym).getParameters().isEmpty()) {
5234 return;
5235 }
5236 }
5237 }
5238 log.warning(LintCategory.SERIAL, tree.pos(),
5239 Warnings.ExternalizableMissingPublicNoArgCtor);
5240 } else {
5324 // Warn if serialPersistentFields is initialized to a
5325 // literal null.
5326 JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5327 if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5328 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5329 JCExpression initExpr = variableDef.init;
5330 if (initExpr != null && TreeInfo.isNull(initExpr)) {
5331 log.warning(LintCategory.SERIAL, initExpr.pos(),
5332 Warnings.SPFNullInit);
5333 }
5334 }
5335 }
5336
5337 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5338 // The "synchronized" modifier is seen in the wild on
5339 // readObject and writeObject methods and is generally
5340 // innocuous.
5341
5342 // private void writeObject(ObjectOutputStream stream) throws IOException
5343 checkPrivateNonStaticMethod(tree, method);
5344 isExpectedReturnType(tree, method, syms.voidType, true);
5345 checkOneArg(tree, e, method, syms.objectOutputStreamType);
5346 hasExpectedExceptions(tree, method, true, syms.ioExceptionType);
5347 checkExternalizable(tree, e, method);
5348 }
5349
5350 private boolean hasAppropriateWriteReplace(JCClassDecl tree, MethodSymbol method, boolean warn) {
5351 // ANY-ACCESS-MODIFIER Object writeReplace() throws
5352 // ObjectStreamException
5353
5354 // Excluding abstract, could have a more complicated
5355 // rule based on abstract-ness of the class
5356 return isConcreteInstanceMethod(tree, method, warn) &&
5357 isExpectedReturnType(tree, method, syms.objectType, warn) &&
5358 hasNoArgs(tree, method, warn) &&
5359 hasExpectedExceptions(tree, method, warn, syms.objectStreamExceptionType);
5360 }
5361
5362 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5363 // The "synchronized" modifier is seen in the wild on
5364 // readObject and writeObject methods and is generally
5365 // innocuous.
5366
5367 // private void readObject(ObjectInputStream stream)
5368 // throws IOException, ClassNotFoundException
5369 checkPrivateNonStaticMethod(tree, method);
5370 isExpectedReturnType(tree, method, syms.voidType, true);
5371 checkOneArg(tree, e, method, syms.objectInputStreamType);
5372 hasExpectedExceptions(tree, method, true, syms.ioExceptionType, syms.classNotFoundExceptionType);
5373 checkExternalizable(tree, e, method);
5374 }
5375
5376 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5377 // private void readObjectNoData() throws ObjectStreamException
5378 checkPrivateNonStaticMethod(tree, method);
5379 isExpectedReturnType(tree, method, syms.voidType, true);
5380 hasNoArgs(tree, method, true);
5381 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5382 checkExternalizable(tree, e, method);
5383 }
5384
5385 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5386 // ANY-ACCESS-MODIFIER Object readResolve()
5387 // throws ObjectStreamException
5388
5389 // Excluding abstract, could have a more complicated
5390 // rule based on abstract-ness of the class
5391 isConcreteInstanceMethod(tree, method, true);
5392 isExpectedReturnType(tree, method, syms.objectType, true);
5393 hasNoArgs(tree, method, true);
5394 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5395 }
5396
5397 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5398 //public void writeExternal(ObjectOutput) throws IOException
5399 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5400 }
5401
5402 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5403 // public void readExternal(ObjectInput) throws IOException
5404 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5405 }
5406
5407 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5408 boolean isExtern) {
5409 if (isExtern && isExternMethod(tree, e, method, argType)) {
5410 log.warning(LintCategory.SERIAL,
5411 TreeInfo.diagnosticPositionFor(method, tree),
5412 Warnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5413 }
5414 }
5624 case FIELD -> {
5625 var field = (VarSymbol)enclosed;
5626 switch(name) {
5627 case "serialPersistentFields" -> {
5628 log.warning(LintCategory.SERIAL,
5629 TreeInfo.diagnosticPositionFor(field, tree),
5630 Warnings.IneffectualSerialFieldRecord);
5631 }
5632
5633 case "serialVersionUID" -> {
5634 // Could generate additional warning that
5635 // svuid value is not checked to match for
5636 // records.
5637 checkSerialVersionUID(tree, e, field);
5638 }}
5639 }
5640
5641 case METHOD -> {
5642 var method = (MethodSymbol)enclosed;
5643 switch(name) {
5644 case "writeReplace" -> hasAppropriateWriteReplace(tree, method, true);
5645 case "readResolve" -> checkReadResolve(tree, e, method);
5646
5647 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5648 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern);
5649
5650 default -> {
5651 if (serialMethodNames.contains(name)) {
5652 log.warning(LintCategory.SERIAL,
5653 TreeInfo.diagnosticPositionFor(method, tree),
5654 Warnings.IneffectualSerialMethodRecord(name));
5655 }
5656 }}
5657 }}});
5658 }
5659 return null;
5660 }
5661
5662 boolean isConcreteInstanceMethod(JCClassDecl tree,
5663 MethodSymbol method,
5664 boolean warn) {
5665 if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5666 if (warn) {
5667 log.warning(LintCategory.SERIAL,
5668 TreeInfo.diagnosticPositionFor(method, tree),
5669 Warnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5670 }
5671 return false;
5672 }
5673 return true;
5674 }
5675
5676 private boolean isExpectedReturnType(JCClassDecl tree,
5677 MethodSymbol method,
5678 Type expectedReturnType,
5679 boolean warn) {
5680 // Note: there may be complications checking writeReplace
5681 // and readResolve since they return Object and could, in
5682 // principle, have covariant overrides and any synthetic
5683 // bridge method would not be represented here for
5684 // checking.
5685 Type rtype = method.getReturnType();
5686 if (!types.isSameType(expectedReturnType, rtype)) {
5687 if (warn) {
5688 log.warning(LintCategory.SERIAL,
5689 TreeInfo.diagnosticPositionFor(method, tree),
5690 Warnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5691 rtype, expectedReturnType));
5692 }
5693 return false;
5694 }
5695 return true;
5696 }
5697
5698 private void checkOneArg(JCClassDecl tree,
5699 Element enclosing,
5700 MethodSymbol method,
5701 Type expectedType) {
5702 String name = method.getSimpleName().toString();
5703
5704 var parameters= method.getParameters();
5705
5706 if (parameters.size() != 1) {
5707 log.warning(LintCategory.SERIAL,
5708 TreeInfo.diagnosticPositionFor(method, tree),
5709 Warnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5710 return;
5711 }
5712
5713 Type parameterType = parameters.get(0).asType();
5714 if (!types.isSameType(parameterType, expectedType)) {
5715 log.warning(LintCategory.SERIAL,
5716 TreeInfo.diagnosticPositionFor(method, tree),
5717 Warnings.SerialMethodParameterType(method.getSimpleName(),
5718 expectedType,
5719 parameterType));
5720 }
5721 }
5722
5723 private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5724 Element enclosing,
5725 MethodSymbol method,
5726 Type expectedType) {
5727 var parameters = method.getParameters();
5728 return (parameters.size() == 1) &&
5729 types.isSameType(parameters.get(0).asType(), expectedType);
5730 }
5731
5732
5733 boolean hasNoArgs(JCClassDecl tree, MethodSymbol method, boolean warn) {
5734 var parameters = method.getParameters();
5735 if (!parameters.isEmpty()) {
5736 if (warn) {
5737 log.warning(LintCategory.SERIAL,
5738 TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5739 Warnings.SerialMethodNoArgs(method.getSimpleName()));
5740 }
5741 return false;
5742 }
5743 return true;
5744 }
5745
5746 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5747 // If the enclosing class is externalizable, warn for the method
5748 if (isExternalizable((Type)enclosing.asType())) {
5749 log.warning(LintCategory.SERIAL,
5750 TreeInfo.diagnosticPositionFor(method, tree),
5751 Warnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5752 }
5753 return;
5754 }
5755
5756 private boolean hasExpectedExceptions(JCClassDecl tree,
5757 MethodSymbol method,
5758 boolean warn,
5759 Type... declaredExceptions) {
5760 for (Type thrownType: method.getThrownTypes()) {
5761 // For each exception in the throws clause of the
5762 // method, if not an Error and not a RuntimeException,
5763 // check if the exception is a subtype of a declared
5764 // exception from the throws clause of the
5765 // serialization method in question.
5766 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5767 types.isSubtype(thrownType, syms.errorType) ) {
5768 continue;
5769 } else {
5770 boolean declared = false;
5771 for (Type declaredException : declaredExceptions) {
5772 if (types.isSubtype(thrownType, declaredException)) {
5773 declared = true;
5774 continue;
5775 }
5776 }
5777 if (!declared) {
5778 if (warn) {
5779 log.warning(LintCategory.SERIAL,
5780 TreeInfo.diagnosticPositionFor(method, tree),
5781 Warnings.SerialMethodUnexpectedException(method.getSimpleName(),
5782 thrownType));
5783 }
5784 return false;
5785 }
5786 }
5787 }
5788 return true;
5789 }
5790
5791 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5792 Lint prevLint = lint;
5793 try {
5794 lint = lint.augment((Symbol) symbol);
5795
5796 if (lint.isEnabled(LintCategory.SERIAL)) {
5797 task.accept(symbol, p);
5798 }
5799
5800 return null;
5801 } finally {
5802 lint = prevLint;
5803 }
5804 }
5805
5806 }
5807
5808 }
|