diff --git a/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs b/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs index e88278884aacd7..1ccb60a42d4aba 100644 --- a/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs +++ b/src/libraries/System.Text.Json/gen/Helpers/RoslynExtensions.cs @@ -15,6 +15,9 @@ namespace System.Text.Json.SourceGeneration { internal static class RoslynExtensions { + public static LanguageVersion? GetLanguageVersion(this Compilation compilation) + => compilation is CSharpCompilation csc ? csc.LanguageVersion : null; + public static INamedTypeSymbol? GetBestTypeByMetadataName(this Compilation compilation, Type type) { Debug.Assert(!type.IsArray, "Resolution logic only capable of handling named types."); diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.DiagnosticDescriptors.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.DiagnosticDescriptors.cs index fb17dadbdee719..b40359df5d8773 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.DiagnosticDescriptors.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.DiagnosticDescriptors.cs @@ -88,6 +88,14 @@ internal static class DiagnosticDescriptors category: JsonConstants.SystemTextJsonSourceGenerationName, defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true); + + public static DiagnosticDescriptor JsonUnsupportedLanguageVersion { get; } = new DiagnosticDescriptor( + id: "SYSLIB1042", + title: new LocalizableResourceString(nameof(SR.JsonUnsupportedLanguageVersionTitle), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)), + messageFormat: new LocalizableResourceString(nameof(SR.JsonUnsupportedLanguageVersionMessageFormat), SR.ResourceManager, typeof(FxResources.System.Text.Json.SourceGeneration.SR)), + category: JsonConstants.SystemTextJsonSourceGenerationName, + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); } } } diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index afd0c12772cc67..d0641ac140cc82 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -6,7 +6,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Reflection; using System.Text.Json.Serialization; using System.Threading; using Microsoft.CodeAnalysis; @@ -17,6 +16,9 @@ namespace System.Text.Json.SourceGeneration { public sealed partial class JsonSourceGenerator { + // The source generator requires NRT and init-only property support. + private const LanguageVersion MinimumSupportedLanguageVersion = LanguageVersion.CSharp9; + private sealed class Parser { private const string SystemTextJsonNamespace = "System.Text.Json"; @@ -104,6 +106,14 @@ public Parser(KnownTypeSymbols knownSymbols) return null; } + LanguageVersion? langVersion = _knownSymbols.Compilation.GetLanguageVersion(); + if (langVersion is null or < MinimumSupportedLanguageVersion) + { + // Unsupported lang version should be the first (and only) diagnostic emitted by the generator. + ReportDiagnostic(DiagnosticDescriptors.JsonUnsupportedLanguageVersion, contextTypeSymbol.GetDiagnosticLocation(), langVersion?.ToDisplayString(), MinimumSupportedLanguageVersion.ToDisplayString()); + return null; + } + Location contextLocation = contextClassDeclaration.GetLocation(); if (!TryGetNestedTypeDeclarations(contextClassDeclaration, semanticModel, cancellationToken, out List? classDeclarationList)) { diff --git a/src/libraries/System.Text.Json/gen/Resources/Strings.resx b/src/libraries/System.Text.Json/gen/Resources/Strings.resx index 7404cad9ccbee4..300e683ab4e70e 100644 --- a/src/libraries/System.Text.Json/gen/Resources/Strings.resx +++ b/src/libraries/System.Text.Json/gen/Resources/Strings.resx @@ -183,4 +183,10 @@ The 'JsonConverterAttribute' type '{0}' specified on member '{1}' is not a converter type or does not contain an accessible parameterless constructor. + + C# language version not supported by the source generator. + + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf index 1e6e5354bb563b..2cfb4bdc97bc71 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.cs.xlf @@ -82,6 +82,16 @@ Neobecný objekt JsonStringEnumConverter vyžaduje dynamický kód. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Typ {0} má více konstruktorů anotovaných s JsonConstructorAttribute. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf index 8f49e4e56e215e..6c381d6ded6b83 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.de.xlf @@ -82,6 +82,16 @@ Der nicht generische "JsonStringEnumConverter" erfordert dynamischen Code. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Typ "{0}" weist mehrere Konstruktoren mit dem Kommentar "JsonConstructorAttribute" auf. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf index 7ae1246d09b219..cd8ceeba3c096b 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.es.xlf @@ -82,6 +82,16 @@ El elemento 'JsonStringEnumConverter' no genérico requiere código dinámico. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. El tipo '{0}' tiene varios constructores anotados con 'JsonConstructorAttribute'. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf index c77fd3bc30bc09..16107bb462c625 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.fr.xlf @@ -82,6 +82,16 @@ Le 'JsonStringEnumConverter' non générique requiert du code dynamique. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Le type' {0} 'a plusieurs constructeurs annotés avec’JsonConstructorAttribute'. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf index ba1aa5b439da08..f9a347a0a222a4 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.it.xlf @@ -82,6 +82,16 @@ L'elemento 'JsonStringEnumConverter' non generico richiede un codice dinamico. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Il tipo '{0}' contiene più costruttori che presentano l'annotazione 'JsonConstructorAttribute'. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf index c37b0a0c98bf2b..f7012d9773c53e 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ja.xlf @@ -82,6 +82,16 @@ 非ジェネリック 'JsonStringEnumConverter' には動的コードが必要です。 + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. 型 '{0}' には、'JsonConstructorAttribute' で注釈が付けられた複数のコンストラクターがあります。 diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf index 12ab8a5571d1e7..6e32fb6945a002 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ko.xlf @@ -82,6 +82,16 @@ 제네릭이 아닌 'JsonStringEnumConverter'에는 동적 코드가 필요합니다. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. '{0}' 형식에 'JsonConstructorAttribute'로 주석이 추가된 여러 생성자가 있습니다. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf index d70419eb349eae..2e0581210c0b95 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pl.xlf @@ -82,6 +82,16 @@ Nieogólny element „JsonStringEnumConverter” wymaga dynamicznego kodu. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Typ "{0}" ma wiele konstruktorów z adnotacją "JsonConstructorAttribute". diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf index 978cfcde17f785..3ddf8733f6c420 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.pt-BR.xlf @@ -82,6 +82,16 @@ O "JsonStringEnumConverter" não genérico requer código dinâmico. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. O tipo '{0}' tem vários construtores anotados com 'JsonConstructorAttribute'. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf index bc0c780f8dbe28..d6de13655dbf3a 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.ru.xlf @@ -82,6 +82,16 @@ Для неуниверсального параметра JsonStringEnumConverter требуется динамический код. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. Тип "{0}" имеет несколько конструкторов, аннотированных с использованием JsonConstructorAttribute. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf index 12b746e205326f..9b790617e79ac5 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.tr.xlf @@ -82,6 +82,16 @@ Genel olmayan 'JsonStringEnumConverter' parametresi dinamik kod gerektirir. + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. '{0}' türünün 'JsonConstructorAttribute' ile açıklanan birden çok oluşturucusu var. diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf index af23644d1a1a75..1eec3cf69ac05a 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hans.xlf @@ -82,6 +82,16 @@ 非泛型 "JsonStringEnumConverter" 需要动态代码。 + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. 类型“{0}”具有用 “JsonConstructorAttribute” 批注的多个构造函数。 diff --git a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf index 9c24bb23ed7833..c995a69ee43f40 100644 --- a/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/libraries/System.Text.Json/gen/Resources/xlf/Strings.zh-Hant.xlf @@ -82,6 +82,16 @@ 非一般 'JsonStringEnumConverter' 需要動態程式碼。 + + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + The System.Text.Json source generator is not available in C# '{0}'. Please use language version {1} or greater. + + + + C# language version not supported by the source generator. + C# language version not supported by the source generator. + + Type '{0}' has multiple constructors annotated with 'JsonConstructorAttribute'. 類型 '{0}' 包含多個以 'JsonConstructorAttribute' 註解的建構函式。 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 2be1a41163e700..67974b94564c40 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 @@ -34,12 +34,17 @@ public void AssertContainsType(string fullyQualifiedName) public static class CompilationHelper { - private static readonly CSharpParseOptions s_parseOptions = - new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Parse); + private readonly static CSharpParseOptions s_defaultParseOptions = CreateParseOptions(); -#if ROSLYN4_0_OR_GREATER - private static readonly GeneratorDriverOptions s_generatorDriverOptions = new GeneratorDriverOptions(disabledOutputs: IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true); -#endif + public static CSharpParseOptions CreateParseOptions( + LanguageVersion? version = null, + DocumentationMode? documentationMode = null) + { + return new CSharpParseOptions( + kind: SourceCodeKind.Regular, + languageVersion: version ?? LanguageVersion.CSharp9, // C# 9 is the minimum supported lang version by the source generator. + documentationMode: documentationMode ?? DocumentationMode.Parse); + } #if NETCOREAPP private static readonly Assembly systemRuntimeAssembly = Assembly.Load(new AssemblyName("System.Runtime")); @@ -50,7 +55,7 @@ public static Compilation CreateCompilation( MetadataReference[] additionalReferences = null, string assemblyName = "TestAssembly", bool includeSTJ = true, - Func configureParseOptions = null) + CSharpParseOptions? parseOptions = null) { List references = new() { @@ -62,6 +67,7 @@ public static Compilation CreateCompilation( MetadataReference.CreateFromFile(typeof(JavaScriptEncoder).Assembly.Location), MetadataReference.CreateFromFile(typeof(GeneratedCodeAttribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(ReadOnlySpan<>).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), #if NETCOREAPP MetadataReference.CreateFromFile(typeof(LinkedList<>).Assembly.Location), MetadataReference.CreateFromFile(systemRuntimeAssembly.Location), @@ -84,37 +90,50 @@ public static Compilation CreateCompilation( } } - var parseOptions = configureParseOptions?.Invoke(s_parseOptions) ?? s_parseOptions; + parseOptions ??= s_defaultParseOptions; + SyntaxTree[] syntaxTrees = new[] + { + CSharpSyntaxTree.ParseText(source, parseOptions), +#if !NETCOREAPP + CSharpSyntaxTree.ParseText(NetfxPolyfillAttributes, parseOptions), +#endif + }; + return CSharpCompilation.Create( assemblyName, - syntaxTrees: new[] { CSharpSyntaxTree.ParseText(source, parseOptions) }, + syntaxTrees: syntaxTrees, references: references, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) ); } - public static SyntaxTree ParseSource(string source) - => CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Preview)); + public static SyntaxTree ParseSource(string source, CSharpParseOptions? options = null) + => CSharpSyntaxTree.ParseText(source, options ?? s_defaultParseOptions); - public static CSharpGeneratorDriver CreateJsonSourceGeneratorDriver(JsonSourceGenerator? generator = null) + public static CSharpGeneratorDriver CreateJsonSourceGeneratorDriver(Compilation compilation, JsonSourceGenerator? generator = null) { generator ??= new(); + CSharpParseOptions parseOptions = compilation.SyntaxTrees + .OfType() + .Select(tree => tree.Options) + .FirstOrDefault() ?? s_defaultParseOptions; + return #if ROSLYN4_0_OR_GREATER CSharpGeneratorDriver.Create( generators: new ISourceGenerator[] { generator.AsSourceGenerator() }, - parseOptions: s_parseOptions, + parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions( disabledOutputs: IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true)); #else CSharpGeneratorDriver.Create( generators: new ISourceGenerator[] { generator }, - parseOptions: s_parseOptions); + parseOptions: parseOptions); #endif } - public static JsonSourceGeneratorResult RunJsonSourceGenerator(Compilation compilation) + public static JsonSourceGeneratorResult RunJsonSourceGenerator(Compilation compilation, bool disableDiagnosticValidation = false) { var generatedSpecs = ImmutableArray.Empty; var generator = new JsonSourceGenerator @@ -122,8 +141,15 @@ public static JsonSourceGeneratorResult RunJsonSourceGenerator(Compilation compi OnSourceEmitting = specs => generatedSpecs = specs }; - CSharpGeneratorDriver driver = CreateJsonSourceGeneratorDriver(generator); + CSharpGeneratorDriver driver = CreateJsonSourceGeneratorDriver(compilation, generator); driver.RunGeneratorsAndUpdateCompilation(compilation, out Compilation outCompilation, out ImmutableArray diagnostics); + + if (!disableDiagnosticValidation) + { + outCompilation.GetDiagnostics().AssertMaxSeverity(DiagnosticSeverity.Info); + diagnostics.AssertMaxSeverity(DiagnosticSeverity.Info); + } + return new() { NewCompilation = outCompilation, @@ -143,6 +169,24 @@ public static byte[] CreateAssemblyImage(Compilation compilation) return ms.ToArray(); } +#if !NETCOREAPP + private const string NetfxPolyfillAttributes = """ + namespace System.Runtime.CompilerServices + { + internal static class IsExternalInit { } + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] + internal sealed class RequiredMemberAttribute : Attribute { } + + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + internal sealed class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) { } + } + } + """; +#endif + public static Compilation CreateReferencedLocationCompilation() { string source = """ @@ -228,9 +272,6 @@ public class HighLowTemps public static Compilation CreateRepeatedLocationsCompilation() { string source = """ - using System; - using System.Collections; - using System.Collections.Generic; using System.Text.Json.Serialization; namespace JsonSourceGeneration @@ -278,57 +319,9 @@ public class Location return CreateCompilation(source); } - public static Compilation CreateRepeatedLocationsWithResolutionCompilation() - { - string source = """ - using System; - using System.Collections; - using System.Collections.Generic; - using System.Text.Json.Serialization; - - [assembly: JsonSerializable(typeof(Fake.Location))] - [assembly: JsonSerializable(typeof(HelloWorld.Location), TypeInfoPropertyName = ""RepeatedLocation"")] - - namespace Fake - { - public class Location - { - public int FakeId { get; set; } - public string FakeAddress1 { get; set; } - public string FakeAddress2 { get; set; } - public string FakeCity { get; set; } - public string FakeState { get; set; } - public string FakePostalCode { get; set; } - public string FakeName { get; set; } - public string FakePhoneNumber { get; set; } - public string FakeCountry { get; set; } - } - } - - namespace HelloWorld - { - public class Location - { - public int Id { get; set; } - public string Address1 { get; set; } - public string Address2 { get; set; } - public string City { get; set; } - public string State { get; set; } - public string PostalCode { get; set; } - public string Name { get; set; } - public string PhoneNumber { get; set; } - public string Country { get; set; } - } - } - """; - - return CreateCompilation(source); - } - public static Compilation CreateCompilationWithInitOnlyProperties() { string source = """ - using System; using System.Text.Json.Serialization; namespace HelloWorld @@ -359,7 +352,6 @@ public partial class MyJsonContext : JsonSerializerContext public static Compilation CreateCompilationWithConstructorInitOnlyProperties() { string source = """ - using System; using System.Text.Json.Serialization; namespace HelloWorld @@ -387,7 +379,6 @@ public partial class MyJsonContext : JsonSerializerContext public static Compilation CreateCompilationWithMixedInitOnlyProperties() { string source = """ - using System; using System.Text.Json.Serialization; namespace HelloWorld @@ -413,10 +404,10 @@ public partial class MyJsonContext : JsonSerializerContext return CreateCompilation(source); } +#if ROSLYN4_4_OR_GREATER public static Compilation CreateCompilationWithRequiredProperties() { string source = """ - using System; using System.Text.Json.Serialization; namespace HelloWorld @@ -439,13 +430,14 @@ public partial class MyJsonContext : JsonSerializerContext } """; - return CreateCompilation(source); + CSharpParseOptions parseOptions = CreateParseOptions(LanguageVersion.CSharp11); + return CreateCompilation(source, parseOptions: parseOptions); } +#endif public static Compilation CreateCompilationWithRecordPositionalParameters() { string source = """ - using System; using System.Text.Json.Serialization; namespace HelloWorld @@ -476,7 +468,6 @@ public partial class MyJsonContext : JsonSerializerContext public static Compilation CreateCompilationWithInaccessibleJsonIncludeProperties() { string source = """ - using System; using System.Text.Json.Serialization; namespace HelloWorld @@ -484,11 +475,11 @@ namespace HelloWorld public class Location { [JsonInclude] - public int publicField; + public int publicField = 1; [JsonInclude] - internal int internalField; + internal int internalField = 2; [JsonInclude] - private int privateField; + private int privateField = 4; [JsonInclude] public int Id { get; private set; } @@ -500,6 +491,8 @@ public class Location public string PhoneNumber { internal get; set; } [JsonInclude] public string Country { private get; set; } + + public int GetPrivateField() => privateField; } [JsonSerializable(typeof(Location))] @@ -650,6 +643,8 @@ public enum Enum2 { A, B, C }; public static Compilation CreateTypesWithInvalidJsonConverterAttributeType() { string source = """ + using System; + using System.Text.Json; using System.Text.Json.Serialization; namespace HelloWorld @@ -664,7 +659,7 @@ public class MyClass [JsonConverter(null)] public int Value1 { get; set; } - [JsonConverter(typeof(int)] + [JsonConverter(typeof(int))] public int Value2 { get; set; } [JsonConverter(typeof(InacessibleConverter))] @@ -743,6 +738,11 @@ internal static void AssertEqualDiagnosticMessages( SyntaxReference? reference = attributeData.ApplicationSyntaxReference; return reference?.SyntaxTree.GetLocation(reference.Span); } + + internal static void AssertMaxSeverity(this IEnumerable diagnostics, DiagnosticSeverity maxSeverity) + { + Assert.Empty(diagnostics.Where(diagnostic => diagnostic.Severity > maxSeverity)); + } } public record struct DiagnosticData( 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 5a64762a9c9d51..a89d83ef497938 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 @@ -1,11 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.CSharp; using Xunit; namespace System.Text.Json.SourceGeneration.UnitTests @@ -73,14 +72,12 @@ public class DocumentedModel MetadataReference.CreateFromImage(documentedImage), }; - Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences, configureParseOptions: options => options.WithDocumentationMode(DocumentationMode.Diagnose)); + Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences, parseOptions: CompilationHelper.CreateParseOptions(documentationMode: DocumentationMode.Diagnose)); JsonSourceGeneratorResult sourceGenResult = CompilationHelper.RunJsonSourceGenerator(compilation); using var emitStream = new MemoryStream(); using var xmlStream = new MemoryStream(); var result = sourceGenResult.NewCompilation.Emit(emitStream, xmlDocumentationStream: xmlStream); - - Assert.Empty(result.Diagnostics); } [Fact] @@ -123,11 +120,7 @@ public class IndexViewModel }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.NewCompilation.GetDiagnostics()); - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Theory] @@ -174,10 +167,7 @@ public class IndexViewModel }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.NewCompilation.GetDiagnostics()); - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] @@ -185,7 +175,7 @@ public void NameClashSourceGeneration() { // Without resolution. Compilation compilation = CompilationHelper.CreateRepeatedLocationsCompilation(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); INamedTypeSymbol symbol = (INamedTypeSymbol)compilation.GetSymbolsWithName("JsonContext").FirstOrDefault(); Location location = symbol.GetAttributes()[1].GetLocation(); @@ -196,12 +186,6 @@ public void NameClashSourceGeneration() }; CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics); - - // With resolution. - compilation = CompilationHelper.CreateRepeatedLocationsWithResolutionCompilation(); - result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.Diagnostics); } [Fact] @@ -215,15 +199,13 @@ public class Program { public static void Main() { - Console.WriteLine(""Hello World""); + Console.WriteLine("Hello World"); } } """; Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); // With STJ usage. source = """ @@ -233,67 +215,57 @@ public class Program { public static void Main() { - JsonSerializer.Serialize(""Hello World""); + JsonSerializer.Serialize("Hello World"); } } """; compilation = CompilationHelper.CreateCompilation(source); - result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] public void DoNotWarnOnClassesWithInitOnlyProperties() { Compilation compilation = CompilationHelper.CreateCompilationWithInitOnlyProperties(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] public void DoNotWarnOnClassesWithConstructorInitOnlyProperties() { Compilation compilation = CompilationHelper.CreateCompilationWithConstructorInitOnlyProperties(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] public void DoNotWarnOnClassesWithMixedInitOnlyProperties() { Compilation compilation = CompilationHelper.CreateCompilationWithMixedInitOnlyProperties(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] public void DoNotWarnOnRecordsWithInitOnlyPositionalParameters() { Compilation compilation = CompilationHelper.CreateCompilationWithRecordPositionalParameters(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } +#if ROSLYN4_4_OR_GREATER [Fact] public void DoNotWarnOnClassesWithRequiredProperties() { Compilation compilation = CompilationHelper.CreateCompilationWithRequiredProperties(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } +#endif [Fact] public void WarnOnClassesWithInaccessibleJsonIncludeProperties() { Compilation compilation = CompilationHelper.CreateCompilationWithInaccessibleJsonIncludeProperties(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); Location idLocation = compilation.GetSymbolsWithName("Id").First().Locations[0]; Location address2Location = compilation.GetSymbolsWithName("Address2").First().Locations[0]; @@ -317,7 +289,7 @@ public void WarnOnClassesWithInaccessibleJsonIncludeProperties() public void PolymorphicClassWarnsOnFastPath() { Compilation compilation = CompilationHelper.CreatePolymorphicClassOnFastPathContext(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); Location myBaseClassLocation = compilation.GetSymbolsWithName("MyBaseClass").First().Locations[0]; @@ -333,7 +305,7 @@ public void PolymorphicClassWarnsOnFastPath() public void JsonStringEnumConverterWarns() { Compilation compilation = CompilationHelper.CreateTypesAnnotatedWithJsonStringEnumConverter(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); Location enum2PropLocation = compilation.GetSymbolsWithName("Enum2Prop").First().GetAttributes()[0].GetLocation(); Location enum1TypeLocation = compilation.GetSymbolsWithName("Enum1").First().GetAttributes()[0].GetLocation(); @@ -351,7 +323,7 @@ public void JsonStringEnumConverterWarns() public void InvalidJsonConverterAttributeTypeWarns() { Compilation compilation = CompilationHelper.CreateTypesWithInvalidJsonConverterAttributeType(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); Location value1PropLocation = compilation.GetSymbolsWithName("Value1").First().GetAttributes()[0].GetLocation(); Location value2PropLocation = compilation.GetSymbolsWithName("Value2").First().GetAttributes()[0].GetLocation(); @@ -371,7 +343,7 @@ public void InvalidJsonConverterAttributeTypeWarns() public void UnboundGenericTypeDeclarationWarns() { Compilation compilation = CompilationHelper.CreateContextWithUnboundGenericTypeDeclarations(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); INamedTypeSymbol symbol = (INamedTypeSymbol)compilation.GetSymbolsWithName("JsonContext").FirstOrDefault(); Collections.Immutable.ImmutableArray attributes = symbol.GetAttributes(); @@ -389,7 +361,7 @@ public void UnboundGenericTypeDeclarationWarns() public void ErrorTypeDeclarationWarns() { Compilation compilation = CompilationHelper.CreateContextWithErrorTypeDeclarations(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); INamedTypeSymbol symbol = (INamedTypeSymbol)compilation.GetSymbolsWithName("JsonContext").FirstOrDefault(); Collections.Immutable.ImmutableArray attributes = symbol.GetAttributes(); @@ -402,5 +374,91 @@ public void ErrorTypeDeclarationWarns() CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics); } + + [Theory] + [InlineData(LanguageVersion.Default)] + [InlineData(LanguageVersion.Preview)] + [InlineData(LanguageVersion.Latest)] + [InlineData(LanguageVersion.LatestMajor)] + [InlineData(LanguageVersion.CSharp9)] +#if ROSLYN4_4_OR_GREATER + [InlineData(LanguageVersion.CSharp10)] + [InlineData(LanguageVersion.CSharp11)] +#endif + public void SupportedLanguageVersions_SucceedCompilation(LanguageVersion langVersion) + { + string source = """ + using System.Text.Json.Serialization; + + namespace HelloWorld + { + public class MyClass + { + public MyClass(int value) + { + Value = value; + } + + public int Value { get; set; } + } + + [JsonSerializable(typeof(MyClass))] + public partial class MyJsonContext : JsonSerializerContext + { + } + } + """; + + CSharpParseOptions parseOptions = CompilationHelper.CreateParseOptions(langVersion); + Compilation compilation = CompilationHelper.CreateCompilation(source, parseOptions: parseOptions); + + CompilationHelper.RunJsonSourceGenerator(compilation); + } + + [Theory] + [InlineData(LanguageVersion.CSharp1)] + [InlineData(LanguageVersion.CSharp2)] + [InlineData(LanguageVersion.CSharp3)] + [InlineData(LanguageVersion.CSharp7)] + [InlineData(LanguageVersion.CSharp7_3)] + [InlineData(LanguageVersion.CSharp8)] + public void UnsupportedLanguageVersions_FailCompilation(LanguageVersion langVersion) + { + string source = """ + using System.Text.Json.Serialization; + + namespace HelloWorld + { + public class MyClass + { + public MyClass(int value) + { + Value = value; + } + + public int Value { get; set; } + } + + [JsonSerializable(typeof(MyClass))] + public partial class MyJsonContext : JsonSerializerContext + { + } + } + """; + + CSharpParseOptions parseOptions = CompilationHelper.CreateParseOptions(langVersion); + Compilation compilation = CompilationHelper.CreateCompilation(source, parseOptions: parseOptions); + + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); + + Location contextLocation = compilation.GetSymbolsWithName("MyJsonContext").First().Locations[0]; + + var expectedDiagnostics = new DiagnosticData[] + { + new(DiagnosticSeverity.Error, contextLocation, $"The System.Text.Json source generator is not available in C# '{langVersion.ToDisplayString()}'. Please use language version 9.0 or greater.") + }; + + CompilationHelper.AssertEqualDiagnosticMessages(expectedDiagnostics, result.Diagnostics); + } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs index 60a3ed97d52646..50ee8f3b8203cf 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorIncrementalTests.cs @@ -18,8 +18,8 @@ public static class JsonSourceGeneratorIncrementalTests [MemberData(nameof(GetCompilationHelperFactories))] public static void CompilingTheSameSourceResultsInEqualModels(Func factory) { - JsonSourceGeneratorResult result1 = CompilationHelper.RunJsonSourceGenerator(factory()); - JsonSourceGeneratorResult result2 = CompilationHelper.RunJsonSourceGenerator(factory()); + JsonSourceGeneratorResult result1 = CompilationHelper.RunJsonSourceGenerator(factory(), disableDiagnosticValidation: true); + JsonSourceGeneratorResult result2 = CompilationHelper.RunJsonSourceGenerator(factory(), disableDiagnosticValidation: true); Assert.Equal(result1.ContextGenerationSpecs.Length, result2.ContextGenerationSpecs.Length); @@ -40,7 +40,6 @@ public static void CompilingTheSameSourceResultsInEqualModels(Func public static void CompilingEquivalentSourcesResultsInEqualModels() { string source1 = """ - using System; using System.Text.Json.Serialization; namespace Test @@ -50,7 +49,7 @@ public partial class JsonContext : JsonSerializerContext { } public class MyPoco { - public string MyProperty { get; set; } = 42; + public int MyProperty { get; set; } = 42; } } """; @@ -64,7 +63,7 @@ namespace Test // Same as above but with different implementation public class MyPoco { - public string MyProperty + public int MyProperty { get => -1; set => throw new NotSupportedException(); @@ -79,8 +78,6 @@ public partial class JsonContext : JsonSerializerContext { } JsonSourceGeneratorResult result1 = CompilationHelper.RunJsonSourceGenerator(CompilationHelper.CreateCompilation(source1)); JsonSourceGeneratorResult result2 = CompilationHelper.RunJsonSourceGenerator(CompilationHelper.CreateCompilation(source2)); - Assert.Empty(result1.Diagnostics); - Assert.Empty(result2.Diagnostics); Assert.Equal(1, result1.ContextGenerationSpecs.Length); Assert.Equal(1, result2.ContextGenerationSpecs.Length); @@ -99,7 +96,6 @@ public partial class JsonContext : JsonSerializerContext { } public static void CompilingDifferentSourcesResultsInUnequalModels() { string source1 = """ - using System; using System.Text.Json.Serialization; namespace Test @@ -109,13 +105,12 @@ public partial class JsonContext : JsonSerializerContext { } public class MyPoco { - public string MyProperty { get; set; } = 42; + public int MyProperty { get; set; } = 42; } } """; string source2 = """ - using System; using System.Text.Json.Serialization; namespace Test @@ -125,15 +120,13 @@ public partial class JsonContext : JsonSerializerContext { } public class MyPoco { - public string MyProperty { get; } = 42; // same, but missing a getter + public int MyProperty { get; } = 42; // same, but missing a getter } } """; JsonSourceGeneratorResult result1 = CompilationHelper.RunJsonSourceGenerator(CompilationHelper.CreateCompilation(source1)); JsonSourceGeneratorResult result2 = CompilationHelper.RunJsonSourceGenerator(CompilationHelper.CreateCompilation(source2)); - Assert.Empty(result1.Diagnostics); - Assert.Empty(result2.Diagnostics); Assert.Equal(1, result1.ContextGenerationSpecs.Length); Assert.Equal(1, result2.ContextGenerationSpecs.Length); @@ -147,7 +140,7 @@ public class MyPoco [MemberData(nameof(GetCompilationHelperFactories))] public static void SourceGenModelDoesNotEncapsulateSymbolsOrCompilationData(Func factory) { - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(factory()); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(factory(), disableDiagnosticValidation: true); WalkObjectGraph(result.ContextGenerationSpecs); static void WalkObjectGraph(object obj) @@ -194,8 +187,8 @@ void Visit(object? node) [MemberData(nameof(GetCompilationHelperFactories))] public static void IncrementalGenerator_SameInput_DoesNotRegenerate(Func factory) { - GeneratorDriver driver = CompilationHelper.CreateJsonSourceGeneratorDriver(); Compilation compilation = factory(); + GeneratorDriver driver = CompilationHelper.CreateJsonSourceGeneratorDriver(compilation); driver = driver.RunGenerators(compilation); GeneratorRunResult runResult = driver.GetRunResult().Results[0]; @@ -286,8 +279,8 @@ public partial class JsonContext : JsonSerializerContext { } } """; - GeneratorDriver driver = CompilationHelper.CreateJsonSourceGeneratorDriver(); Compilation compilation = CompilationHelper.CreateCompilation(source1); + GeneratorDriver driver = CompilationHelper.CreateJsonSourceGeneratorDriver(compilation); driver = driver.RunGenerators(compilation); GeneratorRunResult runResult = driver.GetRunResult().Results[0]; @@ -349,8 +342,8 @@ public class MyPoco } """; - GeneratorDriver driver = CompilationHelper.CreateJsonSourceGeneratorDriver(); Compilation compilation = CompilationHelper.CreateCompilation(source1); + GeneratorDriver driver = CompilationHelper.CreateJsonSourceGeneratorDriver(compilation); driver = driver.RunGenerators(compilation); GeneratorRunResult runResult = driver.GetRunResult().Results[0]; 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 43df7000d1971e..ce27630b6ab692 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 @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; using Xunit; namespace System.Text.Json.SourceGeneration.UnitTests @@ -54,10 +54,6 @@ public void UsePrivates() Compilation compilation = CompilationHelper.CreateCompilation(source); JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); - Assert.Equal(5, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.MyType"); } @@ -73,7 +69,6 @@ public void TypeDiscoveryPrimitiveExternalPOCO() string source = """ using System.Text.Json.Serialization; - using ReferencedAssembly; namespace HelloWorld { @@ -114,10 +109,6 @@ public void UsePrivates() JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); - Assert.Equal(6, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.MyType"); result.AssertContainsType("global::ReferencedAssembly.Location"); @@ -135,7 +126,6 @@ public void TypeDiscoveryWithRenamedAttribute() string source = """ using System.Text.Json.Serialization; - using ReferencedAssembly; using @JsonSerializable = System.Runtime.Serialization.CollectionDataContractAttribute ; using AliasedAttribute = System.Text.Json.Serialization.JsonSerializableAttribute; @@ -179,10 +169,6 @@ public void UsePrivates() JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); - Assert.Equal(6, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.MyType"); result.AssertContainsType("global::ReferencedAssembly.Location"); @@ -217,8 +203,8 @@ public JsonSerializableAttribute(Type type) { } } """; - Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences: null, assemblyName, includeSTJ); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences: null, assemblyName, includeSTJ: includeSTJ); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); if (includeSTJ) { @@ -233,46 +219,16 @@ public JsonSerializableAttribute(Type type) { } Assert.Empty(result.Diagnostics); } - [Theory] - [InlineData("System.Text.Json", true)] - [InlineData("System.Text.Json.Not", true)] - [InlineData("System.Text.Json", false)] - [InlineData("System.Text.Json.Not", false)] - public static void LocalJsonSerializableAttributeUnexpectedShape(string assemblyName, bool includeSTJ) - { - string source = """ - using System; - using System.Text.Json.Serialization; - - [assembly: JsonSerializable(typeof(int))] - - namespace System.Text.Json.Serialization - { - [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] - public sealed class JsonSerializableAttribute : JsonAttribute - { - public JsonSerializableAttribute(string typeInfoPropertyName, Type type) { } - } - } - """; - - Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences: null, assemblyName, includeSTJ); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - Assert.Empty(result.AllGeneratedTypes); - Assert.Empty(result.Diagnostics); - } - [Fact] public void NameClashCompilation() { Compilation compilation = CompilationHelper.CreateRepeatedLocationsCompilation(); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); + JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation, disableDiagnosticValidation: true); // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); + result.Diagnostics.AssertMaxSeverity(DiagnosticSeverity.Warning); + result.NewCompilation.GetDiagnostics().AssertMaxSeverity(DiagnosticSeverity.Warning); } [Fact] @@ -286,7 +242,6 @@ public void CollectionDictionarySourceGeneration() string source = """ using System; - using System.Collections; using System.Collections.Generic; using System.Text.Json.Serialization; using ReferencedAssembly; @@ -314,13 +269,7 @@ public class WeatherForecastWithPOCOs MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - // Make sure compilation was successful. - - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] @@ -363,10 +312,6 @@ public void UsePrivates() JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); - Assert.Equal(5, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::MyType"); result.AssertContainsType("int"); @@ -417,10 +362,6 @@ public record AppRecord(int Id) JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); - Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.AppRecord"); result.AssertContainsType("string"); @@ -453,13 +394,8 @@ internal partial class JsonContext : JsonSerializerContext MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) }; Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); - Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::ReferencedAssembly.LibRecord"); result.AssertContainsType("string"); @@ -499,21 +435,12 @@ internal record AppRecord : LibRecord JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.Diagnostics); - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); - Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.AppRecord"); result.AssertContainsType("string"); result.AssertContainsType("int"); } - private void CheckCompilationDiagnosticsErrors(ImmutableArray diagnostics) - { - Assert.Empty(diagnostics.Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error)); - } - // TODO: add test guarding against (de)serializing static classes. [Fact] @@ -559,10 +486,6 @@ public class MyType JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - Assert.Empty(result.Diagnostics.Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error))); - Assert.Empty(result.NewCompilation.GetDiagnostics().Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error))); - // Should find the generated type. Assert.Equal(2, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::HelloWorld.MyType"); @@ -593,18 +516,13 @@ public class ClassWithObsolete """; Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - ImmutableArray generatorDiags = result.NewCompilation.GetDiagnostics(); - - // No diagnostics expected. - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] public static void NoErrorsWhenUsingReservedCSharpKeywords() { string source = """ - using System; using System.Text.Json.Serialization; namespace Test @@ -621,11 +539,7 @@ public class ClassWithPropertiesAndFieldsThatAreReservedKeywords """; Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - ImmutableArray generatorDiags = result.NewCompilation.GetDiagnostics(); - - // No diagnostics expected. - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] @@ -650,10 +564,6 @@ internal partial class JsonContext : JsonSerializerContext JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - Assert.Empty(result.Diagnostics); - Assert.Empty(result.NewCompilation.GetDiagnostics()); - // Should find the generated type. Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("(string, string, int)"); @@ -665,7 +575,6 @@ internal partial class JsonContext : JsonSerializerContext public static void NoErrorsWhenUsingIgnoredReservedCSharpKeywords() { string source = """ - using System; using System.Text.Json.Serialization; namespace Test @@ -682,11 +591,7 @@ public class ClassWithPropertyNameThatIsAReservedKeyword """; Compilation compilation = CompilationHelper.CreateCompilation(source); - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - ImmutableArray generatorDiags = result.NewCompilation.GetDiagnostics(); - - // No diagnostics expected. - Assert.Empty(result.Diagnostics); + CompilationHelper.RunJsonSourceGenerator(compilation); } [Fact] @@ -699,10 +604,10 @@ public void UseUnderlyingTypeConverterForNullableType() byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation); string source = """ - using ReferencedAssembly; using System; using System.Text.Json; using System.Text.Json.Serialization; + namespace Test { [JsonSourceGenerationOptions] @@ -739,9 +644,6 @@ public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSeri JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - CheckCompilationDiagnosticsErrors(result.NewCompilation.GetDiagnostics()); - Assert.Equal(3, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::Test.Sample"); result.AssertContainsType("global::System.DateTimeOffset"); @@ -752,7 +654,6 @@ public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSeri public void VariousGenericSerializableTypesAreSupported() { string source = """ - using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -789,10 +690,6 @@ public class NestedGenericClass JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - // Make sure compilation was successful. - Assert.Empty(result.Diagnostics.Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error))); - Assert.Empty(result.NewCompilation.GetDiagnostics().Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error))); - Assert.Equal(5, result.AllGeneratedTypes.Count()); result.AssertContainsType("global::System.Collections.Generic.Dictionary"); result.AssertContainsType("global::HelloWorld.MyClass.NestedGenericClass"); @@ -813,10 +710,10 @@ public class NestedGenericClass [InlineData("public readonly partial struct MyReadOnlyStruct")] [InlineData("public readonly ref partial struct MyReadOnlyRefStruct")] #if ROSLYN4_0_OR_GREATER && NETCOREAPP - [InlineData("public partial record MyRecord(int x)")] - [InlineData("public partial record struct MyRecordStruct(int x)")] + [InlineData("public partial record MyRecord(int x)", LanguageVersion.CSharp10)] + [InlineData("public partial record struct MyRecordStruct(int x)", LanguageVersion.CSharp10)] #endif - public void NestedContextsAreSupported(string containingTypeDeclarationHeader) + public void NestedContextsAreSupported(string containingTypeDeclarationHeader, LanguageVersion? languageVersion = null) { string source = $$""" using System.Text.Json.Serialization; @@ -837,13 +734,8 @@ public class MyClass } """; - Compilation compilation = CompilationHelper.CreateCompilation(source); - - JsonSourceGeneratorResult result = CompilationHelper.RunJsonSourceGenerator(compilation); - - // Make sure compilation was successful. - Assert.Empty(result.NewCompilation.GetDiagnostics()); - Assert.Empty(result.Diagnostics); + Compilation compilation = CompilationHelper.CreateCompilation(source, parseOptions: CompilationHelper.CreateParseOptions(languageVersion)); + CompilationHelper.RunJsonSourceGenerator(compilation); } } }