From af317817a7aec7e8c554c6300f01b0da684eb7db Mon Sep 17 00:00:00 2001 From: Kyungtak Woo Date: Sun, 26 Jul 2020 21:19:41 -0500 Subject: [PATCH 1/4] Change syntax receiver to do semantic model check --- .../CompilationHelper.cs | 54 ++++++++++++++++++ .../JsonSourceGeneratorTests.cs | 49 ++-------------- ...ext.Json.SourceGeneration.UnitTests.csproj | 3 +- .../JsonSerializableSyntaxReceiver.cs | 37 ++---------- .../JsonSourceGenerator.cs | 56 +++++++++++-------- 5 files changed, 99 insertions(+), 100 deletions(-) create mode 100644 src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/CompilationHelper.cs diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/CompilationHelper.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/CompilationHelper.cs new file mode 100644 index 0000000000000..307bfcbd1d3f1 --- /dev/null +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/CompilationHelper.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection; +using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Xunit; + +namespace System.Text.Json.SourceGeneration.UnitTests +{ + public class CompilationHelper + { + public static Compilation CreateCompilation(string source) + { + // Bypass System.Runtime error. + Assembly systemRuntimeAssembly = Assembly.Load("System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); + string systemRuntimeAssemblyPath = systemRuntimeAssembly.Location; + + MetadataReference[] references = new MetadataReference[] { + MetadataReference.CreateFromFile(typeof(object).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), + MetadataReference.CreateFromFile(typeof(JsonSerializableAttribute).Assembly.Location), + MetadataReference.CreateFromFile(typeof(JsonSerializerOptions).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Type).Assembly.Location), + MetadataReference.CreateFromFile(typeof(KeyValuePair).Assembly.Location), + MetadataReference.CreateFromFile(systemRuntimeAssemblyPath), + }; + + return CSharpCompilation.Create( + "TestAssembly", + syntaxTrees: new[] { CSharpSyntaxTree.ParseText(source) }, + references: references, + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + ); + } + + private static GeneratorDriver CreateDriver(Compilation compilation, params ISourceGenerator[] generators) + => new CSharpGeneratorDriver( + new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Parse), + ImmutableArray.Create(generators), + ImmutableArray.Empty); + + public static Compilation RunGenerators(Compilation compilation, out ImmutableArray diagnostics, params ISourceGenerator[] generators) + { + CreateDriver(compilation, generators).RunFullGeneration(compilation, out Compilation outCompilation, out diagnostics); + return outCompilation; + } + } +} diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs index ae8cfed1dcfe7..6a018be4c53bc 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs @@ -2,13 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; -using System.Reflection; -using System.Text.Json.Serialization; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Xunit; namespace System.Text.Json.SourceGeneration.UnitTests @@ -41,11 +36,11 @@ public void MySecondMethod() { } } }"; - Compilation compilation = CreateCompilation(source); + Compilation compilation = CompilationHelper.CreateCompilation(source); JsonSerializerSourceGenerator generator = new JsonSerializerSourceGenerator(); - Compilation outCompilation = RunGenerators(compilation, out var generatorDiags, generator); + Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); // Check base functionality of found types. Assert.Equal(1, generator.foundTypes.Count); @@ -97,11 +92,11 @@ public class NotMyType { } }"; - Compilation compilation = CreateCompilation(source); + Compilation compilation = CompilationHelper.CreateCompilation(source); JsonSerializerSourceGenerator generator = new JsonSerializerSourceGenerator(); - Compilation outCompilation = RunGenerators(compilation, out var generatorDiags, generator); + Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); // Check base functionality of found types. Assert.Equal(2, generator.foundTypes.Count); @@ -142,41 +137,5 @@ public class NotMyType { } string[] receivedMethodNamesNotMyType = generator.foundTypes["NotMyType"].GetMethods().Select(method => method.Name).ToArray(); Assert.Equal(expectedMethodNamesNotMyType, receivedMethodNamesNotMyType); } - - private Compilation CreateCompilation(string source) - { - // Bypass System.Runtime error. - Assembly systemRuntimeAssembly = Assembly.Load("System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); - string systemRuntimeAssemblyPath = systemRuntimeAssembly.Location; - - MetadataReference[] references = new MetadataReference[] { - MetadataReference.CreateFromFile(typeof(object).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Attribute).Assembly.Location), - MetadataReference.CreateFromFile(typeof(JsonSerializableAttribute).Assembly.Location), - MetadataReference.CreateFromFile(typeof(JsonSerializerOptions).Assembly.Location), - MetadataReference.CreateFromFile(typeof(Type).Assembly.Location), - MetadataReference.CreateFromFile(typeof(KeyValuePair).Assembly.Location), - MetadataReference.CreateFromFile(systemRuntimeAssemblyPath), - }; - - return CSharpCompilation.Create( - "TestAssembly", - syntaxTrees: new[] { CSharpSyntaxTree.ParseText(source) }, - references: references, - options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) - ); - } - - private GeneratorDriver CreateDriver(Compilation compilation, params ISourceGenerator[] generators) - => new CSharpGeneratorDriver( - new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Parse), - ImmutableArray.Create(generators), - ImmutableArray.Empty); - - private Compilation RunGenerators(Compilation compilation, out ImmutableArray diagnostics, params ISourceGenerator[] generators) - { - CreateDriver(compilation, generators).RunFullGeneration(compilation, out Compilation outCompilation, out diagnostics); - return outCompilation; - } } } diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj index 4dfa011d1375d..b8646203e16d4 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/System.Text.Json.SourceGeneration.UnitTests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) @@ -12,6 +12,7 @@ + diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSerializableSyntaxReceiver.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSerializableSyntaxReceiver.cs index 2260a2755dcb2..2d2b3697cb49a 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSerializableSyntaxReceiver.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSerializableSyntaxReceiver.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -12,42 +13,14 @@ namespace System.Text.Json.SourceGeneration { public class JsonSerializableSyntaxReceiver : ISyntaxReceiver { - public List> ExternalClassTypes = new List>(); - public List> InternalClassTypes = new List>(); + public List TypesWithAttributes = new List(); public void OnVisitSyntaxNode(SyntaxNode syntaxNode) { - // Look for classes or structs for JsonSerializable Attribute. - if (syntaxNode is ClassDeclarationSyntax || syntaxNode is StructDeclarationSyntax) + if(syntaxNode is TypeDeclarationSyntax typeDeclarationNode + && typeDeclarationNode.AttributeLists.Count > 0) { - // Find JsonSerializable Attributes. - IEnumerable? serializableAttributes = null; - AttributeListSyntax attributeList = ((TypeDeclarationSyntax)syntaxNode).AttributeLists.SingleOrDefault(); - if (attributeList != null) - { - serializableAttributes = attributeList.Attributes.Where(node => (node is AttributeSyntax attr && attr.Name.ToString() == "JsonSerializable")).Cast(); - } - - if (serializableAttributes?.Any() == true) - { - // JsonSerializableAttribute has AllowMultiple as False, should only have 1 attribute. - Debug.Assert(serializableAttributes.Count() == 1); - AttributeSyntax attributeNode = serializableAttributes.First(); - - // Check if the attribute is being passed a type. - if (attributeNode.DescendantNodes().Where(node => node is TypeOfExpressionSyntax).Any()) - { - // Get JsonSerializable attribute arguments. - AttributeArgumentSyntax attributeArgumentNode = (AttributeArgumentSyntax)attributeNode.DescendantNodes().Where(node => node is AttributeArgumentSyntax).SingleOrDefault(); - // Get external class token from arguments. - IdentifierNameSyntax externalTypeNode = (IdentifierNameSyntax)attributeArgumentNode?.DescendantNodes().Where(node => node is IdentifierNameSyntax).SingleOrDefault(); - ExternalClassTypes.Add(new KeyValuePair(((TypeDeclarationSyntax)syntaxNode).Identifier.Text, externalTypeNode)); - } - else - { - InternalClassTypes.Add(new KeyValuePair(((TypeDeclarationSyntax)syntaxNode).Identifier.Text, (TypeDeclarationSyntax)syntaxNode)); - } - } + TypesWithAttributes.Add(typeDeclarationNode); } } } diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs index 828f9e16595fd..c84da2afebc70 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; + using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; @@ -24,33 +25,44 @@ public class JsonSerializerSourceGenerator : ISourceGenerator public void Execute(SourceGeneratorContext context) { JsonSerializableSyntaxReceiver receiver = (JsonSerializableSyntaxReceiver)context.SyntaxReceiver; - MetadataLoadContext metadataLoadContext = new MetadataLoadContext(context.Compilation); - INamedTypeSymbol namedTypeSymbol; - ITypeSymbol typeSymbol; - IdentifierNameSyntax identifierNameNode; - SemanticModel semanticModel; - Type convertedType; - TypeDeclarationSyntax typeDeclarationNode; + // Filter classes and structs with JsonSerializable attribute semantically. + INamedTypeSymbol jsonSerializableAttributeSymbol = context.Compilation.GetTypeByMetadataName("System.Text.Json.Serialization.JsonSerializableAttribute"); - // Map type name to type objects. - foreach (KeyValuePair entry in receiver.InternalClassTypes) + // Find classes with JsonSerializable Attributes. + foreach (TypeDeclarationSyntax typeDeclarationNode in receiver.TypesWithAttributes) { - typeDeclarationNode = entry.Value; - semanticModel = context.Compilation.GetSemanticModel(typeDeclarationNode.SyntaxTree); - namedTypeSymbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(typeDeclarationNode); - convertedType = new TypeWrapper(namedTypeSymbol, metadataLoadContext); - foundTypes[entry.Key] = convertedType; - } + SemanticModel model = context.Compilation.GetSemanticModel(typeDeclarationNode.SyntaxTree); - foreach (KeyValuePair entry in receiver.ExternalClassTypes) - { - identifierNameNode = entry.Value; - semanticModel = context.Compilation.GetSemanticModel(identifierNameNode.SyntaxTree); - typeSymbol = context.Compilation.GetSemanticModel(identifierNameNode.SyntaxTree).GetTypeInfo(identifierNameNode).ConvertedType; - convertedType = new TypeWrapper(typeSymbol, metadataLoadContext); - foundTypes[entry.Key] = convertedType; + // Check if it contains a JsonSerializableAttribute. + INamedTypeSymbol typeSymbol = (INamedTypeSymbol)model.GetDeclaredSymbol(typeDeclarationNode); + if(typeSymbol.GetAttributes().Any(attr => attr.AttributeClass.Equals(jsonSerializableAttributeSymbol, SymbolEqualityComparer.Default))) + { + // JsonSerializableAttribute has AllowMultiple as False, should have a single attribute. + AttributeListSyntax attributeList = typeDeclarationNode.AttributeLists.Single(); + IEnumerable serializableAttributes = attributeList.Attributes.Where(node => node is AttributeSyntax).Cast(); + AttributeSyntax attributeNode = serializableAttributes.First(); + Debug.Assert(serializableAttributes.Count() == 1); + + // Check if the attribute is being passed a type. + if (attributeNode.DescendantNodes().Where(node => node is TypeOfExpressionSyntax).Any()) + { + // Get JsonSerializable attribute arguments. + AttributeArgumentSyntax attributeArgumentNode = (AttributeArgumentSyntax)attributeNode.DescendantNodes().Where(node => node is AttributeArgumentSyntax).SingleOrDefault(); + // Get external class token from arguments. + IdentifierNameSyntax externalTypeNode = (IdentifierNameSyntax)attributeArgumentNode?.DescendantNodes().Where(node => node is IdentifierNameSyntax).SingleOrDefault(); + + // Get non-user owned typeSymbol from IdentifierNameSyntax and add to found types. + ITypeSymbol externalTypeSymbol = model.GetTypeInfo(externalTypeNode).ConvertedType; + foundTypes[typeDeclarationNode.Identifier.Text] = new TypeWrapper(externalTypeSymbol, metadataLoadContext); + } + else + { + // Add user owned type into found types. + foundTypes[typeDeclarationNode.Identifier.Text] = new TypeWrapper(typeSymbol, metadataLoadContext); + } + } } // Create sources for all found types. From 63219c439afc3d3a453b9710bdb093eae8447d7f Mon Sep 17 00:00:00 2001 From: Kyungtak Woo Date: Sun, 26 Jul 2020 22:03:06 -0500 Subject: [PATCH 2/4] Add unit test for aliased attribute usage --- .../JsonSourceGeneratorTests.cs | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs index 6a018be4c53bc..36346c1dcc1bc 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs @@ -137,5 +137,86 @@ public class NotMyType { } string[] receivedMethodNamesNotMyType = generator.foundTypes["NotMyType"].GetMethods().Select(method => method.Name).ToArray(); Assert.Equal(expectedMethodNamesNotMyType, receivedMethodNamesNotMyType); } + + [Fact] + public void TypeDiscoveryWithRenamedAttribute() + { + string source = @" + using System; + using System.Text.Json.Serialization; + using JsonSerializable = System.Text.Json.Serialization.JsonConstructorAttribute; + using AliasedAttribute = System.Text.Json.Serialization.JsonSerializableAttribute; + + namespace HelloWorld + { + [AliasedAttribute] + public class MyType { + public int PublicPropertyInt { get; set; } + public string PublicPropertyString { get; set; } + private int PrivatePropertyInt { get; set; } + private string PrivatePropertyString { get; set; } + + public double PublicDouble; + public char PublicChar; + private double PrivateDouble; + private char PrivateChar; + + public void MyMethod() { } + public void MySecondMethod() { } + } + + [AliasedAttribute(typeof(JsonConverterAttribute))] + public class NotMyType { } + + [JsonSerializable(typeof(JsonConverterAttribute))] + public class ShouldNotFind { } + + }"; + + Compilation compilation = CompilationHelper.CreateCompilation(source); + + JsonSerializerSourceGenerator generator = new JsonSerializerSourceGenerator(); + + Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); + + // Check base functionality of found types. + Assert.Equal(2, generator.foundTypes.Count); + + // Check for MyType. + Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); + + // Check for received properties in created type. + string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; + string[] receivedPropertyNamesMyType = generator.foundTypes["MyType"].GetProperties().Select(property => property.Name).ToArray(); + Assert.Equal(expectedPropertyNamesMyType, receivedPropertyNamesMyType); + + // Check for fields in created type. + string[] expectedFieldNamesMyType = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; + string[] receivedFieldNamesMyType = generator.foundTypes["MyType"].GetFields().Select(field => field.Name).ToArray(); + Assert.Equal(expectedFieldNamesMyType, receivedFieldNamesMyType); + + // Check for methods in created type. + string[] expectedMethodNamesMyType = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod" }; + string[] receivedMethodNamesMyType = generator.foundTypes["MyType"].GetMethods().Select(method => method.Name).ToArray(); + Assert.Equal(expectedMethodNamesMyType, receivedMethodNamesMyType); + + // Check for NotMyType. + Assert.Equal("System.Text.Json.Serialization.JsonConverterAttribute", generator.foundTypes["NotMyType"].FullName); + + // Check for received properties in created type. + string[] expectedPropertyNamesNotMyType = { "ConverterType" }; + string[] receivedPropertyNamesNotMyType = generator.foundTypes["NotMyType"].GetProperties().Select(property => property.Name).ToArray(); + Assert.Equal(expectedPropertyNamesNotMyType, receivedPropertyNamesNotMyType); + + // Check for fields in created type. + string[] expectedFieldNamesNotMyType = { }; + string[] receivedFieldNamesNotMyType = generator.foundTypes["NotMyType"].GetFields().Select(field => field.Name).ToArray(); + Assert.Equal(expectedFieldNamesNotMyType, receivedFieldNamesNotMyType); + + // Check for methods in created type. + string[] expectedMethodNamesNotMyType = { "get_ConverterType", "CreateConverter" }; + string[] receivedMethodNamesNotMyType = generator.foundTypes["NotMyType"].GetMethods().Select(method => method.Name).ToArray(); + Assert.Equal(expectedMethodNamesNotMyType, receivedMethodNamesNotMyType); + } } } From 975922a5961c8fee19f495bc1d37ae30e9f3b64f Mon Sep 17 00:00:00 2001 From: Kyungtak Woo Date: Tue, 4 Aug 2020 08:09:51 -0500 Subject: [PATCH 3/4] Added compilation checks and added testing helpers --- .../JsonSourceGeneratorTests.cs | 138 +++++++++--------- .../JsonSourceGenerator.cs | 6 +- 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs index 36346c1dcc1bc..5351f2c992ca6 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections.Immutable; using System.Linq; + using Microsoft.CodeAnalysis; using Xunit; @@ -14,7 +16,6 @@ public class GeneratorTests public void TypeDiscoveryPrimitivePOCO() { string source = @" - using System; using System.Text.Json.Serialization; namespace HelloWorld @@ -33,6 +34,14 @@ public class MyType { public void MyMethod() { } public void MySecondMethod() { } + + public void UsePrivates() + { + PrivateDouble = 0; + PrivateChar = ' '; + double d = PrivateDouble; + char c = PrivateChar; + } } }"; @@ -40,33 +49,27 @@ public void MySecondMethod() { } JsonSerializerSourceGenerator generator = new JsonSerializerSourceGenerator(); - Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); + Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); + + // Make sure compilation was successful. + Assert.Empty(generatorDiags); + Assert.Empty(newCompilation.GetDiagnostics()); // Check base functionality of found types. Assert.Equal(1, generator.foundTypes.Count); Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); - // Check for received properties in created type. + // Check for received fields, properties and methods in created type. string[] expectedPropertyNames = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; - string[] receivedPropertyNames = generator.foundTypes["MyType"].GetProperties().Select(property => property.Name).ToArray(); - Assert.Equal(expectedPropertyNames, receivedPropertyNames); - - // Check for fields in created type. string[] expectedFieldNames = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; - string[] receivedFieldNames = generator.foundTypes["MyType"].GetFields().Select(field => field.Name).ToArray(); - Assert.Equal(expectedFieldNames, receivedFieldNames); - - // Check for methods in created type. - string[] expectedMethodNames = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod" }; - string[] receivedMethodNames = generator.foundTypes["MyType"].GetMethods().Select(method => method.Name).ToArray(); - Assert.Equal(expectedMethodNames, receivedMethodNames); + string[] expectedMethodNames = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod", "UsePrivates" }; + CheckFieldsPropertiesMethods("MyType", ref generator, expectedFieldNames, expectedPropertyNames, expectedMethodNames); } [Fact] public void TypeDiscoveryPrimitiveTemporaryPOCO() { string source = @" - using System; using System.Text.Json.Serialization; namespace HelloWorld @@ -85,18 +88,28 @@ public class MyType { public void MyMethod() { } public void MySecondMethod() { } + public void UsePrivates() + { + PrivateDouble = 0; + PrivateChar = ' '; + double x = PrivateDouble; + string s = PrivateChar.ToString(); + } } [JsonSerializable(typeof(JsonConverterAttribute))] public class NotMyType { } - }"; Compilation compilation = CompilationHelper.CreateCompilation(source); JsonSerializerSourceGenerator generator = new JsonSerializerSourceGenerator(); - Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); + Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray generatorDiags, generator); + + // Make sure compilation was successful. + Assert.Empty(generatorDiags); + Assert.Empty(newCompilation.GetDiagnostics()); // Check base functionality of found types. Assert.Equal(2, generator.foundTypes.Count); @@ -104,47 +117,28 @@ public class NotMyType { } // Check for MyType. Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); - // Check for received properties in created type. - string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; - string[] receivedPropertyNamesMyType = generator.foundTypes["MyType"].GetProperties().Select(property => property.Name).ToArray(); - Assert.Equal(expectedPropertyNamesMyType, receivedPropertyNamesMyType); - - // Check for fields in created type. + // Check for received fields, properties and methods for MyType. string[] expectedFieldNamesMyType = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; - string[] receivedFieldNamesMyType = generator.foundTypes["MyType"].GetFields().Select(field => field.Name).ToArray(); - Assert.Equal(expectedFieldNamesMyType, receivedFieldNamesMyType); - - // Check for methods in created type. - string[] expectedMethodNamesMyType = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod" }; - string[] receivedMethodNamesMyType = generator.foundTypes["MyType"].GetMethods().Select(method => method.Name).ToArray(); - Assert.Equal(expectedMethodNamesMyType, receivedMethodNamesMyType); + string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; + string[] expectedMethodNamesMyType = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod", "UsePrivates" }; + CheckFieldsPropertiesMethods("MyType", ref generator, expectedFieldNamesMyType, expectedPropertyNamesMyType, expectedMethodNamesMyType); // Check for NotMyType. Assert.Equal("System.Text.Json.Serialization.JsonConverterAttribute", generator.foundTypes["NotMyType"].FullName); - // Check for received properties in created type. - string[] expectedPropertyNamesNotMyType = { "ConverterType" }; - string[] receivedPropertyNamesNotMyType = generator.foundTypes["NotMyType"].GetProperties().Select(property => property.Name).ToArray(); - Assert.Equal(expectedPropertyNamesNotMyType, receivedPropertyNamesNotMyType); - - // Check for fields in created type. + // Check for received fields, properties and methods for NotMyType. string[] expectedFieldNamesNotMyType = { }; - string[] receivedFieldNamesNotMyType = generator.foundTypes["NotMyType"].GetFields().Select(field => field.Name).ToArray(); - Assert.Equal(expectedFieldNamesNotMyType, receivedFieldNamesNotMyType); - - // Check for methods in created type. + string[] expectedPropertyNamesNotMyType = { "ConverterType" }; string[] expectedMethodNamesNotMyType = { "get_ConverterType", "CreateConverter" }; - string[] receivedMethodNamesNotMyType = generator.foundTypes["NotMyType"].GetMethods().Select(method => method.Name).ToArray(); - Assert.Equal(expectedMethodNamesNotMyType, receivedMethodNamesNotMyType); + CheckFieldsPropertiesMethods("NotMyType", ref generator, expectedFieldNamesNotMyType, expectedPropertyNamesNotMyType, expectedMethodNamesNotMyType); } [Fact] public void TypeDiscoveryWithRenamedAttribute() { string source = @" - using System; using System.Text.Json.Serialization; - using JsonSerializable = System.Text.Json.Serialization.JsonConstructorAttribute; + using @JsonSerializable = System.ObsoleteAttribute; using AliasedAttribute = System.Text.Json.Serialization.JsonSerializableAttribute; namespace HelloWorld @@ -163,12 +157,19 @@ public class MyType { public void MyMethod() { } public void MySecondMethod() { } + public void UsePrivates() + { + PrivateDouble = 0; + PrivateChar = ' '; + double d = PrivateDouble; + char c = PrivateChar; + } } [AliasedAttribute(typeof(JsonConverterAttribute))] public class NotMyType { } - [JsonSerializable(typeof(JsonConverterAttribute))] + [@JsonSerializable(""Testing"", true)] public class ShouldNotFind { } }"; @@ -177,7 +178,11 @@ public class ShouldNotFind { } JsonSerializerSourceGenerator generator = new JsonSerializerSourceGenerator(); - Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); + Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); + + // Make sure compilation was successful. + Assert.Empty(generatorDiags); + Assert.Empty(newCompilation.GetDiagnostics()); // Check base functionality of found types. Assert.Equal(2, generator.foundTypes.Count); @@ -185,38 +190,31 @@ public class ShouldNotFind { } // Check for MyType. Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); - // Check for received properties in created type. - string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; - string[] receivedPropertyNamesMyType = generator.foundTypes["MyType"].GetProperties().Select(property => property.Name).ToArray(); - Assert.Equal(expectedPropertyNamesMyType, receivedPropertyNamesMyType); - - // Check for fields in created type. + // Check for received fields, properties and methods for MyType. string[] expectedFieldNamesMyType = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; - string[] receivedFieldNamesMyType = generator.foundTypes["MyType"].GetFields().Select(field => field.Name).ToArray(); - Assert.Equal(expectedFieldNamesMyType, receivedFieldNamesMyType); - - // Check for methods in created type. - string[] expectedMethodNamesMyType = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod" }; - string[] receivedMethodNamesMyType = generator.foundTypes["MyType"].GetMethods().Select(method => method.Name).ToArray(); - Assert.Equal(expectedMethodNamesMyType, receivedMethodNamesMyType); + string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; + string[] expectedMethodNamesMyType = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod", "UsePrivates" }; + CheckFieldsPropertiesMethods("MyType", ref generator, expectedFieldNamesMyType, expectedPropertyNamesMyType, expectedMethodNamesMyType); // Check for NotMyType. Assert.Equal("System.Text.Json.Serialization.JsonConverterAttribute", generator.foundTypes["NotMyType"].FullName); - // Check for received properties in created type. + // Check for received fields, properties and methods for NotMyType. + string[] expectedFieldNamesNotMyType = { }; string[] expectedPropertyNamesNotMyType = { "ConverterType" }; - string[] receivedPropertyNamesNotMyType = generator.foundTypes["NotMyType"].GetProperties().Select(property => property.Name).ToArray(); - Assert.Equal(expectedPropertyNamesNotMyType, receivedPropertyNamesNotMyType); + string[] expectedMethodNamesNotMyType = { "get_ConverterType", "CreateConverter" }; + CheckFieldsPropertiesMethods("NotMyType", ref generator, expectedFieldNamesNotMyType, expectedPropertyNamesNotMyType, expectedMethodNamesNotMyType ); + } - // Check for fields in created type. - string[] expectedFieldNamesNotMyType = { }; - string[] receivedFieldNamesNotMyType = generator.foundTypes["NotMyType"].GetFields().Select(field => field.Name).ToArray(); - Assert.Equal(expectedFieldNamesNotMyType, receivedFieldNamesNotMyType); + private void CheckFieldsPropertiesMethods(string typeName, ref JsonSerializerSourceGenerator generator, string[] expectedFields, string[] expectedProperties, string[] expectedMethods) + { + string[] receivedFields = generator.foundTypes[typeName].GetFields().Select(field => field.Name).ToArray(); + string[] receivedProperties = generator.foundTypes[typeName].GetProperties().Select(property => property.Name).ToArray(); + string[] receivedMethods = generator.foundTypes[typeName].GetMethods().Select(method => method.Name).ToArray(); - // Check for methods in created type. - string[] expectedMethodNamesNotMyType = { "get_ConverterType", "CreateConverter" }; - string[] receivedMethodNamesNotMyType = generator.foundTypes["NotMyType"].GetMethods().Select(method => method.Name).ToArray(); - Assert.Equal(expectedMethodNamesNotMyType, receivedMethodNamesNotMyType); + Assert.Equal(expectedFields, receivedFields); + Assert.Equal(expectedProperties, receivedProperties); + Assert.Equal(expectedMethods, receivedMethods); } } } diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs index c84da2afebc70..9b05438dc6d9c 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs @@ -30,6 +30,11 @@ public void Execute(SourceGeneratorContext context) // Filter classes and structs with JsonSerializable attribute semantically. INamedTypeSymbol jsonSerializableAttributeSymbol = context.Compilation.GetTypeByMetadataName("System.Text.Json.Serialization.JsonSerializableAttribute"); + if (jsonSerializableAttributeSymbol == null) + { + return; + } + // Find classes with JsonSerializable Attributes. foreach (TypeDeclarationSyntax typeDeclarationNode in receiver.TypesWithAttributes) { @@ -110,7 +115,6 @@ public void Execute(SourceGeneratorContext context) member.Clear(); context.AddSource($"{entry.Key}ClassInfo", SourceText.From($@" -using System; using System.Collections.Generic; namespace HelloWorldGenerated From 91abe6ec2ae0d1e6ffeb0c6939b0ec11fd6ba50d Mon Sep 17 00:00:00 2001 From: Kyungtak Woo Date: Tue, 4 Aug 2020 12:57:00 -0500 Subject: [PATCH 4/4] Sort before list and array comparison for determinism --- .../JsonSourceGeneratorTests.cs | 9 +++--- .../JsonSourceGeneratorTests.cs | 29 +++++++++---------- .../JsonSerializableSyntaxReceiver.cs | 1 - .../JsonSourceGenerator.cs | 1 - 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.Tests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.Tests/JsonSourceGeneratorTests.cs index c8a32bbe05a9f..f1cdd0164c6ec 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.Tests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.Tests/JsonSourceGeneratorTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Collections.Generic; +using System.Linq; using System.Text.Json.Serialization; using Xunit; @@ -67,11 +68,11 @@ public void TestGeneratedCode() Assert.Equal(expectedCtorParamsExternal, externalTypeTest.CtorParams); // Public and private methods are visible. - List expectedMethodsInternal = new List { "get_PublicIntPropertyPublic", "set_PublicIntPropertyPublic", "get_PublicIntPropertyPrivateSet", "set_PublicIntPropertyPrivateSet", "get_PublicIntPropertyPrivateGet", "set_PublicIntPropertyPrivateGet", "UseFields" }; - Assert.Equal(expectedMethodsInternal, internalTypeTest.Methods); + List expectedMethodsInternal = new List { "get_PublicIntPropertyPrivateGet", "get_PublicIntPropertyPrivateSet", "get_PublicIntPropertyPublic", "set_PublicIntPropertyPrivateGet", "set_PublicIntPropertyPrivateSet", "set_PublicIntPropertyPublic", "UseFields" }; + Assert.Equal(expectedMethodsInternal, internalTypeTest.Methods.OrderBy(s => s).ToList()); - List expectedMethodsExternal = new List { "get_ConverterType", "CreateConverter" }; - Assert.Equal(expectedMethodsExternal, externalTypeTest.Methods); + List expectedMethodsExternal = new List { "CreateConverter", "get_ConverterType" }; + Assert.Equal(expectedMethodsExternal, externalTypeTest.Methods.OrderBy(s => s).ToList()); // Public and private fields are visible. Dictionary expectedFieldsInternal = new Dictionary { { "PublicCharField", "Char" }, { "PrivateStringField", "String" } }; diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs index 5351f2c992ca6..d43a052081bc2 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration.UnitTests/JsonSourceGeneratorTests.cs @@ -4,7 +4,6 @@ using System.Collections.Immutable; using System.Linq; - using Microsoft.CodeAnalysis; using Xunit; @@ -60,9 +59,9 @@ public void UsePrivates() Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); // Check for received fields, properties and methods in created type. - string[] expectedPropertyNames = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; - string[] expectedFieldNames = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; - string[] expectedMethodNames = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod", "UsePrivates" }; + string[] expectedPropertyNames = { "PrivatePropertyInt", "PrivatePropertyString", "PublicPropertyInt", "PublicPropertyString",}; + string[] expectedFieldNames = { "PrivateChar", "PrivateDouble", "PublicChar", "PublicDouble" }; + string[] expectedMethodNames = { "get_PrivatePropertyInt", "get_PrivatePropertyString", "get_PublicPropertyInt", "get_PublicPropertyString", "MyMethod", "MySecondMethod", "set_PrivatePropertyInt", "set_PrivatePropertyString", "set_PublicPropertyInt", "set_PublicPropertyString", "UsePrivates" }; CheckFieldsPropertiesMethods("MyType", ref generator, expectedFieldNames, expectedPropertyNames, expectedMethodNames); } @@ -118,9 +117,9 @@ public class NotMyType { } Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); // Check for received fields, properties and methods for MyType. - string[] expectedFieldNamesMyType = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; - string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; - string[] expectedMethodNamesMyType = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod", "UsePrivates" }; + string[] expectedFieldNamesMyType = { "PrivateChar", "PrivateDouble", "PublicChar", "PublicDouble" }; + string[] expectedPropertyNamesMyType = { "PrivatePropertyInt", "PrivatePropertyString", "PublicPropertyInt", "PublicPropertyString" }; + string[] expectedMethodNamesMyType = { "get_PrivatePropertyInt", "get_PrivatePropertyString", "get_PublicPropertyInt", "get_PublicPropertyString", "MyMethod", "MySecondMethod", "set_PrivatePropertyInt", "set_PrivatePropertyString", "set_PublicPropertyInt", "set_PublicPropertyString", "UsePrivates" }; CheckFieldsPropertiesMethods("MyType", ref generator, expectedFieldNamesMyType, expectedPropertyNamesMyType, expectedMethodNamesMyType); // Check for NotMyType. @@ -129,7 +128,7 @@ public class NotMyType { } // Check for received fields, properties and methods for NotMyType. string[] expectedFieldNamesNotMyType = { }; string[] expectedPropertyNamesNotMyType = { "ConverterType" }; - string[] expectedMethodNamesNotMyType = { "get_ConverterType", "CreateConverter" }; + string[] expectedMethodNamesNotMyType = { "CreateConverter", "get_ConverterType" }; CheckFieldsPropertiesMethods("NotMyType", ref generator, expectedFieldNamesNotMyType, expectedPropertyNamesNotMyType, expectedMethodNamesNotMyType); } @@ -191,9 +190,9 @@ public class ShouldNotFind { } Assert.Equal("HelloWorld.MyType", generator.foundTypes["MyType"].FullName); // Check for received fields, properties and methods for MyType. - string[] expectedFieldNamesMyType = { "PublicDouble", "PublicChar", "PrivateDouble", "PrivateChar" }; - string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString", "PrivatePropertyInt", "PrivatePropertyString" }; - string[] expectedMethodNamesMyType = { "get_PublicPropertyInt", "set_PublicPropertyInt", "get_PublicPropertyString", "set_PublicPropertyString", "get_PrivatePropertyInt", "set_PrivatePropertyInt", "get_PrivatePropertyString", "set_PrivatePropertyString", "MyMethod", "MySecondMethod", "UsePrivates" }; + string[] expectedFieldNamesMyType = { "PrivateChar", "PrivateDouble", "PublicChar", "PublicDouble" }; + string[] expectedPropertyNamesMyType = { "PrivatePropertyInt", "PrivatePropertyString", "PublicPropertyInt", "PublicPropertyString" }; + string[] expectedMethodNamesMyType = { "get_PrivatePropertyInt", "get_PrivatePropertyString", "get_PublicPropertyInt", "get_PublicPropertyString", "MyMethod", "MySecondMethod", "set_PrivatePropertyInt", "set_PrivatePropertyString", "set_PublicPropertyInt", "set_PublicPropertyString", "UsePrivates" }; CheckFieldsPropertiesMethods("MyType", ref generator, expectedFieldNamesMyType, expectedPropertyNamesMyType, expectedMethodNamesMyType); // Check for NotMyType. @@ -202,15 +201,15 @@ public class ShouldNotFind { } // Check for received fields, properties and methods for NotMyType. string[] expectedFieldNamesNotMyType = { }; string[] expectedPropertyNamesNotMyType = { "ConverterType" }; - string[] expectedMethodNamesNotMyType = { "get_ConverterType", "CreateConverter" }; + string[] expectedMethodNamesNotMyType = { "CreateConverter", "get_ConverterType" }; CheckFieldsPropertiesMethods("NotMyType", ref generator, expectedFieldNamesNotMyType, expectedPropertyNamesNotMyType, expectedMethodNamesNotMyType ); } private void CheckFieldsPropertiesMethods(string typeName, ref JsonSerializerSourceGenerator generator, string[] expectedFields, string[] expectedProperties, string[] expectedMethods) { - string[] receivedFields = generator.foundTypes[typeName].GetFields().Select(field => field.Name).ToArray(); - string[] receivedProperties = generator.foundTypes[typeName].GetProperties().Select(property => property.Name).ToArray(); - string[] receivedMethods = generator.foundTypes[typeName].GetMethods().Select(method => method.Name).ToArray(); + string[] receivedFields = generator.foundTypes[typeName].GetFields().Select(field => field.Name).OrderBy(s => s).ToArray(); + string[] receivedProperties = generator.foundTypes[typeName].GetProperties().Select(property => property.Name).OrderBy(s => s).ToArray(); + string[] receivedMethods = generator.foundTypes[typeName].GetMethods().Select(method => method.Name).OrderBy(s => s).ToArray(); Assert.Equal(expectedFields, receivedFields); Assert.Equal(expectedProperties, receivedProperties); diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSerializableSyntaxReceiver.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSerializableSyntaxReceiver.cs index 2d2b3697cb49a..3b5d2cb8996fe 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSerializableSyntaxReceiver.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSerializableSyntaxReceiver.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs index 9b05438dc6d9c..453fd2ea7b502 100644 --- a/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs +++ b/src/libraries/System.Text.Json/System.Text.Json.SourceGeneration/JsonSourceGenerator.cs @@ -6,7 +6,6 @@ using System.Diagnostics; using System.Linq; using System.Reflection; - using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text;