Skip to content

Commit 3ff1732

Browse files
Avoid referencing types of JsonIgnore'd properties.
1 parent a4e1dee commit 3ff1732

File tree

4 files changed

+172
-32
lines changed

4 files changed

+172
-32
lines changed

src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,17 @@ private void GeneratePropMetadataInitFunc(SourceWriter writer, string propInitMe
612612
PropertyGenerationSpec property = properties[i];
613613
string propertyName = property.NameSpecifiedInSourceCode;
614614
string declaringTypeFQN = property.DeclaringType.FullyQualifiedName;
615-
string propertyTypeFQN = property.PropertyType.FullyQualifiedName;
615+
616+
// If the property is ignored and its type is not used anywhere else in the type graph,
617+
// emit a JsonPropertyInfo of type 'object' to avoid unnecessarily referencing the type.
618+
// STJ requires that all ignored properties be included so that it can perform
619+
// necessary run-time validations using configuration not known at compile time
620+
// such as the property naming policy and case sensitivity.
621+
bool isIgnoredPropertyOfUnusedType =
622+
property.DefaultIgnoreCondition is JsonIgnoreCondition.Always &&
623+
!_typeIndex.ContainsKey(property.PropertyType);
624+
625+
string propertyTypeFQN = isIgnoredPropertyOfUnusedType ? "object" : property.PropertyType.FullyQualifiedName;
616626

617627
string getterValue = property switch
618628
{
@@ -653,9 +663,12 @@ private void GeneratePropMetadataInitFunc(SourceWriter writer, string propInitMe
653663
: $"({JsonConverterTypeRef}<{propertyTypeFQN}>){ExpandConverterMethodName}(typeof({propertyTypeFQN}), new {converterFQN}(), {OptionsLocalVariableName})";
654664
}
655665

656-
string attributeProviderFactoryExpr = property.IsProperty
657-
? $"typeof({property.DeclaringType.FullyQualifiedName}).GetProperty({FormatStringLiteral(property.MemberName)}, {InstanceMemberBindingFlagsVariableName}, null, typeof({property.PropertyType.FullyQualifiedName}), {EmptyTypeArray}, null)"
658-
: $"typeof({property.DeclaringType.FullyQualifiedName}).GetField({FormatStringLiteral(property.MemberName)}, {InstanceMemberBindingFlagsVariableName})";
666+
string attributeProviderFactoryExpr = property switch
667+
{
668+
_ when isIgnoredPropertyOfUnusedType => "null",
669+
{ IsProperty: true } => $"typeof({property.DeclaringType.FullyQualifiedName}).GetProperty({FormatStringLiteral(property.MemberName)}, {InstanceMemberBindingFlagsVariableName}, null, typeof({propertyTypeFQN}), {EmptyTypeArray}, null)",
670+
_ => $"typeof({property.DeclaringType.FullyQualifiedName}).GetField({FormatStringLiteral(property.MemberName)}, {InstanceMemberBindingFlagsVariableName})",
671+
};
659672

660673
writer.WriteLine($$"""
661674
var {{InfoVarName}}{{i}} = new {{JsonPropertyInfoValuesTypeRef}}<{{propertyTypeFQN}}>

src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using Microsoft.CodeAnalysis.CSharp;
1515
using Microsoft.CodeAnalysis.Text;
1616
using Xunit;
17+
using Xunit.Abstractions;
1718

1819
namespace System.Text.Json.SourceGeneration.UnitTests
1920
{
@@ -133,7 +134,10 @@ public static CSharpGeneratorDriver CreateJsonSourceGeneratorDriver(Compilation
133134
#endif
134135
}
135136

136-
public static JsonSourceGeneratorResult RunJsonSourceGenerator(Compilation compilation, bool disableDiagnosticValidation = false)
137+
public static JsonSourceGeneratorResult RunJsonSourceGenerator(
138+
Compilation compilation,
139+
bool disableDiagnosticValidation = false,
140+
ITestOutputHelper? logger = null)
137141
{
138142
var generatedSpecs = ImmutableArray<ContextGenerationSpec>.Empty;
139143
var generator = new JsonSourceGenerator
@@ -144,6 +148,19 @@ public static JsonSourceGeneratorResult RunJsonSourceGenerator(Compilation compi
144148
CSharpGeneratorDriver driver = CreateJsonSourceGeneratorDriver(compilation, generator);
145149
driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outCompilation, out ImmutableArray<Diagnostic> diagnostics);
146150

151+
if (logger is not null)
152+
{
153+
foreach (Diagnostic diagnostic in outCompilation.GetDiagnostics().Concat(diagnostics))
154+
{
155+
logger.WriteLine(diagnostic.ToString());
156+
}
157+
158+
foreach (var tree in outCompilation.SyntaxTrees)
159+
{
160+
LogGeneratedCode(tree, logger);
161+
}
162+
}
163+
147164
if (!disableDiagnosticValidation)
148165
{
149166
outCompilation.GetDiagnostics().AssertMaxSeverity(DiagnosticSeverity.Info);
@@ -831,6 +848,59 @@ internal static void AssertMaxSeverity(this IEnumerable<Diagnostic> diagnostics,
831848
{
832849
Assert.DoesNotContain(diagnostics, diagnostic => diagnostic.Severity > maxSeverity);
833850
}
851+
852+
private static void LogGeneratedCode(SyntaxTree tree, ITestOutputHelper logger)
853+
{
854+
logger.WriteLine(FileSeparator);
855+
logger.WriteLine($"{tree.FilePath} content:");
856+
logger.WriteLine(FileSeparator);
857+
using NumberedSourceFileWriter lineWriter = new(logger);
858+
tree.GetRoot().WriteTo(lineWriter);
859+
lineWriter.WriteLine(string.Empty);
860+
}
861+
862+
private static readonly string FileSeparator = new string('=', 140);
863+
864+
private sealed class NumberedSourceFileWriter : TextWriter
865+
{
866+
private readonly ITestOutputHelper _logger;
867+
private readonly StringBuilder _lineBuilder = new StringBuilder();
868+
private int _lineNumber;
869+
870+
internal NumberedSourceFileWriter(ITestOutputHelper logger)
871+
{
872+
_logger = logger;
873+
}
874+
875+
public override Encoding Encoding => Encoding.Unicode;
876+
877+
public override void WriteLine(string? value)
878+
{
879+
_logger.WriteLine($"{++_lineNumber,6}: {_lineBuilder}{value}");
880+
_lineBuilder.Clear();
881+
}
882+
883+
public override void Write(string? value)
884+
{
885+
if (value is null)
886+
{
887+
return;
888+
}
889+
890+
if (value.EndsWith("\r\n", StringComparison.Ordinal))
891+
{
892+
WriteLine(value.Substring(0, value.Length - 2));
893+
}
894+
else if (value.EndsWith("\n", StringComparison.Ordinal))
895+
{
896+
WriteLine(value.Substring(0, value.Length - 1));
897+
}
898+
else
899+
{
900+
_lineBuilder.Append(value);
901+
}
902+
}
903+
}
834904
}
835905

836906
public record struct DiagnosticData(

0 commit comments

Comments
 (0)