From 4eadba482fc416a37d398cc45b52a45041afeef0 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Wed, 10 Nov 2021 10:25:39 -0800 Subject: [PATCH] Provide locations for src-gen diagnostic output --- .../gen/ContextGenerationSpec.cs | 3 + .../gen/JsonSourceGenerator.Emitter.cs | 6 +- .../gen/JsonSourceGenerator.Parser.cs | 42 +++-- .../gen/Reflection/FieldInfoWrapper.cs | 2 + .../gen/Reflection/PropertyInfoWrapper.cs | 2 + .../gen/Reflection/ReflectionExtensions.cs | 22 +++ .../gen/Reflection/TypeWrapper.cs | 2 + .../gen/TypeGenerationSpec.cs | 6 + .../CompilationHelper.cs | 19 ++- .../JsonSourceGeneratorDiagnosticsTests.cs | 144 +++++++++--------- .../JsonSourceGeneratorTests.cs | 18 +-- 11 files changed, 166 insertions(+), 100 deletions(-) diff --git a/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs b/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs index 13e9c7437391d..b88bd91867200 100644 --- a/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs @@ -5,6 +5,7 @@ using System.Text.Json.Serialization; using System.Text.Json.Reflection; using System.Diagnostics; +using Microsoft.CodeAnalysis; namespace System.Text.Json.SourceGeneration { @@ -15,6 +16,8 @@ namespace System.Text.Json.SourceGeneration [DebuggerDisplay("ContextTypeRef={ContextTypeRef}")] internal sealed class ContextGenerationSpec { + public Location Location { get; init; } + public JsonSourceGenerationOptionsAttribute GenerationOptions { get; init; } public Type ContextType { get; init; } diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index ec6124a8222be..087f3e2dc4095 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -274,8 +274,9 @@ private void GenerateTypeInfo(TypeGenerationSpec typeGenerationSpec) break; case ClassType.TypeUnsupportedBySourceGen: { + Location location = typeGenerationSpec.Type.GetDiagnosticLocation() ?? typeGenerationSpec.AttributeLocation ?? _currentContext.Location; _sourceGenerationContext.ReportDiagnostic( - Diagnostic.Create(TypeNotSupported, Location.None, new string[] { typeGenerationSpec.TypeRef })); + Diagnostic.Create(TypeNotSupported, location, new string[] { typeGenerationSpec.TypeRef })); return; } default: @@ -293,7 +294,8 @@ private void GenerateTypeInfo(TypeGenerationSpec typeGenerationSpec) } else { - _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(DuplicateTypeName, Location.None, new string[] { typeGenerationSpec.TypeInfoPropertyName })); + Location location = typeGenerationSpec.AttributeLocation ?? _currentContext.Location; + _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(DuplicateTypeName, location, new string[] { typeGenerationSpec.TypeInfoPropertyName })); } } diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 2785e66c7cd3a..324ddc2b48895 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -116,6 +116,8 @@ private sealed class Parser private readonly HashSet _implicitlyRegisteredTypes = new(); + private readonly HashSet> _typeLevelDiagnostics = new(); + private JsonKnownNamingPolicy _currentContextNamingPolicy; private static DiagnosticDescriptor ContextClassesMustBePartial { get; } = new DiagnosticDescriptor( @@ -285,15 +287,18 @@ public Parser(Compilation compilation, in JsonSourceGenerationContext sourceGene INamedTypeSymbol contextTypeSymbol = (INamedTypeSymbol)compilationSemanticModel.GetDeclaredSymbol(classDeclarationSyntax); Debug.Assert(contextTypeSymbol != null); + Location contextLocation = contextTypeSymbol.Locations[0]; + if (!TryGetClassDeclarationList(contextTypeSymbol, out List classDeclarationList)) { // Class or one of its containing types is not partial so we can't add to it. - _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(ContextClassesMustBePartial, Location.None, new string[] { contextTypeSymbol.Name })); + _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(ContextClassesMustBePartial, contextLocation, new string[] { contextTypeSymbol.Name })); continue; } ContextGenerationSpec contextGenSpec = new() { + Location = contextLocation, GenerationOptions = options ?? new JsonSourceGenerationOptionsAttribute(), ContextType = contextTypeSymbol.AsType(_metadataLoadContext), ContextClassDeclarationList = classDeclarationList @@ -316,6 +321,22 @@ public Parser(Compilation compilation, in JsonSourceGenerationContext sourceGene continue; } + // Emit type-level diagnostics + foreach ((Type Type, DiagnosticDescriptor Descriptor, string[] MessageArgs) diagnostic in _typeLevelDiagnostics) + { + Type type = diagnostic.Type; + Location location = type.GetDiagnosticLocation(); + + if (location == null) + { + TypeGenerationSpec spec = _typeGenerationSpecCache[type]; + location = spec.AttributeLocation; + } + + location ??= contextLocation; + _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(diagnostic.Descriptor, location, diagnostic.MessageArgs)); + } + contextGenSpec.ImplicitlyRegisteredTypes.UnionWith(_implicitlyRegisteredTypes); contextGenSpecList ??= new List(); @@ -324,6 +345,7 @@ public Parser(Compilation compilation, in JsonSourceGenerationContext sourceGene // Clear the cache of generated metadata between the processing of context classes. _typeGenerationSpecCache.Clear(); _implicitlyRegisteredTypes.Clear(); + _typeLevelDiagnostics.Clear(); } if (contextGenSpecList == null) @@ -487,6 +509,8 @@ private static bool TryGetClassDeclarationList(INamedTypeSymbol typeSymbol, [Not typeGenerationSpec.GenerationMode = generationMode; } + typeGenerationSpec.AttributeLocation = attributeSyntax.GetLocation(); + return typeGenerationSpec; } @@ -877,7 +901,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener if (!type.TryGetDeserializationConstructor(useDefaultCtorInAnnotatedStructs, out ConstructorInfo? constructor)) { classType = ClassType.TypeUnsupportedBySourceGen; - _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(MultipleJsonConstructorAttribute, Location.None, new string[] { $"{type}" })); + _typeLevelDiagnostics.Add((type, MultipleJsonConstructorAttribute, new string[] { $"{type}" })); } else { @@ -944,7 +968,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener } spec = GetPropertyGenerationSpec(propertyInfo, isVirtual, generationMode); - CacheMemberHelper(); + CacheMemberHelper(propertyInfo.GetDiagnosticLocation()); } foreach (FieldInfo fieldInfo in currentType.GetFields(bindingFlags)) @@ -955,10 +979,10 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener } spec = GetPropertyGenerationSpec(fieldInfo, isVirtual: false, generationMode); - CacheMemberHelper(); + CacheMemberHelper(fieldInfo.GetDiagnosticLocation()); } - void CacheMemberHelper() + void CacheMemberHelper(Location memberLocation) { CacheMember(spec, ref propGenSpecList, ref ignoredMembers); @@ -972,13 +996,13 @@ void CacheMemberHelper() { if (dataExtensionPropGenSpec != null) { - _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(MultipleJsonExtensionDataAttribute, Location.None, new string[] { type.Name })); + _typeLevelDiagnostics.Add((type, MultipleJsonExtensionDataAttribute, new string[] { type.Name })); } Type propType = spec.TypeGenerationSpec.Type; if (!IsValidDataExtensionPropertyType(propType)) { - _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(DataExtensionPropertyInvalid, Location.None, new string[] { type.Name, spec.ClrName })); + _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(DataExtensionPropertyInvalid, memberLocation, new string[] { type.Name, spec.ClrName })); } dataExtensionPropGenSpec = GetOrAddTypeGenerationSpec(propType, generationMode); @@ -987,13 +1011,13 @@ void CacheMemberHelper() if (!hasInitOnlyProperties && spec.CanUseSetter && spec.IsInitOnlySetter) { - _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(InitOnlyPropertyDeserializationNotSupported, Location.None, new string[] { type.Name })); + _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(InitOnlyPropertyDeserializationNotSupported, memberLocation, new string[] { type.Name })); hasInitOnlyProperties = true; } if (spec.HasJsonInclude && (!spec.CanUseGetter || !spec.CanUseSetter || !spec.IsPublic)) { - _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(InaccessibleJsonIncludePropertiesNotSupported, Location.None, new string[] { type.Name, spec.ClrName })); + _sourceGenerationContext.ReportDiagnostic(Diagnostic.Create(InaccessibleJsonIncludePropertiesNotSupported, memberLocation, new string[] { type.Name, spec.ClrName })); } } } diff --git a/src/libraries/System.Text.Json/gen/Reflection/FieldInfoWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/FieldInfoWrapper.cs index 66e00c0de20bb..d06c264ab0456 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/FieldInfoWrapper.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/FieldInfoWrapper.cs @@ -100,5 +100,7 @@ public override void SetValue(object obj, object value, BindingFlags invokeAttr, { throw new NotImplementedException(); } + + public Location? Location => _field.Locations.Length > 0 ? _field.Locations[0] : null; } } diff --git a/src/libraries/System.Text.Json/gen/Reflection/PropertyInfoWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/PropertyInfoWrapper.cs index bfb593f992fbd..d7eea3323416b 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/PropertyInfoWrapper.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/PropertyInfoWrapper.cs @@ -92,5 +92,7 @@ public override void SetValue(object obj, object value, BindingFlags invokeAttr, { throw new NotSupportedException(); } + + public Location? Location => _property.Locations.Length > 0 ? _property.Locations[0] : null; } } diff --git a/src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs b/src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs index 101f3e48fbfb7..590ffc713dfd8 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/ReflectionExtensions.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Linq; using System.Reflection; +using Microsoft.CodeAnalysis; namespace System.Text.Json.Reflection { @@ -45,5 +46,26 @@ private static bool HasJsonConstructorAttribute(ConstructorInfo constructorInfo) return false; } + + public static Location? GetDiagnosticLocation(this Type type) + { + TypeWrapper? typeWrapper = type as TypeWrapper; + Debug.Assert(typeWrapper != null); + return typeWrapper.Location; + } + + public static Location? GetDiagnosticLocation(this PropertyInfo propertyInfo) + { + PropertyInfoWrapper? propertyInfoWrapper = propertyInfo as PropertyInfoWrapper; + Debug.Assert(propertyInfoWrapper != null); + return propertyInfoWrapper.Location; + } + + public static Location? GetDiagnosticLocation(this FieldInfo fieldInfo) + { + FieldInfoWrapper? fieldInfoWrapper = fieldInfo as FieldInfoWrapper; + Debug.Assert(fieldInfoWrapper != null); + return fieldInfoWrapper.Location; + } } } diff --git a/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs index 5d4d778bc6348..2d06d9ec50cd9 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs @@ -600,5 +600,7 @@ public override bool Equals(Type o) } return base.Equals(o); } + + public Location? Location => _typeSymbol.Locations.Length > 0 ? _typeSymbol.Locations[0] : null; } } diff --git a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs index a85bdd05b914c..39fcd9827b38e 100644 --- a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.Text.Json.Reflection; using System.Text.Json.Serialization; +using Microsoft.CodeAnalysis; namespace System.Text.Json.SourceGeneration { @@ -18,6 +19,11 @@ internal class TypeGenerationSpec /// public string TypeRef { get; private set; } + /// + /// If specified as a root type via JsonSerializableAttribute, specifies the location of the attribute application. + /// + public Location? AttributeLocation { get; set; } + /// /// The name of the public JsonTypeInfo<T> property for this type on the generated context class. /// For example, if the context class is named MyJsonContext, and the value of this property is JsonMessage; diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs index b84c518275ffc..375bb2a240cf2 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/CompilationHelper.cs @@ -11,6 +11,7 @@ using System.Text.Encodings.Web; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; using Xunit; namespace System.Text.Json.SourceGeneration.UnitTests @@ -336,22 +337,28 @@ public partial class MyJsonContext : JsonSerializerContext return CreateCompilation(source); } - internal static void CheckDiagnosticMessages(ImmutableArray diagnostics, DiagnosticSeverity level, string[] expectedMessages) + internal static void CheckDiagnosticMessages( + DiagnosticSeverity level, + ImmutableArray diagnostics, + (TextSpan Location, string Message)[] expectedDiags) { - string[] actualMessages = diagnostics.Where(diagnostic => diagnostic.Severity == level).Select(diagnostic => diagnostic.GetMessage()).ToArray(); + (TextSpan Location, string Message)[] actualDiags = diagnostics + .Where(diagnostic => diagnostic.Severity == level) + .Select(diagnostic => (diagnostic.Location.SourceSpan, diagnostic.GetMessage())) + .ToArray(); // Can't depend on reflection order when generating type metadata. - Array.Sort(actualMessages); - Array.Sort(expectedMessages); + Array.Sort(actualDiags); + Array.Sort(expectedDiags); if (CultureInfo.CurrentUICulture.Name.StartsWith("en", StringComparison.OrdinalIgnoreCase)) { - Assert.Equal(expectedMessages, actualMessages); + Assert.Equal(expectedDiags, actualDiags); } else { // for non-English runs, just compare the number of messages are the same - Assert.Equal(expectedMessages.Length, actualMessages.Length); + Assert.Equal(expectedDiags.Length, actualDiags.Length); } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs index a25196a34fe07..8978779efd9f5 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorDiagnosticsTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; using Xunit; namespace System.Text.Json.SourceGeneration.UnitTests @@ -9,7 +10,7 @@ namespace System.Text.Json.SourceGeneration.UnitTests public class JsonSourceGeneratorDiagnosticsTests { [Fact] - [ActiveIssue("Figure out issue with CampaignSummaryViewModel namespace.")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/58226", TestPlatforms.Browser)] public void SuccessfulSourceGeneration() { // Compile the referenced assembly first. @@ -26,10 +27,13 @@ public void SuccessfulSourceGeneration() using System.Text.Json.Serialization; using ReferencedAssembly; - [assembly: JsonSerializable(typeof(JsonSourceGenerator.IndexViewModel)] - namespace JsonSourceGenerator { + [JsonSerializable(typeof(JsonSourceGenerator.IndexViewModel)] + public partial class JsonContext : JsonSerializerContext + { + } + public class IndexViewModel { public List ActiveOrUpcomingEvents { get; set; } @@ -50,25 +54,13 @@ public class IndexViewModel CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); - // Expected info logs. - string[] expectedInfoDiagnostics = new string[] { - "Generated serialization metadata for type System.Collections.Generic.List", - "Generated serialization metadata for type System.Int32", - "Generated serialization metadata for type System.String", - "Generated serialization metadata for type System.DateTimeOffset", - "Generated serialization metadata for type System.Boolean", - "Generated serialization metadata for type ReferencedAssembly.ActiveOrUpcomingEvent", - "Generated serialization metadata for type ReferencedAssembly.CampaignSummaryViewModel", - "Generated serialization metadata for type JsonSourceGenerator.IndexViewModel", - }; - - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, expectedInfoDiagnostics); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, new string[] { }); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, new string[] { }); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); } [Fact] - [ActiveIssue("Figure out issue with CampaignSummaryViewModel namespace.")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/58226", TestPlatforms.Browser)] public void UnsuccessfulSourceGeneration() { // Compile the referenced assembly first. @@ -85,13 +77,16 @@ public void UnsuccessfulSourceGeneration() using System.Text.Json.Serialization; using ReferencedAssembly; - [assembly: JsonSerializable(typeof(JsonSourceGenerator.IndexViewModel)] - namespace JsonSourceGenerator { + [JsonSerializable(typeof(JsonSourceGenerator.IndexViewModel)] + public partial class JsonContext : JsonSerializerContext + { + } + public class IndexViewModel { - public ISet ActiveOrUpcomingEvents { get; set; } + public ActiveOrUpcomingEvent[,] ActiveOrUpcomingEvents { get; set; } public CampaignSummaryViewModel FeaturedCampaign { get; set; } public bool IsNewAccount { get; set; } public bool HasFeaturedCampaign => FeaturedCampaign != null; @@ -109,19 +104,15 @@ public class IndexViewModel CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); - // Expected success info logs. - string[] expectedInfoDiagnostics = new string[] { - "Generated serialization metadata for type JsonSourceGeneration.IndexViewModel", - "Generated serialization metadata for type System.Boolean", - "Generated serialization metadata for type ReferencedAssembly.CampaignSummaryViewModel" - }; - // Expected warning logs. - string[] expectedWarningDiagnostics = new string[] { "Did not generate serialization metadata for type System.Collections.Generic.ISet" }; + ValueTuple[] expectedWarningDiagnostics = new ValueTuple[] + { + (new TextSpan(315, 11), "Did not generate serialization metadata for type 'global::ReferencedAssembly.ActiveOrUpcomingEvent[]'.") + }; - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, expectedInfoDiagnostics); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, new string[] { }); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, expectedWarningDiagnostics); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); } [Fact] @@ -133,20 +124,23 @@ public void NameClashSourceGeneration() JsonSourceGenerator generator = new JsonSourceGenerator(); CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); - string[] expectedWarningDiagnostics = new string[] { "There are multiple types named Location. Source was generated for the first one detected. Use 'JsonSerializableAttribute.TypeInfoPropertyName' to resolve this collision." }; + ValueTuple[] expectedWarningDiagnostics = new ValueTuple[] + { + (new TextSpan(303, 45), "There are multiple types named Location. Source was generated for the first one detected. Use 'JsonSerializableAttribute.TypeInfoPropertyName' to resolve this collision.") + }; - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, expectedWarningDiagnostics); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); // With resolution. compilation = CompilationHelper.CreateRepeatedLocationsWithResolutionCompilation(); generator = new JsonSourceGenerator(); CompilationHelper.RunGenerators(compilation, out generatorDiags, generator); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); } [Fact] @@ -156,41 +150,40 @@ public void ProgramsThatDontUseGeneratorCompile() // No STJ usage. string source = @"using System; -public class Program -{ - public static void Main() - { - Console.WriteLine(""Hello World""); - - } -} -"; + public class Program + { + public static void Main() + { + Console.WriteLine(""Hello World""); + } + } + "; Compilation compilation = CompilationHelper.CreateCompilation(source); JsonSourceGenerator generator = new JsonSourceGenerator(); CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); // With STJ usage. source = @"using System.Text.Json; -public class Program -{ - public static void Main() - { - JsonSerializer.Serialize(""Hello World""); - } -} -"; + public class Program + { + public static void Main() + { + JsonSerializer.Serialize(""Hello World""); + } + } + "; compilation = CompilationHelper.CreateCompilation(source); generator = new JsonSourceGenerator(); CompilationHelper.RunGenerators(compilation, out generatorDiags, generator); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); } [Fact] @@ -201,11 +194,14 @@ public void WarnOnClassesWithInitOnlyProperties() JsonSourceGenerator generator = new JsonSourceGenerator(); CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); - string[] expectedWarningDiagnostics = new string[] { "The type 'Location' defines init-only properties, deserialization of which is currently not supported in source generation mode." }; + ValueTuple[] expectedWarningDiagnostics = new ValueTuple[] + { + (new TextSpan(236, 2), "The type 'Location' defines init-only properties, deserialization of which is currently not supported in source generation mode.") + }; - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, expectedWarningDiagnostics); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); } [Fact] @@ -216,16 +212,16 @@ public void WarnOnClassesWithInaccessibleJsonIncludeProperties() JsonSourceGenerator generator = new JsonSourceGenerator(); CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator); - string[] expectedWarningDiagnostics = new string[] + ValueTuple[] expectedWarningDiagnostics = new ValueTuple[] { - "The member 'Location.Id' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.", - "The member 'Location.Address2' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.", - "The member 'Location.Country' has been annotated with the JsonIncludeAttribute but is not visible to the source generator." + (new TextSpan(271, 2), "The member 'Location.Id' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), + (new TextSpan(469, 8), "The member 'Location.Address2' has been annotated with the JsonIncludeAttribute but is not visible to the source generator."), + (new TextSpan(667, 7), "The member 'Location.Country' has been annotated with the JsonIncludeAttribute but is not visible to the source generator.") }; - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, expectedWarningDiagnostics); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs index 08519e16fde39..4331dd9c61502 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Collections.Immutable; -using System.IO; using System.Linq; using System.Reflection; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; using Xunit; namespace System.Text.Json.SourceGeneration.UnitTests @@ -70,7 +70,7 @@ public void UsePrivates() Assert.Equal("HelloWorld.MyType", myType.FullName); // Check for received fields, properties and methods in created type. - string[] expectedPropertyNames = { "PublicPropertyInt", "PublicPropertyString",}; + string[] expectedPropertyNames = { "PublicPropertyInt", "PublicPropertyString", }; string[] expectedFieldNames = { "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, expectedFieldNames, expectedPropertyNames, expectedMethodNames); @@ -245,7 +245,7 @@ public void UsePrivates() string[] expectedPropertyNamesNotMyType = { "Address1", "Address2", "City", "Country", "Id", "Name", "PhoneNumber", "PostalCode", "State" }; string[] expectedMethodNamesNotMyType = { "get_Address1", "get_Address2", "get_City", "get_Country", "get_Id", "get_Name", "get_PhoneNumber", "get_PostalCode", "get_State", "set_Address1", "set_Address2", "set_City", "set_Country", "set_Id", "set_Name", "set_PhoneNumber", "set_PostalCode", "set_State" }; - CheckFieldsPropertiesMethods(notMyType, expectedFieldNamesNotMyType, expectedPropertyNamesNotMyType, expectedMethodNamesNotMyType ); + CheckFieldsPropertiesMethods(notMyType, expectedFieldNamesNotMyType, expectedPropertyNamesNotMyType, expectedMethodNamesNotMyType); } [Theory] @@ -291,9 +291,9 @@ public JsonSerializableAttribute(Type type) { } Assert.Null(types); } - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); } [Theory] @@ -323,9 +323,9 @@ public JsonSerializableAttribute(string typeInfoPropertyName, Type type) { } CompilationHelper.RunGenerators(compilation, out ImmutableArray generatorDiags, generator); Assert.Null(generator.GetSerializableTypes()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty()); - CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty>()); + CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty>()); } [Fact]