150 diags = JCDiagnostic.Factory.instance(context);
151 Options options = Options.instance(context);
152 lint = Lint.instance(context);
153 fileManager = context.get(JavaFileManager.class);
154
155 source = Source.instance(context);
156 target = Target.instance(context);
157 warnOnAnyAccessToMembers = options.isSet("warnOnAccessToMembers");
158
159 disablePreviewCheck = false;
160
161 Target target = Target.instance(context);
162 syntheticNameChar = target.syntheticNameChar();
163
164 profile = Profile.instance(context);
165 preview = Preview.instance(context);
166
167 allowModules = Feature.MODULES.allowedInSource(source);
168 allowRecords = Feature.RECORDS.allowedInSource(source);
169 allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
170 }
171
172 /** Character for synthetic names
173 */
174 char syntheticNameChar;
175
176 /** A table mapping flat names of all compiled classes for each module in this run
177 * to their symbols; maintained from outside.
178 */
179 private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
180
181 /** Are modules allowed
182 */
183 private final boolean allowModules;
184
185 /** Are records allowed
186 */
187 private final boolean allowRecords;
188
189 /** Are sealed classes allowed
190 */
191 private final boolean allowSealed;
192
193 /** Whether to force suppression of deprecation and preview warnings.
194 * This happens when attributing import statements for JDK 9+.
195 * @see Feature#DEPRECATION_ON_IMPORT
196 */
197 private boolean importSuppression;
198
199 /* *************************************************************************
200 * Errors and Warnings
201 **************************************************************************/
202
203 Lint setLint(Lint newLint) {
204 Lint prev = lint;
205 lint = newLint;
206 return prev;
207 }
208
209 boolean setImportSuppression(boolean newImportSuppression) {
210 boolean prev = importSuppression;
211 importSuppression = newImportSuppression;
212 return prev;
650 /** Check that type is a class or interface type.
651 * @param pos Position to be used for error reporting.
652 * @param t The type to be checked.
653 */
654 Type checkClassType(DiagnosticPosition pos, Type t) {
655 if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
656 return typeTagError(pos,
657 diags.fragment(Fragments.TypeReqClass),
658 asTypeParam(t));
659 } else {
660 return t;
661 }
662 }
663 //where
664 private Object asTypeParam(Type t) {
665 return (t.hasTag(TYPEVAR))
666 ? diags.fragment(Fragments.TypeParameter(t))
667 : t;
668 }
669
670 /** Check that type is a valid qualifier for a constructor reference expression
671 */
672 Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
673 t = checkClassOrArrayType(pos, t);
674 if (t.hasTag(CLASS)) {
675 if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
676 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
677 t = types.createErrorType(t);
678 } else if ((t.tsym.flags() & ENUM) != 0) {
679 log.error(pos, Errors.EnumCantBeInstantiated);
680 t = types.createErrorType(t);
681 } else {
682 t = checkClassType(pos, t, true);
683 }
684 } else if (t.hasTag(ARRAY)) {
685 if (!types.isReifiable(((ArrayType)t).elemtype)) {
686 log.error(pos, Errors.GenericArrayCreation);
687 t = types.createErrorType(t);
688 }
689 }
707 args = args.tail;
708 }
709 }
710 return t;
711 }
712
713 /** Check that type is a reference type, i.e. a class, interface or array type
714 * or a type variable.
715 * @param pos Position to be used for error reporting.
716 * @param t The type to be checked.
717 */
718 Type checkRefType(DiagnosticPosition pos, Type t) {
719 if (t.isReference())
720 return t;
721 else
722 return typeTagError(pos,
723 diags.fragment(Fragments.TypeReqRef),
724 t);
725 }
726
727 /** Check that each type is a reference type, i.e. a class, interface or array type
728 * or a type variable.
729 * @param trees Original trees, used for error reporting.
730 * @param types The types to be checked.
731 */
732 List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
733 List<JCExpression> tl = trees;
734 for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
735 l.head = checkRefType(tl.head.pos(), l.head);
736 tl = tl.tail;
737 }
738 return types;
739 }
740
741 /** Check that type is a null or reference type.
742 * @param pos Position to be used for error reporting.
743 * @param t The type to be checked.
744 */
745 Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
746 if (t.isReference() || t.hasTag(BOT))
1098 * Warning: we can't use flags() here since this method
1099 * is called during class enter, when flags() would cause a premature
1100 * completion.
1101 * @param flags The set of modifiers given in a definition.
1102 * @param sym The defined symbol.
1103 * @param tree The declaration
1104 */
1105 long checkFlags(long flags, Symbol sym, JCTree tree) {
1106 final DiagnosticPosition pos = tree.pos();
1107 long mask;
1108 long implicit = 0;
1109
1110 switch (sym.kind) {
1111 case VAR:
1112 if (TreeInfo.isReceiverParam(tree))
1113 mask = ReceiverParamFlags;
1114 else if (sym.owner.kind != TYP)
1115 mask = LocalVarFlags;
1116 else if ((sym.owner.flags_field & INTERFACE) != 0)
1117 mask = implicit = InterfaceVarFlags;
1118 else
1119 mask = VarFlags;
1120 break;
1121 case MTH:
1122 if (sym.name == names.init) {
1123 if ((sym.owner.flags_field & ENUM) != 0) {
1124 // enum constructors cannot be declared public or
1125 // protected and must be implicitly or explicitly
1126 // private
1127 implicit = PRIVATE;
1128 mask = PRIVATE;
1129 } else
1130 mask = ConstructorFlags;
1131 } else if ((sym.owner.flags_field & INTERFACE) != 0) {
1132 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1133 mask = AnnotationTypeElementMask;
1134 implicit = PUBLIC | ABSTRACT;
1135 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1136 mask = InterfaceMethodMask;
1137 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1138 if ((flags & DEFAULT) != 0) {
1139 implicit |= ABSTRACT;
1140 }
1141 } else {
1142 mask = implicit = InterfaceMethodFlags;
1143 }
1144 } else if ((sym.owner.flags_field & RECORD) != 0) {
1145 mask = RecordMethodFlags;
1146 } else {
1147 mask = MethodFlags;
1148 }
1149 if ((flags & STRICTFP) != 0) {
1150 log.warning(tree.pos(), LintWarnings.Strictfp);
1151 }
1152 // Imply STRICTFP if owner has STRICTFP set.
1153 if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1154 ((flags) & Flags.DEFAULT) != 0)
1155 implicit |= sym.owner.flags_field & STRICTFP;
1156 break;
1157 case TYP:
1158 if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1159 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1160 boolean implicitlyStatic = !sym.isAnonymous() &&
1161 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1162 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1163 // local statics are allowed only if records are allowed too
1164 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? StaticLocalFlags : LocalClassFlags;
1165 implicit = implicitlyStatic ? STATIC : implicit;
1166 } else if (sym.owner.kind == TYP) {
1167 // statics in inner classes are allowed only if records are allowed too
1168 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1169 if (sym.owner.owner.kind == PCK ||
1170 (sym.owner.flags_field & STATIC) != 0) {
1171 mask |= STATIC;
1172 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1173 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1174 }
1175 // Nested interfaces and enums are always STATIC (Spec ???)
1176 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1177 } else {
1178 mask = ExtendedClassFlags;
1179 }
1180 // Interfaces are always ABSTRACT
1181 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1182
1183 if ((flags & ENUM) != 0) {
1184 // enums can't be declared abstract, final, sealed or non-sealed
1185 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
1186 implicit |= implicitEnumFinalFlag(tree);
1187 }
1188 if ((flags & RECORD) != 0) {
1189 // records can't be declared abstract
1190 mask &= ~ABSTRACT;
1191 implicit |= FINAL;
1192 }
1193 if ((flags & STRICTFP) != 0) {
1194 log.warning(tree.pos(), LintWarnings.Strictfp);
1195 }
1196 // Imply STRICTFP if owner has STRICTFP set.
1197 implicit |= sym.owner.flags_field & STRICTFP;
1198 break;
1199 default:
1200 throw new AssertionError();
1201 }
1202 long illegal = flags & ExtendedStandardFlags & ~mask;
1203 if (illegal != 0) {
1204 if ((illegal & INTERFACE) != 0) {
1205 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1206 mask |= INTERFACE;
1207 }
1208 else {
1209 log.error(pos,
1210 Errors.ModNotAllowedHere(asFlagSet(illegal)));
1211 }
1212 }
1213 else if ((sym.kind == TYP ||
1214 // ISSUE: Disallowing abstract&private is no longer appropriate
1215 // in the presence of inner classes. Should it be deleted here?
1216 checkDisjoint(pos, flags,
1217 ABSTRACT,
1218 PRIVATE | STATIC | DEFAULT))
1219 &&
1220 checkDisjoint(pos, flags,
1221 STATIC | PRIVATE,
1222 DEFAULT)
1223 &&
1224 checkDisjoint(pos, flags,
1225 ABSTRACT | INTERFACE,
1226 FINAL | NATIVE | SYNCHRONIZED)
1227 &&
1228 checkDisjoint(pos, flags,
1229 PUBLIC,
1230 PRIVATE | PROTECTED)
1231 &&
1232 checkDisjoint(pos, flags,
1233 PRIVATE,
1234 PUBLIC | PROTECTED)
1235 &&
1236 checkDisjoint(pos, flags,
1237 FINAL,
1238 VOLATILE)
1239 &&
1240 (sym.kind == TYP ||
1241 checkDisjoint(pos, flags,
1242 ABSTRACT | NATIVE,
1243 STRICTFP))
1244 && checkDisjoint(pos, flags,
1245 FINAL,
1246 SEALED | NON_SEALED)
1247 && checkDisjoint(pos, flags,
1248 SEALED,
1249 FINAL | NON_SEALED)
1250 && checkDisjoint(pos, flags,
1251 SEALED,
1252 ANNOTATION)) {
1253 // skip
1254 }
1255 return flags & (mask | ~ExtendedStandardFlags) | implicit;
1256 }
1257
1258 /** Determine if this enum should be implicitly final.
1259 *
1260 * If the enum has no specialized enum constants, it is final.
1261 *
1262 * If the enum does have specialized enum constants, it is
1263 * <i>not</i> final.
1264 */
1265 private long implicitEnumFinalFlag(JCTree tree) {
1266 if (!tree.hasTag(CLASSDEF)) return 0;
1267 class SpecialTreeVisitor extends JCTree.Visitor {
1268 boolean specialized;
1269 SpecialTreeVisitor() {
1270 this.specialized = false;
1271 }
1272
2029 return true;
2030 }
2031 }
2032 }
2033 return false;
2034 }
2035
2036 /** Check that a given method conforms with any method it overrides.
2037 * @param tree The tree from which positions are extracted
2038 * for errors.
2039 * @param m The overriding method.
2040 */
2041 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2042 ClassSymbol origin = (ClassSymbol)m.owner;
2043 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2044 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2045 log.error(tree.pos(), Errors.EnumNoFinalize);
2046 return;
2047 }
2048 }
2049 if (allowRecords && origin.isRecord()) {
2050 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2051 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2052 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2053 if (recordComponent.isPresent()) {
2054 return;
2055 }
2056 }
2057
2058 for (Type t = origin.type; t.hasTag(CLASS);
2059 t = types.supertype(t)) {
2060 if (t != origin.type) {
2061 checkOverride(tree, t, origin, m);
2062 }
2063 for (Type t2 : types.interfaces(t)) {
2064 checkOverride(tree, t2, origin, m);
2065 }
2066 }
2067
2068 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
2464 /** Check that all abstract methods implemented by a class are
2465 * mutually compatible.
2466 * @param pos Position to be used for error reporting.
2467 * @param c The class whose interfaces are checked.
2468 */
2469 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2470 List<Type> supertypes = types.interfaces(c);
2471 Type supertype = types.supertype(c);
2472 if (supertype.hasTag(CLASS) &&
2473 (supertype.tsym.flags() & ABSTRACT) != 0)
2474 supertypes = supertypes.prepend(supertype);
2475 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2476 if (!l.head.getTypeArguments().isEmpty() &&
2477 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2478 return;
2479 for (List<Type> m = supertypes; m != l; m = m.tail)
2480 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2481 return;
2482 }
2483 checkCompatibleConcretes(pos, c);
2484 }
2485
2486 /** Check that all non-override equivalent methods accessible from 'site'
2487 * are mutually compatible (JLS 8.4.8/9.4.1).
2488 *
2489 * @param pos Position to be used for error reporting.
2490 * @param site The class whose methods are checked.
2491 * @param sym The method symbol to be checked.
2492 */
2493 void checkOverrideClashes(DiagnosticPosition pos, Type site, MethodSymbol sym) {
2494 ClashFilter cf = new ClashFilter(site);
2495 //for each method m1 that is overridden (directly or indirectly)
2496 //by method 'sym' in 'site'...
2497
2498 ArrayList<Symbol> symbolsByName = new ArrayList<>();
2499 types.membersClosure(site, false).getSymbolsByName(sym.name, cf).forEach(symbolsByName::add);
2500 for (Symbol m1 : symbolsByName) {
2501 if (!sym.overrides(m1, site.tsym, types, false)) {
2502 continue;
2503 }
4797 }
4798 } else {
4799 Assert.error("Unknown pattern: " + currentPattern.getTag());
4800 }
4801 return false;
4802 }
4803
4804 /** check if a type is a subtype of Externalizable, if that is available. */
4805 boolean isExternalizable(Type t) {
4806 try {
4807 syms.externalizableType.complete();
4808 } catch (CompletionFailure e) {
4809 return false;
4810 }
4811 return types.isSubtype(t, syms.externalizableType);
4812 }
4813
4814 /**
4815 * Check structure of serialization declarations.
4816 */
4817 public void checkSerialStructure(JCClassDecl tree, ClassSymbol c) {
4818 (new SerialTypeVisitor()).visit(c, tree);
4819 }
4820
4821 /**
4822 * This visitor will warn if a serialization-related field or
4823 * method is declared in a suspicious or incorrect way. In
4824 * particular, it will warn for cases where the runtime
4825 * serialization mechanism will silently ignore a mis-declared
4826 * entity.
4827 *
4828 * Distinguished serialization-related fields and methods:
4829 *
4830 * Methods:
4831 *
4832 * private void writeObject(ObjectOutputStream stream) throws IOException
4833 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
4834 *
4835 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
4836 * private void readObjectNoData() throws ObjectStreamException
4837 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
4838 *
4839 * Fields:
4840 *
4841 * private static final long serialVersionUID
4842 * private static final ObjectStreamField[] serialPersistentFields
4843 *
4844 * Externalizable: methods defined on the interface
4845 * public void writeExternal(ObjectOutput) throws IOException
4846 * public void readExternal(ObjectInput) throws IOException
4847 */
4848 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
4849 SerialTypeVisitor() {
4850 this.lint = Check.this.lint;
4851 }
4852
4853 private static final Set<String> serialMethodNames =
4854 Set.of("writeObject", "writeReplace",
4855 "readObject", "readObjectNoData",
4856 "readResolve");
4857
4858 private static final Set<String> serialFieldNames =
4859 Set.of("serialVersionUID", "serialPersistentFields");
4860
4861 // Type of serialPersistentFields
4862 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
4863
4864 Lint lint;
4865
4866 @Override
4867 public Void defaultAction(Element e, JCClassDecl p) {
4868 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
4869 }
4870
4890 if (sym.kind == VAR) {
4891 svuidSym = (VarSymbol)sym;
4892 break;
4893 }
4894 }
4895
4896 if (svuidSym == null) {
4897 log.warning(p.pos(), LintWarnings.MissingSVUID(c));
4898 }
4899
4900 // Check for serialPersistentFields to gate checks for
4901 // non-serializable non-transient instance fields
4902 boolean serialPersistentFieldsPresent =
4903 c.members()
4904 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
4905 .iterator()
4906 .hasNext();
4907
4908 // Check declarations of serialization-related methods and
4909 // fields
4910 for(Symbol el : c.getEnclosedElements()) {
4911 runUnderLint(el, p, (enclosed, tree) -> {
4912 String name = null;
4913 switch(enclosed.getKind()) {
4914 case FIELD -> {
4915 if (!serialPersistentFieldsPresent) {
4916 var flags = enclosed.flags();
4917 if ( ((flags & TRANSIENT) == 0) &&
4918 ((flags & STATIC) == 0)) {
4919 Type varType = enclosed.asType();
4920 if (!canBeSerialized(varType)) {
4921 // Note per JLS arrays are
4922 // serializable even if the
4923 // component type is not.
4924 log.warning(
4925 TreeInfo.diagnosticPositionFor(enclosed, tree),
4926 LintWarnings.NonSerializableInstanceField);
4927 } else if (varType.hasTag(ARRAY)) {
4928 ArrayType arrayType = (ArrayType)varType;
4929 Type elementType = arrayType.elemtype;
4964 // will also pull in default methods from
4965 // superinterfaces. In other words, the runtime checks
4966 // (which long predate default methods on interfaces)
4967 // do not admit the possibility of inheriting methods
4968 // this way, a difference from general inheritance.
4969
4970 // The current implementation just checks the enclosed
4971 // elements and does not directly check the inherited
4972 // methods. If all the types are being checked this is
4973 // less of a concern; however, there are cases that
4974 // could be missed. In particular, readResolve and
4975 // writeReplace could, in principle, by inherited from
4976 // a non-serializable superclass and thus not checked
4977 // even if compiled with a serializable child class.
4978 case METHOD -> {
4979 var method = (MethodSymbol)enclosed;
4980 name = method.getSimpleName().toString();
4981 if (serialMethodNames.contains(name)) {
4982 switch (name) {
4983 case "writeObject" -> checkWriteObject(tree, e, method);
4984 case "writeReplace" -> checkWriteReplace(tree,e, method);
4985 case "readObject" -> checkReadObject(tree,e, method);
4986 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
4987 case "readResolve" -> checkReadResolve(tree, e, method);
4988 default -> throw new AssertionError();
4989 }
4990 }
4991 }
4992 }
4993 });
4994 }
4995
4996 return null;
4997 }
4998
4999 boolean canBeSerialized(Type type) {
5000 return type.isPrimitive() || rs.isSerializable(type);
5001 }
5002
5003 /**
5004 * Check that Externalizable class needs a public no-arg
5005 * constructor.
5006 *
5007 * Check that a Serializable class has access to the no-arg
5008 * constructor of its first nonserializable superclass.
5009 */
5010 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5011 if (isExternalizable(c.type)) {
5012 for(var sym : c.getEnclosedElements()) {
5013 if (sym.isConstructor() &&
5014 ((sym.flags() & PUBLIC) == PUBLIC)) {
5015 if (((MethodSymbol)sym).getParameters().isEmpty()) {
5016 return;
5017 }
5018 }
5019 }
5020 log.warning(tree.pos(),
5021 LintWarnings.ExternalizableMissingPublicNoArgCtor);
5022 } else {
5106 // Warn if serialPersistentFields is initialized to a
5107 // literal null.
5108 JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5109 if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5110 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5111 JCExpression initExpr = variableDef.init;
5112 if (initExpr != null && TreeInfo.isNull(initExpr)) {
5113 log.warning(initExpr.pos(),
5114 LintWarnings.SPFNullInit);
5115 }
5116 }
5117 }
5118
5119 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5120 // The "synchronized" modifier is seen in the wild on
5121 // readObject and writeObject methods and is generally
5122 // innocuous.
5123
5124 // private void writeObject(ObjectOutputStream stream) throws IOException
5125 checkPrivateNonStaticMethod(tree, method);
5126 checkReturnType(tree, e, method, syms.voidType);
5127 checkOneArg(tree, e, method, syms.objectOutputStreamType);
5128 checkExceptions(tree, e, method, syms.ioExceptionType);
5129 checkExternalizable(tree, e, method);
5130 }
5131
5132 private void checkWriteReplace(JCClassDecl tree, Element e, MethodSymbol method) {
5133 // ANY-ACCESS-MODIFIER Object writeReplace() throws
5134 // ObjectStreamException
5135
5136 // Excluding abstract, could have a more complicated
5137 // rule based on abstract-ness of the class
5138 checkConcreteInstanceMethod(tree, e, method);
5139 checkReturnType(tree, e, method, syms.objectType);
5140 checkNoArgs(tree, e, method);
5141 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5142 }
5143
5144 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5145 // The "synchronized" modifier is seen in the wild on
5146 // readObject and writeObject methods and is generally
5147 // innocuous.
5148
5149 // private void readObject(ObjectInputStream stream)
5150 // throws IOException, ClassNotFoundException
5151 checkPrivateNonStaticMethod(tree, method);
5152 checkReturnType(tree, e, method, syms.voidType);
5153 checkOneArg(tree, e, method, syms.objectInputStreamType);
5154 checkExceptions(tree, e, method, syms.ioExceptionType, syms.classNotFoundExceptionType);
5155 checkExternalizable(tree, e, method);
5156 }
5157
5158 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5159 // private void readObjectNoData() throws ObjectStreamException
5160 checkPrivateNonStaticMethod(tree, method);
5161 checkReturnType(tree, e, method, syms.voidType);
5162 checkNoArgs(tree, e, method);
5163 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5164 checkExternalizable(tree, e, method);
5165 }
5166
5167 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5168 // ANY-ACCESS-MODIFIER Object readResolve()
5169 // throws ObjectStreamException
5170
5171 // Excluding abstract, could have a more complicated
5172 // rule based on abstract-ness of the class
5173 checkConcreteInstanceMethod(tree, e, method);
5174 checkReturnType(tree,e, method, syms.objectType);
5175 checkNoArgs(tree, e, method);
5176 checkExceptions(tree, e, method, syms.objectStreamExceptionType);
5177 }
5178
5179 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5180 //public void writeExternal(ObjectOutput) throws IOException
5181 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5182 }
5183
5184 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5185 // public void readExternal(ObjectInput) throws IOException
5186 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5187 }
5188
5189 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5190 boolean isExtern) {
5191 if (isExtern && isExternMethod(tree, e, method, argType)) {
5192 log.warning(
5193 TreeInfo.diagnosticPositionFor(method, tree),
5194 LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5195 }
5196 }
5406 case FIELD -> {
5407 var field = (VarSymbol)enclosed;
5408 switch(name) {
5409 case "serialPersistentFields" -> {
5410 log.warning(
5411 TreeInfo.diagnosticPositionFor(field, tree),
5412 LintWarnings.IneffectualSerialFieldRecord);
5413 }
5414
5415 case "serialVersionUID" -> {
5416 // Could generate additional warning that
5417 // svuid value is not checked to match for
5418 // records.
5419 checkSerialVersionUID(tree, e, field);
5420 }}
5421 }
5422
5423 case METHOD -> {
5424 var method = (MethodSymbol)enclosed;
5425 switch(name) {
5426 case "writeReplace" -> checkWriteReplace(tree, e, method);
5427 case "readResolve" -> checkReadResolve(tree, e, method);
5428
5429 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5430 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern);
5431
5432 default -> {
5433 if (serialMethodNames.contains(name)) {
5434 log.warning(
5435 TreeInfo.diagnosticPositionFor(method, tree),
5436 LintWarnings.IneffectualSerialMethodRecord(name));
5437 }
5438 }}
5439 }}});
5440 }
5441 return null;
5442 }
5443
5444 void checkConcreteInstanceMethod(JCClassDecl tree,
5445 Element enclosing,
5446 MethodSymbol method) {
5447 if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5448 log.warning(
5449 TreeInfo.diagnosticPositionFor(method, tree),
5450 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5451 }
5452 }
5453
5454 private void checkReturnType(JCClassDecl tree,
5455 Element enclosing,
5456 MethodSymbol method,
5457 Type expectedReturnType) {
5458 // Note: there may be complications checking writeReplace
5459 // and readResolve since they return Object and could, in
5460 // principle, have covariant overrides and any synthetic
5461 // bridge method would not be represented here for
5462 // checking.
5463 Type rtype = method.getReturnType();
5464 if (!types.isSameType(expectedReturnType, rtype)) {
5465 log.warning(
5466 TreeInfo.diagnosticPositionFor(method, tree),
5467 LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5468 rtype, expectedReturnType));
5469 }
5470 }
5471
5472 private void checkOneArg(JCClassDecl tree,
5473 Element enclosing,
5474 MethodSymbol method,
5475 Type expectedType) {
5476 String name = method.getSimpleName().toString();
5477
5478 var parameters= method.getParameters();
5479
5480 if (parameters.size() != 1) {
5481 log.warning(
5482 TreeInfo.diagnosticPositionFor(method, tree),
5483 LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5484 return;
5485 }
5486
5487 Type parameterType = parameters.get(0).asType();
5488 if (!types.isSameType(parameterType, expectedType)) {
5489 log.warning(
5490 TreeInfo.diagnosticPositionFor(method, tree),
5491 LintWarnings.SerialMethodParameterType(method.getSimpleName(),
5492 expectedType,
5493 parameterType));
5494 }
5495 }
5496
5497 private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5498 Element enclosing,
5499 MethodSymbol method,
5500 Type expectedType) {
5501 var parameters = method.getParameters();
5502 return (parameters.size() == 1) &&
5503 types.isSameType(parameters.get(0).asType(), expectedType);
5504 }
5505
5506
5507 private void checkNoArgs(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5508 var parameters = method.getParameters();
5509 if (!parameters.isEmpty()) {
5510 log.warning(
5511 TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5512 LintWarnings.SerialMethodNoArgs(method.getSimpleName()));
5513 }
5514 }
5515
5516 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5517 // If the enclosing class is externalizable, warn for the method
5518 if (isExternalizable((Type)enclosing.asType())) {
5519 log.warning(
5520 TreeInfo.diagnosticPositionFor(method, tree),
5521 LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5522 }
5523 return;
5524 }
5525
5526 private void checkExceptions(JCClassDecl tree,
5527 Element enclosing,
5528 MethodSymbol method,
5529 Type... declaredExceptions) {
5530 for (Type thrownType: method.getThrownTypes()) {
5531 // For each exception in the throws clause of the
5532 // method, if not an Error and not a RuntimeException,
5533 // check if the exception is a subtype of a declared
5534 // exception from the throws clause of the
5535 // serialization method in question.
5536 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5537 types.isSubtype(thrownType, syms.errorType) ) {
5538 continue;
5539 } else {
5540 boolean declared = false;
5541 for (Type declaredException : declaredExceptions) {
5542 if (types.isSubtype(thrownType, declaredException)) {
5543 declared = true;
5544 continue;
5545 }
5546 }
5547 if (!declared) {
5548 log.warning(
5549 TreeInfo.diagnosticPositionFor(method, tree),
5550 LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5551 thrownType));
5552 }
5553 }
5554 }
5555 return;
5556 }
5557
5558 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5559 Lint prevLint = lint;
5560 try {
5561 lint = lint.augment((Symbol) symbol);
5562
5563 if (lint.isEnabled(LintCategory.SERIAL)) {
5564 task.accept(symbol, p);
5565 }
5566
5567 return null;
5568 } finally {
5569 lint = prevLint;
5570 }
5571 }
5572
5573 }
5574
5575 void checkRequiresIdentity(JCTree tree, Lint lint) {
|
150 diags = JCDiagnostic.Factory.instance(context);
151 Options options = Options.instance(context);
152 lint = Lint.instance(context);
153 fileManager = context.get(JavaFileManager.class);
154
155 source = Source.instance(context);
156 target = Target.instance(context);
157 warnOnAnyAccessToMembers = options.isSet("warnOnAccessToMembers");
158
159 disablePreviewCheck = false;
160
161 Target target = Target.instance(context);
162 syntheticNameChar = target.syntheticNameChar();
163
164 profile = Profile.instance(context);
165 preview = Preview.instance(context);
166
167 allowModules = Feature.MODULES.allowedInSource(source);
168 allowRecords = Feature.RECORDS.allowedInSource(source);
169 allowSealed = Feature.SEALED_CLASSES.allowedInSource(source);
170 allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
171 Feature.VALUE_CLASSES.allowedInSource(source);
172 }
173
174 /** Character for synthetic names
175 */
176 char syntheticNameChar;
177
178 /** A table mapping flat names of all compiled classes for each module in this run
179 * to their symbols; maintained from outside.
180 */
181 private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
182
183 /** Are modules allowed
184 */
185 private final boolean allowModules;
186
187 /** Are records allowed
188 */
189 private final boolean allowRecords;
190
191 /** Are sealed classes allowed
192 */
193 private final boolean allowSealed;
194
195 /** Are value classes allowed
196 */
197 private final boolean allowValueClasses;
198
199 /** Whether to force suppression of deprecation and preview warnings.
200 * This happens when attributing import statements for JDK 9+.
201 * @see Feature#DEPRECATION_ON_IMPORT
202 */
203 private boolean importSuppression;
204
205 /* *************************************************************************
206 * Errors and Warnings
207 **************************************************************************/
208
209 Lint setLint(Lint newLint) {
210 Lint prev = lint;
211 lint = newLint;
212 return prev;
213 }
214
215 boolean setImportSuppression(boolean newImportSuppression) {
216 boolean prev = importSuppression;
217 importSuppression = newImportSuppression;
218 return prev;
656 /** Check that type is a class or interface type.
657 * @param pos Position to be used for error reporting.
658 * @param t The type to be checked.
659 */
660 Type checkClassType(DiagnosticPosition pos, Type t) {
661 if (!t.hasTag(CLASS) && !t.hasTag(ERROR)) {
662 return typeTagError(pos,
663 diags.fragment(Fragments.TypeReqClass),
664 asTypeParam(t));
665 } else {
666 return t;
667 }
668 }
669 //where
670 private Object asTypeParam(Type t) {
671 return (t.hasTag(TYPEVAR))
672 ? diags.fragment(Fragments.TypeParameter(t))
673 : t;
674 }
675
676 void checkConstraintsOfValueClass(JCClassDecl tree, ClassSymbol c) {
677 DiagnosticPosition pos = tree.pos();
678 for (Type st : types.closure(c.type)) {
679 if (st == null || st.tsym == null || st.tsym.kind == ERR)
680 continue;
681 if (st.tsym == syms.objectType.tsym || st.tsym == syms.recordType.tsym || st.isInterface())
682 continue;
683 if (!st.tsym.isAbstract()) {
684 if (c != st.tsym) {
685 log.error(pos, Errors.ConcreteSupertypeForValueClass(c, st));
686 }
687 continue;
688 }
689 // dealing with an abstract value or value super class below.
690 for (Symbol s : st.tsym.members().getSymbols(NON_RECURSIVE)) {
691 if (s.kind == MTH) {
692 if ((s.flags() & (SYNCHRONIZED | STATIC)) == SYNCHRONIZED) {
693 log.error(pos, Errors.SuperClassMethodCannotBeSynchronized(s, c, st));
694 }
695 break;
696 }
697 }
698 }
699 }
700
701 /** Check that type is a valid qualifier for a constructor reference expression
702 */
703 Type checkConstructorRefType(DiagnosticPosition pos, Type t) {
704 t = checkClassOrArrayType(pos, t);
705 if (t.hasTag(CLASS)) {
706 if ((t.tsym.flags() & (ABSTRACT | INTERFACE)) != 0) {
707 log.error(pos, Errors.AbstractCantBeInstantiated(t.tsym));
708 t = types.createErrorType(t);
709 } else if ((t.tsym.flags() & ENUM) != 0) {
710 log.error(pos, Errors.EnumCantBeInstantiated);
711 t = types.createErrorType(t);
712 } else {
713 t = checkClassType(pos, t, true);
714 }
715 } else if (t.hasTag(ARRAY)) {
716 if (!types.isReifiable(((ArrayType)t).elemtype)) {
717 log.error(pos, Errors.GenericArrayCreation);
718 t = types.createErrorType(t);
719 }
720 }
738 args = args.tail;
739 }
740 }
741 return t;
742 }
743
744 /** Check that type is a reference type, i.e. a class, interface or array type
745 * or a type variable.
746 * @param pos Position to be used for error reporting.
747 * @param t The type to be checked.
748 */
749 Type checkRefType(DiagnosticPosition pos, Type t) {
750 if (t.isReference())
751 return t;
752 else
753 return typeTagError(pos,
754 diags.fragment(Fragments.TypeReqRef),
755 t);
756 }
757
758 /** Check that type is an identity type, i.e. not a value type.
759 * When not discernible statically, give it the benefit of doubt
760 * and defer to runtime.
761 *
762 * @param pos Position to be used for error reporting.
763 * @param t The type to be checked.
764 */
765 boolean checkIdentityType(DiagnosticPosition pos, Type t) {
766 if (t.hasTag(TYPEVAR)) {
767 t = types.skipTypeVars(t, false);
768 }
769 if (t.isIntersection()) {
770 IntersectionClassType ict = (IntersectionClassType)t;
771 boolean result = true;
772 for (Type component : ict.getExplicitComponents()) {
773 result &= checkIdentityType(pos, component);
774 }
775 return result;
776 }
777 if (t.isPrimitive() || (t.isValueClass() && !t.tsym.isAbstract())) {
778 typeTagError(pos, diags.fragment(Fragments.TypeReqIdentity), t);
779 return false;
780 }
781 return true;
782 }
783
784 /** Check that each type is a reference type, i.e. a class, interface or array type
785 * or a type variable.
786 * @param trees Original trees, used for error reporting.
787 * @param types The types to be checked.
788 */
789 List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
790 List<JCExpression> tl = trees;
791 for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
792 l.head = checkRefType(tl.head.pos(), l.head);
793 tl = tl.tail;
794 }
795 return types;
796 }
797
798 /** Check that type is a null or reference type.
799 * @param pos Position to be used for error reporting.
800 * @param t The type to be checked.
801 */
802 Type checkNullOrRefType(DiagnosticPosition pos, Type t) {
803 if (t.isReference() || t.hasTag(BOT))
1155 * Warning: we can't use flags() here since this method
1156 * is called during class enter, when flags() would cause a premature
1157 * completion.
1158 * @param flags The set of modifiers given in a definition.
1159 * @param sym The defined symbol.
1160 * @param tree The declaration
1161 */
1162 long checkFlags(long flags, Symbol sym, JCTree tree) {
1163 final DiagnosticPosition pos = tree.pos();
1164 long mask;
1165 long implicit = 0;
1166
1167 switch (sym.kind) {
1168 case VAR:
1169 if (TreeInfo.isReceiverParam(tree))
1170 mask = ReceiverParamFlags;
1171 else if (sym.owner.kind != TYP)
1172 mask = LocalVarFlags;
1173 else if ((sym.owner.flags_field & INTERFACE) != 0)
1174 mask = implicit = InterfaceVarFlags;
1175 else {
1176 boolean isInstanceField = (flags & STATIC) == 0;
1177 boolean isInstanceFieldOfValueClass = isInstanceField && sym.owner.type.isValueClass();
1178 boolean isRecordField = isInstanceField && (sym.owner.flags_field & RECORD) != 0;
1179 if (allowValueClasses && (isInstanceFieldOfValueClass || isRecordField)) {
1180 implicit |= FINAL | STRICT;
1181 mask = ValueFieldFlags;
1182 } else {
1183 mask = VarFlags;
1184 }
1185 }
1186 break;
1187 case MTH:
1188 if (sym.name == names.init) {
1189 if ((sym.owner.flags_field & ENUM) != 0) {
1190 // enum constructors cannot be declared public or
1191 // protected and must be implicitly or explicitly
1192 // private
1193 implicit = PRIVATE;
1194 mask = PRIVATE;
1195 } else
1196 mask = ConstructorFlags;
1197 } else if ((sym.owner.flags_field & INTERFACE) != 0) {
1198 if ((sym.owner.flags_field & ANNOTATION) != 0) {
1199 mask = AnnotationTypeElementMask;
1200 implicit = PUBLIC | ABSTRACT;
1201 } else if ((flags & (DEFAULT | STATIC | PRIVATE)) != 0) {
1202 mask = InterfaceMethodMask;
1203 implicit = (flags & PRIVATE) != 0 ? 0 : PUBLIC;
1204 if ((flags & DEFAULT) != 0) {
1205 implicit |= ABSTRACT;
1206 }
1207 } else {
1208 mask = implicit = InterfaceMethodFlags;
1209 }
1210 } else if ((sym.owner.flags_field & RECORD) != 0) {
1211 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1212 RecordMethodFlags & ~SYNCHRONIZED : RecordMethodFlags;
1213 } else {
1214 // value objects do not have an associated monitor/lock
1215 mask = ((sym.owner.flags_field & VALUE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
1216 MethodFlags & ~SYNCHRONIZED : MethodFlags;
1217 }
1218 if ((flags & STRICTFP) != 0) {
1219 log.warning(tree.pos(), LintWarnings.Strictfp);
1220 }
1221 // Imply STRICTFP if owner has STRICTFP set.
1222 if (((flags|implicit) & Flags.ABSTRACT) == 0 ||
1223 ((flags) & Flags.DEFAULT) != 0)
1224 implicit |= sym.owner.flags_field & STRICTFP;
1225 break;
1226 case TYP:
1227 if (sym.owner.kind.matches(KindSelector.VAL_MTH) ||
1228 (sym.isDirectlyOrIndirectlyLocal() && (flags & ANNOTATION) != 0)) {
1229 boolean implicitlyStatic = !sym.isAnonymous() &&
1230 ((flags & RECORD) != 0 || (flags & ENUM) != 0 || (flags & INTERFACE) != 0);
1231 boolean staticOrImplicitlyStatic = (flags & STATIC) != 0 || implicitlyStatic;
1232 // local statics are allowed only if records are allowed too
1233 mask = staticOrImplicitlyStatic && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedStaticLocalClassFlags : ExtendedLocalClassFlags;
1234 implicit = implicitlyStatic ? STATIC : implicit;
1235 } else if (sym.owner.kind == TYP) {
1236 // statics in inner classes are allowed only if records are allowed too
1237 mask = ((flags & STATIC) != 0) && allowRecords && (flags & ANNOTATION) == 0 ? ExtendedMemberStaticClassFlags : ExtendedMemberClassFlags;
1238 if (sym.owner.owner.kind == PCK ||
1239 (sym.owner.flags_field & STATIC) != 0) {
1240 mask |= STATIC;
1241 } else if (!allowRecords && ((flags & ENUM) != 0 || (flags & RECORD) != 0)) {
1242 log.error(pos, Errors.StaticDeclarationNotAllowedInInnerClasses);
1243 }
1244 // Nested interfaces and enums are always STATIC (Spec ???)
1245 if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
1246 } else {
1247 mask = ExtendedClassFlags;
1248 }
1249 if ((flags & (VALUE_CLASS | SEALED | ABSTRACT)) == (VALUE_CLASS | SEALED) ||
1250 (flags & (VALUE_CLASS | NON_SEALED | ABSTRACT)) == (VALUE_CLASS | NON_SEALED)) {
1251 log.error(pos, Errors.NonAbstractValueClassCantBeSealedOrNonSealed);
1252 }
1253 // Interfaces are always ABSTRACT
1254 if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
1255
1256 if ((flags & (INTERFACE | VALUE_CLASS)) == 0) {
1257 implicit |= IDENTITY_TYPE;
1258 }
1259
1260 if ((flags & ENUM) != 0) {
1261 // enums can't be declared abstract, final, sealed or non-sealed or value
1262 mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | VALUE_CLASS);
1263 implicit |= implicitEnumFinalFlag(tree);
1264 }
1265 if ((flags & RECORD) != 0) {
1266 // records can't be declared abstract
1267 mask &= ~ABSTRACT;
1268 implicit |= FINAL;
1269 }
1270 if ((flags & STRICTFP) != 0) {
1271 log.warning(tree.pos(), LintWarnings.Strictfp);
1272 }
1273 // Imply STRICTFP if owner has STRICTFP set.
1274 implicit |= sym.owner.flags_field & STRICTFP;
1275
1276 // concrete value classes are implicitly final
1277 if ((flags & (ABSTRACT | INTERFACE | VALUE_CLASS)) == VALUE_CLASS) {
1278 implicit |= FINAL;
1279 }
1280 break;
1281 default:
1282 throw new AssertionError();
1283 }
1284 long illegal = flags & ExtendedStandardFlags & ~mask;
1285 if (illegal != 0) {
1286 if ((illegal & INTERFACE) != 0) {
1287 log.error(pos, ((flags & ANNOTATION) != 0) ? Errors.AnnotationDeclNotAllowedHere : Errors.IntfNotAllowedHere);
1288 mask |= INTERFACE;
1289 }
1290 else {
1291 log.error(pos,
1292 Errors.ModNotAllowedHere(asFlagSet(illegal)));
1293 }
1294 } else if ((sym.kind == TYP ||
1295 // ISSUE: Disallowing abstract&private is no longer appropriate
1296 // in the presence of inner classes. Should it be deleted here?
1297 checkDisjoint(pos, flags,
1298 ABSTRACT,
1299 PRIVATE | STATIC | DEFAULT))
1300 &&
1301 checkDisjoint(pos, flags,
1302 STATIC | PRIVATE,
1303 DEFAULT)
1304 &&
1305 checkDisjoint(pos, flags,
1306 ABSTRACT | INTERFACE,
1307 FINAL | NATIVE | SYNCHRONIZED)
1308 &&
1309 checkDisjoint(pos, flags,
1310 PUBLIC,
1311 PRIVATE | PROTECTED)
1312 &&
1313 checkDisjoint(pos, flags,
1314 PRIVATE,
1315 PUBLIC | PROTECTED)
1316 &&
1317 // we are using `implicit` here as instance fields of value classes are implicitly final
1318 checkDisjoint(pos, flags | implicit,
1319 FINAL,
1320 VOLATILE)
1321 &&
1322 (sym.kind == TYP ||
1323 checkDisjoint(pos, flags,
1324 ABSTRACT | NATIVE,
1325 STRICTFP))
1326 && checkDisjoint(pos, flags,
1327 FINAL,
1328 SEALED | NON_SEALED)
1329 && checkDisjoint(pos, flags,
1330 SEALED,
1331 FINAL | NON_SEALED)
1332 && checkDisjoint(pos, flags,
1333 SEALED,
1334 ANNOTATION)
1335 && checkDisjoint(pos, flags,
1336 VALUE_CLASS,
1337 ANNOTATION)
1338 && checkDisjoint(pos, flags,
1339 VALUE_CLASS,
1340 INTERFACE) ) {
1341 // skip
1342 }
1343 return flags & (mask | ~ExtendedStandardFlags) | implicit;
1344 }
1345
1346 /** Determine if this enum should be implicitly final.
1347 *
1348 * If the enum has no specialized enum constants, it is final.
1349 *
1350 * If the enum does have specialized enum constants, it is
1351 * <i>not</i> final.
1352 */
1353 private long implicitEnumFinalFlag(JCTree tree) {
1354 if (!tree.hasTag(CLASSDEF)) return 0;
1355 class SpecialTreeVisitor extends JCTree.Visitor {
1356 boolean specialized;
1357 SpecialTreeVisitor() {
1358 this.specialized = false;
1359 }
1360
2117 return true;
2118 }
2119 }
2120 }
2121 return false;
2122 }
2123
2124 /** Check that a given method conforms with any method it overrides.
2125 * @param tree The tree from which positions are extracted
2126 * for errors.
2127 * @param m The overriding method.
2128 */
2129 void checkOverride(Env<AttrContext> env, JCMethodDecl tree, MethodSymbol m) {
2130 ClassSymbol origin = (ClassSymbol)m.owner;
2131 if ((origin.flags() & ENUM) != 0 && names.finalize.equals(m.name)) {
2132 if (m.overrides(syms.enumFinalFinalize, origin, types, false)) {
2133 log.error(tree.pos(), Errors.EnumNoFinalize);
2134 return;
2135 }
2136 }
2137 if (allowValueClasses && origin.isValueClass() && names.finalize.equals(m.name)) {
2138 if (m.overrides(syms.objectFinalize, origin, types, false)) {
2139 log.warning(tree.pos(), Warnings.ValueFinalize);
2140 }
2141 }
2142 if (allowRecords && origin.isRecord()) {
2143 // let's find out if this is a user defined accessor in which case the @Override annotation is acceptable
2144 Optional<? extends RecordComponent> recordComponent = origin.getRecordComponents().stream()
2145 .filter(rc -> rc.accessor == tree.sym && (rc.accessor.flags_field & GENERATED_MEMBER) == 0).findFirst();
2146 if (recordComponent.isPresent()) {
2147 return;
2148 }
2149 }
2150
2151 for (Type t = origin.type; t.hasTag(CLASS);
2152 t = types.supertype(t)) {
2153 if (t != origin.type) {
2154 checkOverride(tree, t, origin, m);
2155 }
2156 for (Type t2 : types.interfaces(t)) {
2157 checkOverride(tree, t2, origin, m);
2158 }
2159 }
2160
2161 final boolean explicitOverride = m.attribute(syms.overrideType.tsym) != null;
2557 /** Check that all abstract methods implemented by a class are
2558 * mutually compatible.
2559 * @param pos Position to be used for error reporting.
2560 * @param c The class whose interfaces are checked.
2561 */
2562 void checkCompatibleSupertypes(DiagnosticPosition pos, Type c) {
2563 List<Type> supertypes = types.interfaces(c);
2564 Type supertype = types.supertype(c);
2565 if (supertype.hasTag(CLASS) &&
2566 (supertype.tsym.flags() & ABSTRACT) != 0)
2567 supertypes = supertypes.prepend(supertype);
2568 for (List<Type> l = supertypes; l.nonEmpty(); l = l.tail) {
2569 if (!l.head.getTypeArguments().isEmpty() &&
2570 !checkCompatibleAbstracts(pos, l.head, l.head, c))
2571 return;
2572 for (List<Type> m = supertypes; m != l; m = m.tail)
2573 if (!checkCompatibleAbstracts(pos, l.head, m.head, c))
2574 return;
2575 }
2576 checkCompatibleConcretes(pos, c);
2577
2578 Type identitySuper = null;
2579 for (Type t : types.closure(c)) {
2580 if (t != c) {
2581 if (t.isIdentityClass() && (t.tsym.flags() & VALUE_BASED) == 0)
2582 identitySuper = t;
2583 if (c.isValueClass() && identitySuper != null && identitySuper.tsym != syms.objectType.tsym) { // Object is special
2584 log.error(pos, Errors.ValueTypeHasIdentitySuperType(c, identitySuper));
2585 break;
2586 }
2587 }
2588 }
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 }
4902 }
4903 } else {
4904 Assert.error("Unknown pattern: " + currentPattern.getTag());
4905 }
4906 return false;
4907 }
4908
4909 /** check if a type is a subtype of Externalizable, if that is available. */
4910 boolean isExternalizable(Type t) {
4911 try {
4912 syms.externalizableType.complete();
4913 } catch (CompletionFailure e) {
4914 return false;
4915 }
4916 return types.isSubtype(t, syms.externalizableType);
4917 }
4918
4919 /**
4920 * Check structure of serialization declarations.
4921 */
4922 public void checkSerialStructure(Env<AttrContext> env, JCClassDecl tree, ClassSymbol c) {
4923 (new SerialTypeVisitor(env)).visit(c, tree);
4924 }
4925
4926 /**
4927 * This visitor will warn if a serialization-related field or
4928 * method is declared in a suspicious or incorrect way. In
4929 * particular, it will warn for cases where the runtime
4930 * serialization mechanism will silently ignore a mis-declared
4931 * entity.
4932 *
4933 * Distinguished serialization-related fields and methods:
4934 *
4935 * Methods:
4936 *
4937 * private void writeObject(ObjectOutputStream stream) throws IOException
4938 * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException
4939 *
4940 * private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
4941 * private void readObjectNoData() throws ObjectStreamException
4942 * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException
4943 *
4944 * Fields:
4945 *
4946 * private static final long serialVersionUID
4947 * private static final ObjectStreamField[] serialPersistentFields
4948 *
4949 * Externalizable: methods defined on the interface
4950 * public void writeExternal(ObjectOutput) throws IOException
4951 * public void readExternal(ObjectInput) throws IOException
4952 */
4953 private class SerialTypeVisitor extends ElementKindVisitor14<Void, JCClassDecl> {
4954 Env<AttrContext> env;
4955 SerialTypeVisitor(Env<AttrContext> env) {
4956 this.lint = Check.this.lint;
4957 this.env = env;
4958 }
4959
4960 private static final Set<String> serialMethodNames =
4961 Set.of("writeObject", "writeReplace",
4962 "readObject", "readObjectNoData",
4963 "readResolve");
4964
4965 private static final Set<String> serialFieldNames =
4966 Set.of("serialVersionUID", "serialPersistentFields");
4967
4968 // Type of serialPersistentFields
4969 private final Type OSF_TYPE = new Type.ArrayType(syms.objectStreamFieldType, syms.arrayClass);
4970
4971 Lint lint;
4972
4973 @Override
4974 public Void defaultAction(Element e, JCClassDecl p) {
4975 throw new IllegalArgumentException(Objects.requireNonNullElse(e.toString(), ""));
4976 }
4977
4997 if (sym.kind == VAR) {
4998 svuidSym = (VarSymbol)sym;
4999 break;
5000 }
5001 }
5002
5003 if (svuidSym == null) {
5004 log.warning(p.pos(), LintWarnings.MissingSVUID(c));
5005 }
5006
5007 // Check for serialPersistentFields to gate checks for
5008 // non-serializable non-transient instance fields
5009 boolean serialPersistentFieldsPresent =
5010 c.members()
5011 .getSymbolsByName(names.serialPersistentFields, sym -> sym.kind == VAR)
5012 .iterator()
5013 .hasNext();
5014
5015 // Check declarations of serialization-related methods and
5016 // fields
5017 final boolean[] hasWriteReplace = {false};
5018 for(Symbol el : c.getEnclosedElements()) {
5019 runUnderLint(el, p, (enclosed, tree) -> {
5020 String name = null;
5021 switch(enclosed.getKind()) {
5022 case FIELD -> {
5023 if (!serialPersistentFieldsPresent) {
5024 var flags = enclosed.flags();
5025 if ( ((flags & TRANSIENT) == 0) &&
5026 ((flags & STATIC) == 0)) {
5027 Type varType = enclosed.asType();
5028 if (!canBeSerialized(varType)) {
5029 // Note per JLS arrays are
5030 // serializable even if the
5031 // component type is not.
5032 log.warning(
5033 TreeInfo.diagnosticPositionFor(enclosed, tree),
5034 LintWarnings.NonSerializableInstanceField);
5035 } else if (varType.hasTag(ARRAY)) {
5036 ArrayType arrayType = (ArrayType)varType;
5037 Type elementType = arrayType.elemtype;
5072 // will also pull in default methods from
5073 // superinterfaces. In other words, the runtime checks
5074 // (which long predate default methods on interfaces)
5075 // do not admit the possibility of inheriting methods
5076 // this way, a difference from general inheritance.
5077
5078 // The current implementation just checks the enclosed
5079 // elements and does not directly check the inherited
5080 // methods. If all the types are being checked this is
5081 // less of a concern; however, there are cases that
5082 // could be missed. In particular, readResolve and
5083 // writeReplace could, in principle, by inherited from
5084 // a non-serializable superclass and thus not checked
5085 // even if compiled with a serializable child class.
5086 case METHOD -> {
5087 var method = (MethodSymbol)enclosed;
5088 name = method.getSimpleName().toString();
5089 if (serialMethodNames.contains(name)) {
5090 switch (name) {
5091 case "writeObject" -> checkWriteObject(tree, e, method);
5092 case "writeReplace" -> {hasWriteReplace[0] = true; hasAppropriateWriteReplace(tree, method, true);}
5093 case "readObject" -> checkReadObject(tree,e, method);
5094 case "readObjectNoData" -> checkReadObjectNoData(tree, e, method);
5095 case "readResolve" -> checkReadResolve(tree, e, method);
5096 default -> throw new AssertionError();
5097 }
5098 }
5099 }
5100 }
5101 });
5102 }
5103 if (!hasWriteReplace[0] &&
5104 (c.isValueClass() || hasAbstractValueSuperClass(c, Set.of(syms.numberType.tsym))) &&
5105 !c.isAbstract() && !c.isRecord() &&
5106 types.unboxedType(c.type) == Type.noType) {
5107 // we need to check if the class is inheriting an appropriate writeReplace method
5108 MethodSymbol ms = null;
5109 Log.DiagnosticHandler discardHandler = log.new DiscardDiagnosticHandler();
5110 try {
5111 ms = rs.resolveInternalMethod(env.tree, env, c.type, names.writeReplace, List.nil(), List.nil());
5112 } catch (FatalError fe) {
5113 // ignore no method was found
5114 } finally {
5115 log.popDiagnosticHandler(discardHandler);
5116 }
5117 if (ms == null || !hasAppropriateWriteReplace(p, ms, false)) {
5118 log.warning(p.pos(),
5119 c.isValueClass() ? LintWarnings.SerializableValueClassWithoutWriteReplace1 :
5120 LintWarnings.SerializableValueClassWithoutWriteReplace2);
5121 }
5122 }
5123 return null;
5124 }
5125
5126 boolean canBeSerialized(Type type) {
5127 return type.isPrimitive() || rs.isSerializable(type);
5128 }
5129
5130 private boolean hasAbstractValueSuperClass(Symbol c, Set<Symbol> excluding) {
5131 while (c.getKind() == ElementKind.CLASS) {
5132 Type sup = ((ClassSymbol)c).getSuperclass();
5133 if (!sup.hasTag(CLASS) || sup.isErroneous() ||
5134 sup.tsym == syms.objectType.tsym) {
5135 return false;
5136 }
5137 // if it is a value super class it has to be abstract
5138 if (sup.isValueClass() && !excluding.contains(sup.tsym)) {
5139 return true;
5140 }
5141 c = sup.tsym;
5142 }
5143 return false;
5144 }
5145
5146 /**
5147 * Check that Externalizable class needs a public no-arg
5148 * constructor.
5149 *
5150 * Check that a Serializable class has access to the no-arg
5151 * constructor of its first nonserializable superclass.
5152 */
5153 private void checkCtorAccess(JCClassDecl tree, ClassSymbol c) {
5154 if (isExternalizable(c.type)) {
5155 for(var sym : c.getEnclosedElements()) {
5156 if (sym.isConstructor() &&
5157 ((sym.flags() & PUBLIC) == PUBLIC)) {
5158 if (((MethodSymbol)sym).getParameters().isEmpty()) {
5159 return;
5160 }
5161 }
5162 }
5163 log.warning(tree.pos(),
5164 LintWarnings.ExternalizableMissingPublicNoArgCtor);
5165 } else {
5249 // Warn if serialPersistentFields is initialized to a
5250 // literal null.
5251 JCTree spfDecl = TreeInfo.declarationFor(spf, tree);
5252 if (spfDecl != null && spfDecl.getTag() == VARDEF) {
5253 JCVariableDecl variableDef = (JCVariableDecl) spfDecl;
5254 JCExpression initExpr = variableDef.init;
5255 if (initExpr != null && TreeInfo.isNull(initExpr)) {
5256 log.warning(initExpr.pos(),
5257 LintWarnings.SPFNullInit);
5258 }
5259 }
5260 }
5261
5262 private void checkWriteObject(JCClassDecl tree, Element e, MethodSymbol method) {
5263 // The "synchronized" modifier is seen in the wild on
5264 // readObject and writeObject methods and is generally
5265 // innocuous.
5266
5267 // private void writeObject(ObjectOutputStream stream) throws IOException
5268 checkPrivateNonStaticMethod(tree, method);
5269 isExpectedReturnType(tree, method, syms.voidType, true);
5270 checkOneArg(tree, e, method, syms.objectOutputStreamType);
5271 hasExpectedExceptions(tree, method, true, syms.ioExceptionType);
5272 checkExternalizable(tree, e, method);
5273 }
5274
5275 private boolean hasAppropriateWriteReplace(JCClassDecl tree, MethodSymbol method, boolean warn) {
5276 // ANY-ACCESS-MODIFIER Object writeReplace() throws
5277 // ObjectStreamException
5278
5279 // Excluding abstract, could have a more complicated
5280 // rule based on abstract-ness of the class
5281 return isConcreteInstanceMethod(tree, method, warn) &&
5282 isExpectedReturnType(tree, method, syms.objectType, warn) &&
5283 hasNoArgs(tree, method, warn) &&
5284 hasExpectedExceptions(tree, method, warn, syms.objectStreamExceptionType);
5285 }
5286
5287 private void checkReadObject(JCClassDecl tree, Element e, MethodSymbol method) {
5288 // The "synchronized" modifier is seen in the wild on
5289 // readObject and writeObject methods and is generally
5290 // innocuous.
5291
5292 // private void readObject(ObjectInputStream stream)
5293 // throws IOException, ClassNotFoundException
5294 checkPrivateNonStaticMethod(tree, method);
5295 isExpectedReturnType(tree, method, syms.voidType, true);
5296 checkOneArg(tree, e, method, syms.objectInputStreamType);
5297 hasExpectedExceptions(tree, method, true, syms.ioExceptionType, syms.classNotFoundExceptionType);
5298 checkExternalizable(tree, e, method);
5299 }
5300
5301 private void checkReadObjectNoData(JCClassDecl tree, Element e, MethodSymbol method) {
5302 // private void readObjectNoData() throws ObjectStreamException
5303 checkPrivateNonStaticMethod(tree, method);
5304 isExpectedReturnType(tree, method, syms.voidType, true);
5305 hasNoArgs(tree, method, true);
5306 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5307 checkExternalizable(tree, e, method);
5308 }
5309
5310 private void checkReadResolve(JCClassDecl tree, Element e, MethodSymbol method) {
5311 // ANY-ACCESS-MODIFIER Object readResolve()
5312 // throws ObjectStreamException
5313
5314 // Excluding abstract, could have a more complicated
5315 // rule based on abstract-ness of the class
5316 isConcreteInstanceMethod(tree, method, true);
5317 isExpectedReturnType(tree, method, syms.objectType, true);
5318 hasNoArgs(tree, method, true);
5319 hasExpectedExceptions(tree, method, true, syms.objectStreamExceptionType);
5320 }
5321
5322 private void checkWriteExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5323 //public void writeExternal(ObjectOutput) throws IOException
5324 checkExternMethodRecord(tree, e, method, syms.objectOutputType, isExtern);
5325 }
5326
5327 private void checkReadExternalRecord(JCClassDecl tree, Element e, MethodSymbol method, boolean isExtern) {
5328 // public void readExternal(ObjectInput) throws IOException
5329 checkExternMethodRecord(tree, e, method, syms.objectInputType, isExtern);
5330 }
5331
5332 private void checkExternMethodRecord(JCClassDecl tree, Element e, MethodSymbol method, Type argType,
5333 boolean isExtern) {
5334 if (isExtern && isExternMethod(tree, e, method, argType)) {
5335 log.warning(
5336 TreeInfo.diagnosticPositionFor(method, tree),
5337 LintWarnings.IneffectualExternalizableMethodRecord(method.getSimpleName().toString()));
5338 }
5339 }
5549 case FIELD -> {
5550 var field = (VarSymbol)enclosed;
5551 switch(name) {
5552 case "serialPersistentFields" -> {
5553 log.warning(
5554 TreeInfo.diagnosticPositionFor(field, tree),
5555 LintWarnings.IneffectualSerialFieldRecord);
5556 }
5557
5558 case "serialVersionUID" -> {
5559 // Could generate additional warning that
5560 // svuid value is not checked to match for
5561 // records.
5562 checkSerialVersionUID(tree, e, field);
5563 }}
5564 }
5565
5566 case METHOD -> {
5567 var method = (MethodSymbol)enclosed;
5568 switch(name) {
5569 case "writeReplace" -> hasAppropriateWriteReplace(tree, method, true);
5570 case "readResolve" -> checkReadResolve(tree, e, method);
5571
5572 case "writeExternal" -> checkWriteExternalRecord(tree, e, method, isExtern);
5573 case "readExternal" -> checkReadExternalRecord(tree, e, method, isExtern);
5574
5575 default -> {
5576 if (serialMethodNames.contains(name)) {
5577 log.warning(
5578 TreeInfo.diagnosticPositionFor(method, tree),
5579 LintWarnings.IneffectualSerialMethodRecord(name));
5580 }
5581 }}
5582 }}});
5583 }
5584 return null;
5585 }
5586
5587 boolean isConcreteInstanceMethod(JCClassDecl tree,
5588 MethodSymbol method,
5589 boolean warn) {
5590 if ((method.flags() & (STATIC | ABSTRACT)) != 0) {
5591 if (warn) {
5592 log.warning(
5593 TreeInfo.diagnosticPositionFor(method, tree),
5594 LintWarnings.SerialConcreteInstanceMethod(method.getSimpleName()));
5595 }
5596 return false;
5597 }
5598 return true;
5599 }
5600
5601 private boolean isExpectedReturnType(JCClassDecl tree,
5602 MethodSymbol method,
5603 Type expectedReturnType,
5604 boolean warn) {
5605 // Note: there may be complications checking writeReplace
5606 // and readResolve since they return Object and could, in
5607 // principle, have covariant overrides and any synthetic
5608 // bridge method would not be represented here for
5609 // checking.
5610 Type rtype = method.getReturnType();
5611 if (!types.isSameType(expectedReturnType, rtype)) {
5612 if (warn) {
5613 log.warning(
5614 TreeInfo.diagnosticPositionFor(method, tree),
5615 LintWarnings.SerialMethodUnexpectedReturnType(method.getSimpleName(),
5616 rtype, expectedReturnType));
5617 }
5618 return false;
5619 }
5620 return true;
5621 }
5622
5623 private void checkOneArg(JCClassDecl tree,
5624 Element enclosing,
5625 MethodSymbol method,
5626 Type expectedType) {
5627 String name = method.getSimpleName().toString();
5628
5629 var parameters= method.getParameters();
5630
5631 if (parameters.size() != 1) {
5632 log.warning(
5633 TreeInfo.diagnosticPositionFor(method, tree),
5634 LintWarnings.SerialMethodOneArg(method.getSimpleName(), parameters.size()));
5635 return;
5636 }
5637
5638 Type parameterType = parameters.get(0).asType();
5639 if (!types.isSameType(parameterType, expectedType)) {
5640 log.warning(
5641 TreeInfo.diagnosticPositionFor(method, tree),
5642 LintWarnings.SerialMethodParameterType(method.getSimpleName(),
5643 expectedType,
5644 parameterType));
5645 }
5646 }
5647
5648 private boolean hasExactlyOneArgWithType(JCClassDecl tree,
5649 Element enclosing,
5650 MethodSymbol method,
5651 Type expectedType) {
5652 var parameters = method.getParameters();
5653 return (parameters.size() == 1) &&
5654 types.isSameType(parameters.get(0).asType(), expectedType);
5655 }
5656
5657
5658 boolean hasNoArgs(JCClassDecl tree, MethodSymbol method, boolean warn) {
5659 var parameters = method.getParameters();
5660 if (!parameters.isEmpty()) {
5661 if (warn) {
5662 log.warning(
5663 TreeInfo.diagnosticPositionFor(parameters.get(0), tree),
5664 LintWarnings.SerialMethodNoArgs(method.getSimpleName()));
5665 }
5666 return false;
5667 }
5668 return true;
5669 }
5670
5671 private void checkExternalizable(JCClassDecl tree, Element enclosing, MethodSymbol method) {
5672 // If the enclosing class is externalizable, warn for the method
5673 if (isExternalizable((Type)enclosing.asType())) {
5674 log.warning(
5675 TreeInfo.diagnosticPositionFor(method, tree),
5676 LintWarnings.IneffectualSerialMethodExternalizable(method.getSimpleName()));
5677 }
5678 return;
5679 }
5680
5681 private boolean hasExpectedExceptions(JCClassDecl tree,
5682 MethodSymbol method,
5683 boolean warn,
5684 Type... declaredExceptions) {
5685 for (Type thrownType: method.getThrownTypes()) {
5686 // For each exception in the throws clause of the
5687 // method, if not an Error and not a RuntimeException,
5688 // check if the exception is a subtype of a declared
5689 // exception from the throws clause of the
5690 // serialization method in question.
5691 if (types.isSubtype(thrownType, syms.runtimeExceptionType) ||
5692 types.isSubtype(thrownType, syms.errorType) ) {
5693 continue;
5694 } else {
5695 boolean declared = false;
5696 for (Type declaredException : declaredExceptions) {
5697 if (types.isSubtype(thrownType, declaredException)) {
5698 declared = true;
5699 continue;
5700 }
5701 }
5702 if (!declared) {
5703 if (warn) {
5704 log.warning(
5705 TreeInfo.diagnosticPositionFor(method, tree),
5706 LintWarnings.SerialMethodUnexpectedException(method.getSimpleName(),
5707 thrownType));
5708 }
5709 return false;
5710 }
5711 }
5712 }
5713 return true;
5714 }
5715
5716 private <E extends Element> Void runUnderLint(E symbol, JCClassDecl p, BiConsumer<E, JCClassDecl> task) {
5717 Lint prevLint = lint;
5718 try {
5719 lint = lint.augment((Symbol) symbol);
5720
5721 if (lint.isEnabled(LintCategory.SERIAL)) {
5722 task.accept(symbol, p);
5723 }
5724
5725 return null;
5726 } finally {
5727 lint = prevLint;
5728 }
5729 }
5730
5731 }
5732
5733 void checkRequiresIdentity(JCTree tree, Lint lint) {
|