mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Diagnostics] Emit a warning when an immutable decodable property has an initial value (#30218)
* [Diagnostics] Emit a warning when an immutable decodable property has an initial value * [Sema] Use Decl::diagnose instead of Diags.diagnose * [AST] Remove property name from 'decodable_property_will_not_be_decoded' diagnostic * [Test] Update tests * [Test] Update existing codable tests
This commit is contained in:
@@ -830,9 +830,67 @@ deriveBodyDecodable_init(AbstractFunctionDecl *initDecl, void *) {
|
||||
std::tie(varDecl, varType, useIfPresentVariant) =
|
||||
lookupVarDeclForCodingKeysCase(conformanceDC, elt, targetDecl);
|
||||
|
||||
// Don't output a decode statement for a var let with a default value.
|
||||
if (varDecl->isLet() && varDecl->isParentInitialized())
|
||||
// Don't output a decode statement for a let with an initial value.
|
||||
if (varDecl->isLet() && varDecl->isParentInitialized()) {
|
||||
// But emit a warning to let the user know that it won't be decoded.
|
||||
auto lookupResult =
|
||||
codingKeysEnum->lookupDirect(varDecl->getBaseName());
|
||||
auto keyExistsInCodingKeys =
|
||||
llvm::any_of(lookupResult, [&](ValueDecl *VD) {
|
||||
if (isa<EnumElementDecl>(VD)) {
|
||||
return VD->getBaseName() == varDecl->getBaseName();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
auto *encodableProto = C.getProtocol(KnownProtocolKind::Encodable);
|
||||
bool conformsToEncodable =
|
||||
TypeChecker::conformsToProtocol(
|
||||
targetDecl->getDeclaredInterfaceType(), encodableProto,
|
||||
conformanceDC,
|
||||
ConformanceCheckFlags::SkipConditionalRequirements) != nullptr;
|
||||
|
||||
// Strategy to use for CodingKeys enum diagnostic part - this is to
|
||||
// make the behaviour more explicit:
|
||||
//
|
||||
// 1. If we have an *implicit* CodingKeys enum:
|
||||
// (a) If the type is Decodable only, explicitly define the enum and
|
||||
// remove the key from it. This makes it explicit that the key
|
||||
// will not be decoded.
|
||||
// (b) If the type is Codable, explicitly define the enum and keep the
|
||||
// key in it. This is because removing the key will break encoding
|
||||
// which is mostly likely not what the user expects.
|
||||
//
|
||||
// 2. If we have an *explicit* CodingKeys enum:
|
||||
// (a) If the type is Decodable only and the key exists in the enum,
|
||||
// then explicitly remove the key from the enum. This makes it
|
||||
// explicit that the key will not be decoded.
|
||||
// (b) If the type is Decodable only and the key does not exist in
|
||||
// the enum, do nothing. This is because the user has explicitly
|
||||
// made it clear that that they don't want the key to be decoded.
|
||||
// (c) If the type is Codable, do nothing. This is because removing
|
||||
// the key will break encoding which is most likely not what the
|
||||
// user expects.
|
||||
if (!codingKeysEnum->isImplicit()) {
|
||||
if (conformsToEncodable || !keyExistsInCodingKeys) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
varDecl->diagnose(diag::decodable_property_will_not_be_decoded);
|
||||
if (codingKeysEnum->isImplicit()) {
|
||||
varDecl->diagnose(
|
||||
diag::decodable_property_init_or_codingkeys_implicit,
|
||||
conformsToEncodable ? 0 : 1, varDecl->getName());
|
||||
} else {
|
||||
varDecl->diagnose(
|
||||
diag::decodable_property_init_or_codingkeys_explicit,
|
||||
varDecl->getName());
|
||||
}
|
||||
varDecl->diagnose(diag::decodable_make_property_mutable)
|
||||
.fixItReplace(varDecl->getAttributeInsertionLoc(true), "var");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
auto methodName =
|
||||
useIfPresentVariant ? C.Id_decodeIfPresent : C.Id_decode;
|
||||
|
||||
Reference in New Issue
Block a user