Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Emit diagnostic warnings and exceptions when sourcegen is handling in…
…it-only inaccessible JsonInclude properties.
  • Loading branch information
eiriktsarpalis committed Sep 15, 2021
commit 46aaf43090fdfd611450058b562670b7a45058ae
37 changes: 20 additions & 17 deletions src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -711,25 +711,28 @@ private string GeneratePropMetadataInitFunc(TypeGenerationSpec typeGenerationSpe
? @$"jsonPropertyName: ""{memberMetadata.JsonPropertyName}"""
: "jsonPropertyName: null";

string getterNamedArg = memberMetadata.CanUseGetter &&
memberMetadata.DefaultIgnoreCondition != JsonIgnoreCondition.Always
? $"getter: static (obj) => (({declaringTypeCompilableName})obj).{clrPropertyName}"
: "getter: null";

string setterNamedArg;
if (memberMetadata.CanUseSetter &&
memberMetadata.DefaultIgnoreCondition != JsonIgnoreCondition.Always)
string getterNamedArg = memberMetadata switch
{
string propMutation = typeGenerationSpec.IsValueType
? @$"{UnsafeTypeRef}.Unbox<{declaringTypeCompilableName}>(obj).{clrPropertyName} = value!"
: $@"(({declaringTypeCompilableName})obj).{clrPropertyName} = value!";

setterNamedArg = $"setter: static (obj, value) => {propMutation}";
}
else
{ DefaultIgnoreCondition: JsonIgnoreCondition.Always } => "getter: null",
{ CanUseGetter: true } => $"getter: static (obj) => (({declaringTypeCompilableName})obj).{clrPropertyName}",
{ CanUseGetter: false, HasJsonInclude: true }
=> @$"getter: static (obj) => throw new {InvalidOperationExceptionTypeRef}(""{SR.InaccessibleJsonIncludePropertiesNotSupportedTitle}"")",
_ => "getter: null"
};

string setterNamedArg = memberMetadata switch
{
setterNamedArg = "setter: null";
}
{ DefaultIgnoreCondition: JsonIgnoreCondition.Always } => "setter: null",
{ CanUseSetter: true, IsInitOnlySetter: true }
=> @$"setter: static (obj, value) => throw new {InvalidOperationExceptionTypeRef}(""{SR.InitOnlyPropertyDeserializationNotSupportedTitle}"")",
{ CanUseSetter: true } when typeGenerationSpec.IsValueType
=> $@"setter: static (obj, value) => {UnsafeTypeRef}.Unbox<{declaringTypeCompilableName}>(obj).{clrPropertyName} = value!",
{ CanUseSetter: true }
=> @$"setter: static (obj, value) => (({declaringTypeCompilableName})obj).{clrPropertyName} = value!",
{ CanUseSetter: false, HasJsonInclude: true }
=> @$"setter: static (obj, value) => throw new {InvalidOperationExceptionTypeRef}(""{SR.InaccessibleJsonIncludePropertiesNotSupportedTitle}"")",
_ => "setter: null",
};

JsonIgnoreCondition? ignoreCondition = memberMetadata.DefaultIgnoreCondition;
string ignoreConditionNamedArg = ignoreCondition.HasValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,22 @@ private sealed class Parser
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true);

private static DiagnosticDescriptor InitOnlyPropertyDeserializationNotSupported { get; } = new DiagnosticDescriptor(
id: "SYSLIB1037",
title: new LocalizableResourceString(nameof(SR.InitOnlyPropertyDeserializationNotSupportedTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.InitOnlyPropertyDeserializationNotSupportedFormat), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
category: JsonConstants.SystemTextJsonSourceGenerationName,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

private static DiagnosticDescriptor InaccessibleJsonIncludePropertiesNotSupported { get; } = new DiagnosticDescriptor(
id: "SYSLIB1038",
title: new LocalizableResourceString(nameof(SR.InaccessibleJsonIncludePropertiesNotSupportedTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
messageFormat: new LocalizableResourceString(nameof(SR.InaccessibleJsonIncludePropertiesNotSupportedFormat), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)),
category: JsonConstants.SystemTextJsonSourceGenerationName,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);

public Parser(Compilation compilation, in JsonSourceGenerationContext sourceGenerationContext)
{
_compilation = compilation;
Expand Down Expand Up @@ -624,6 +640,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener
string? converterInstatiationLogic = null;
bool implementsIJsonOnSerialized = false;
bool implementsIJsonOnSerializing = false;
bool hasEncounteredInitOnlyProperties = false;
bool hasTypeFactoryConverter = false;
bool hasPropertyFactoryConverters = false;

Expand Down Expand Up @@ -954,6 +971,17 @@ void CacheMemberHelper()
dataExtensionPropGenSpec = GetOrAddTypeGenerationSpec(propType, generationMode);
_implicitlyRegisteredTypes.Add(dataExtensionPropGenSpec);
}

if (!hasEncounteredInitOnlyProperties && spec.CanUseSetter && spec.IsInitOnlySetter)
{
_sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(InitOnlyPropertyDeserializationNotSupported, Location.None, new string[] { type.Name }));
hasEncounteredInitOnlyProperties = true;
}

if (spec.HasJsonInclude && (!spec.CanUseGetter || !spec.CanUseSetter || !spec.IsPublic))
{
_sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(InaccessibleJsonIncludePropertiesNotSupported, Location.None, new string[] { type.Name, spec.ClrName }));
}
}
}

Expand Down Expand Up @@ -1079,7 +1107,8 @@ private PropertyGenerationSpec GetPropertyGenerationSpec(
out bool canUseGetter,
out bool canUseSetter,
out bool getterIsVirtual,
out bool setterIsVirtual);
out bool setterIsVirtual,
out bool setterIsInitOnly);

string clrName = memberInfo.Name;
string runtimePropertyName = DetermineRuntimePropName(clrName, jsonPropertyName, _currentContextNamingPolicy);
Expand All @@ -1095,6 +1124,7 @@ private PropertyGenerationSpec GetPropertyGenerationSpec(
RuntimePropertyName = runtimePropertyName,
PropertyNameVarName = propertyNameVarName,
IsReadOnly = isReadOnly,
IsInitOnlySetter = setterIsInitOnly,
CanUseGetter = canUseGetter,
CanUseSetter = canUseSetter,
GetterIsVirtual = getterIsVirtual,
Expand Down Expand Up @@ -1227,13 +1257,15 @@ private static void ProcessMember(
out bool canUseGetter,
out bool canUseSetter,
out bool getterIsVirtual,
out bool setterIsVirtual)
out bool setterIsVirtual,
out bool setterIsInitOnly)
{
isPublic = false;
canUseGetter = false;
canUseSetter = false;
getterIsVirtual = false;
setterIsVirtual = false;
setterIsInitOnly = false;

switch (memberInfo)
{
Expand All @@ -1260,15 +1292,16 @@ private static void ProcessMember(
if (setMethod != null)
{
isReadOnly = false;
setterIsInitOnly = setMethod.IsInitOnly();

if (setMethod.IsPublic)
{
isPublic = true;
canUseSetter = !setMethod.IsInitOnly();
canUseSetter = true;
}
else if (setMethod.IsAssembly)
{
canUseSetter = hasJsonInclude && !setMethod.IsInitOnly();
canUseSetter = hasJsonInclude;
}

setterIsVirtual = setMethod.IsVirtual;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ internal sealed class PropertyGenerationSpec
/// </summary>
public bool IsProperty { get; init; }

/// <summary>
/// If representing a property, returns true if either the getter or setter are public.
/// </summary>
public bool IsPublic { get; init; }

public bool IsVirtual { get; init; }
Expand All @@ -39,6 +42,11 @@ internal sealed class PropertyGenerationSpec
/// </summary>
public bool IsReadOnly { get; init; }

/// <summary>
/// Whether the property has an init-only set method.
/// </summary>
public bool IsInitOnlySetter { get; init; }

/// <summary>
/// Whether the property has a public or internal (only usable when JsonIncludeAttribute is specified)
/// getter that can be referenced in generated source code.
Expand Down
14 changes: 13 additions & 1 deletion src/libraries/System.Text.Json/gen/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,16 @@
<data name="DataExtensionPropertyInvalidTitle" xml:space="preserve">
<value>Data extension property type invalid.</value>
</data>
</root>
<data name="InitOnlyPropertyDeserializationNotSupportedTitle" xml:space="preserve">
<value>Deserialization of init-only properties is currently not supported in source generation mode.</value>
</data>
<data name="InitOnlyPropertyDeserializationNotSupportedFormat" xml:space="preserve">
<value>The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</value>
</data>
<data name="InaccessibleJsonIncludePropertiesNotSupportedTitle" xml:space="preserve">
<value>Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</value>
</data>
<data name="InaccessibleJsonIncludePropertiesNotSupportedFormat" xml:space="preserve">
<value>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</value>
</data>
</root>
20 changes: 20 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@
<target state="translated">Duplicitní název typu</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="new">The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedTitle">
<source>Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</source>
<target state="new">Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="InitOnlyPropertyDeserializationNotSupportedFormat">
<source>The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</source>
<target state="new">The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="InitOnlyPropertyDeserializationNotSupportedTitle">
<source>Deserialization of init-only properties is currently not supported in source generation mode.</source>
<target state="new">Deserialization of init-only properties is currently not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="MultipleJsonConstructorAttributeFormat">
<source>Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.</source>
<target state="translated">Typ {0} má více konstruktorů anotovaných s JsonConstructorAttribute. </target>
Expand Down
20 changes: 20 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@
<target state="translated">Doppelter Typname</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="new">The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedTitle">
<source>Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</source>
<target state="new">Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="InitOnlyPropertyDeserializationNotSupportedFormat">
<source>The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</source>
<target state="new">The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="InitOnlyPropertyDeserializationNotSupportedTitle">
<source>Deserialization of init-only properties is currently not supported in source generation mode.</source>
<target state="new">Deserialization of init-only properties is currently not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="MultipleJsonConstructorAttributeFormat">
<source>Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.</source>
<target state="translated">Typ "{0}" weist mehrere Konstruktoren mit dem Kommentar "JsonConstructorAttribute" auf.</target>
Expand Down
20 changes: 20 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@
<target state="translated">Nombre de tipo duplicado.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="new">The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedTitle">
<source>Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</source>
<target state="new">Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="InitOnlyPropertyDeserializationNotSupportedFormat">
<source>The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</source>
<target state="new">The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="InitOnlyPropertyDeserializationNotSupportedTitle">
<source>Deserialization of init-only properties is currently not supported in source generation mode.</source>
<target state="new">Deserialization of init-only properties is currently not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="MultipleJsonConstructorAttributeFormat">
<source>Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.</source>
<target state="translated">El tipo '{0}' tiene varios constructores anotados con 'JsonConstructorAttribute'.</target>
Expand Down
20 changes: 20 additions & 0 deletions src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,26 @@
<target state="translated">Nom de type dupliqué.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedFormat">
<source>The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</source>
<target state="new">The member '{0}.{1}' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.</target>
<note />
</trans-unit>
<trans-unit id="InaccessibleJsonIncludePropertiesNotSupportedTitle">
<source>Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</source>
<target state="new">Inaccessible properties annotated with the JsonIncludeAttribute are not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="InitOnlyPropertyDeserializationNotSupportedFormat">
<source>The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</source>
<target state="new">The type '{0}' defines init-only properties, deserialization of which is currently not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="InitOnlyPropertyDeserializationNotSupportedTitle">
<source>Deserialization of init-only properties is currently not supported in source generation mode.</source>
<target state="new">Deserialization of init-only properties is currently not supported in source generation mode.</target>
<note />
</trans-unit>
<trans-unit id="MultipleJsonConstructorAttributeFormat">
<source>Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'.</source>
<target state="translated">Le type' {0} 'a plusieurs constructeurs annotés avec’JsonConstructorAttribute'.</target>
Expand Down
Loading