Example #1
0
        public void Record()
        {
            // Compile the referenced assembly first.
            Compilation referencedCompilation = CompilationHelper.CreateReferencedLibRecordCompilation();

            // Emit the image of the referenced assembly.
            byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation);

            string source = @"
            using System.Text.Json.Serialization;

            namespace HelloWorld
            {
                [JsonSerializable(typeof(AppRecord))]
                internal partial class JsonContext : JsonSerializerContext
                {
                }

                public record AppRecord(int Id)
                {
                    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; }
                    [JsonInclude]
                    public string PhoneNumber;
                    [JsonInclude]
                    public string Country;
                }
            }";

            MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) };

            Compilation compilation = CompilationHelper.CreateCompilation(source);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator);

            // Make sure compilation was successful.
            CheckCompilationDiagnosticsErrors(generatorDiags);
            CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());

            Dictionary <string, Type> types = generator.GetSerializableTypes();

            // Check base functionality of found types.
            Assert.Equal(1, types.Count);
            Type recordType = types["HelloWorld.AppRecord"];

            Assert.Equal("HelloWorld.AppRecord", recordType.FullName);

            // Check for received fields, properties and methods for NotMyType.
            string[] expectedFieldsNames   = { "Country", "PhoneNumber" };
            string[] expectedPropertyNames = { "Address1", "Address2", "City", "Id", "Name", "PostalCode", "State" };
            CheckFieldsPropertiesMethods(recordType, expectedFieldsNames, expectedPropertyNames);

            Assert.Equal(1, recordType.GetConstructors().Length);
        }
        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);
            JsonSourceGenerator generator   = new JsonSourceGenerator();

            CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator);
            Assert.Null(generator.GetSerializableTypes());

            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>());
        }
Example #3
0
        public void MetadataLoadFilePathHandle()
        {
            // Create a MetadataReference from new code.
            string referencedSource = @"
            namespace ReferencedAssembly
            {
                public class ReferencedType
                {
                    public int ReferencedPublicInt;
                    public double ReferencedPublicDouble;     
                }
            }";

            // Compile the referenced assembly first.
            Compilation referencedCompilation = CompilationHelper.CreateCompilation(referencedSource);

            // Emit the image of the referenced assembly.
            byte[] referencedImage;
            using (MemoryStream ms = new MemoryStream())
            {
                var emitResult = referencedCompilation.Emit(ms);
                if (!emitResult.Success)
                {
                    throw new InvalidOperationException();
                }
                referencedImage = ms.ToArray();
            }

            string source = @"
            using System.Text.Json.Serialization;
            using ReferencedAssembly;

            [assembly: JsonSerializable(typeof(HelloWorld.MyType))]
            [assembly: JsonSerializable(typeof(ReferencedAssembly.ReferencedType))]

            namespace HelloWorld
            {
                public class MyType
                {
                    public void MyMethod() { }
                    public void MySecondMethod() { }
                }
            }";

            MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) };

            // Compilation using the referenced image should fail if out MetadataLoadContext does not handle.
            Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator);

            // Make sure compilation was successful.
            Assert.Empty(generatorDiags.Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error)));
            Assert.Empty(newCompilation.GetDiagnostics().Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error)));

            // Should find both types since compilation above was successful.
            Assert.Equal(2, generator.SerializableTypes.Count);
        }
Example #4
0
        public void CanGetAttributes()
        {
            string source = @"
            using System;
            using System.Text.Json.Serialization;

            [assembly: JsonSerializable(typeof(HelloWorld.MyType))]

            namespace HelloWorld
            {
                public class MyType
                {
                    [JsonInclude]
                    public double PublicDouble;

                    [JsonPropertyName(""PPublicDouble"")]
                    public char PublicChar;

                    [JsonIgnore]
                    private double PrivateDouble;

                    private char PrivateChar;

                    public MyType() {{ }}

                    [JsonConstructor]
                    public MyType(double d) {{ PrivateDouble = d; }}

                    [JsonPropertyName(""TestName"")]
                    public int PublicPropertyInt { get; set; }

                    [JsonExtensionData]
                    public string PublicPropertyString { get; set; }

                    [JsonIgnore]
                    private int PrivatePropertyInt { get; set; }

                    private string PrivatePropertyString { get; set; }

                    [Obsolete(""Testing"", true)]
                    public void MyMethod() { }

                    public void MySecondMethod() { }
                }
            }";

            Compilation compilation = CompilationHelper.CreateCompilation(source);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation outCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator);

            // Check base functionality of found types.
            Assert.Equal(1, generator.SerializableTypes.Count);
            Type foundType = generator.SerializableTypes.First().Value;

            Assert.Equal("HelloWorld.MyType", foundType.FullName);

            // Check for ConstructorInfoWrapper attribute usage.
            (string, string[])[] receivedCtorsWithAttributeNames = foundType.GetConstructors().Select(ctor => (ctor.DeclaringType.FullName, ctor.GetCustomAttributesData().Cast <CustomAttributeData>().Select(attributeData => attributeData.AttributeType.Name).ToArray())).ToArray();
Example #5
0
        public static void NoWarningsDueToObsoleteMembers()
        {
            string source = @"using System;
using System.Text.Json.Serialization;

namespace Test
{
    [JsonSerializable(typeof(ClassWithObsolete))]
    public partial class JsonContext : JsonSerializerContext { }

    public class ClassWithObsolete
    {
        [Obsolete(""This is a test"")]
        public bool Test { get; set; }
    }
}
";

            Compilation         compilation = CompilationHelper.CreateCompilation(source);
            JsonSourceGenerator generator   = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out _, generator);
            ImmutableArray <Diagnostic> generatorDiags = newCompilation.GetDiagnostics();

            // No diagnostics expected.
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty <(Location, string)>());
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty <(Location, string)>());
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty <(Location, string)>());
        }
        public static void NoErrorsWhenUsingIgnoredReservedCSharpKeywords()
        {
            string              source      = @"using System;
using System.Text.Json.Serialization;

namespace Test
{
    [JsonSerializable(typeof(ClassWithPropertyNameThatIsAReservedKeyword))]
    public partial class JsonContext : JsonSerializerContext { }

    public class ClassWithPropertyNameThatIsAReservedKeyword
    {
        [JsonIgnore]
        public string @event { get; set; }
    }
}
";
            Compilation         compilation = CompilationHelper.CreateCompilation(source);
            JsonSourceGenerator generator   = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out _, generator);
            ImmutableArray <Diagnostic> generatorDiags = newCompilation.GetDiagnostics();

            // No diagnostics expected.
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty <(Location, string)>());
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty <(Location, string)>());
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty <(Location, string)>());
        }
Example #7
0
        public void ContextTypeNotInNamespace()
        {
            string source = @"
            using System.Text.Json.Serialization;

            [JsonSerializable(typeof(MyType))]
            internal partial class JsonContext : JsonSerializerContext
            {
            }

            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() { }

                public void UsePrivates()
                {
                    PrivateDouble = 0;
                    PrivateChar = ' ';
                    double d = PrivateDouble;
                    char c = PrivateChar;
                }
            }";

            Compilation compilation = CompilationHelper.CreateCompilation(source);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator);

            // Make sure compilation was successful.
            CheckCompilationDiagnosticsErrors(generatorDiags);
            CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());

            Dictionary <string, Type> types = generator.GetSerializableTypes();

            // Check base functionality of found types.
            Assert.Equal(1, types.Count);
            Type myType = types["MyType"];

            Assert.Equal("MyType", myType.FullName);

            // Check for received fields, properties and methods in created type.
            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);
        }
Example #8
0
        public void SuccessfulSourceGeneration()
        {
            // Compile the referenced assembly first.
            Compilation campaignCompilation = CompilationHelper.CreateCampaignSummaryViewModelCompilation();
            Compilation eventCompilation    = CompilationHelper.CreateActiveOrUpcomingEventCompilation();

            // Emit the image of the referenced assembly.
            byte[] campaignImage = CompilationHelper.CreateAssemblyImage(campaignCompilation);
            byte[] eventImage    = CompilationHelper.CreateAssemblyImage(eventCompilation);

            // Main source for current compilation.
            string source = @"
            using System.Collections.Generic;
            using System.Text.Json.Serialization;
            using ReferencedAssembly;

            [assembly: JsonSerializable(typeof(JsonSourceGenerator.IndexViewModel)]

            namespace JsonSourceGenerator
            {
                public class IndexViewModel
                {
                    public List<ActiveOrUpcomingEvent> ActiveOrUpcomingEvents { get; set; }
                    public CampaignSummaryViewModel FeaturedCampaign { get; set; }
                    public bool IsNewAccount { get; set; }
                    public bool HasFeaturedCampaign => FeaturedCampaign != null;
                }
            }";

            MetadataReference[] additionalReferences =
            {
                MetadataReference.CreateFromImage(campaignImage),
                MetadataReference.CreateFromImage(eventImage),
            };

            Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator);

            // Expected info logs.
            string[] expectedInfoDiagnostics = new string[] {
                "Generated serialization metadata for type System.Collections.Generic.List<ReferencedAssembly.ActiveOrUpcomingEvent>",
                "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[] { });
        }
        private void CheckFieldsPropertiesMethods(string typeName, ref JsonSourceGenerator generator, string[] expectedFields, string[] expectedProperties, string[] expectedMethods)
        {
            Type type = generator.SerializableTypes[typeName];

            string[] receivedFields     = type.GetFields().Select(field => field.Name).OrderBy(s => s).ToArray();
            string[] receivedProperties = type.GetProperties().Select(property => property.Name).OrderBy(s => s).ToArray();
            string[] receivedMethods    = type.GetMethods().Select(method => method.Name).OrderBy(s => s).ToArray();

            Assert.Equal(expectedFields, receivedFields);
            Assert.Equal(expectedProperties, receivedProperties);
            Assert.Equal(expectedMethods, receivedMethods);
        }
Example #10
0
        public void TestMultipleDefinitions()
        {
            // Adding a dependency to an assembly that has internal definitions of public types
            // should not result in a collision and break generation.
            // Verify usage of the extension GetBestTypeByMetadataName(this Compilation) instead of Compilation.GetTypeByMetadataName().
            var referencedSource = @"
                namespace System.Text.Json.Serialization
                {
                    internal class JsonSerializerContext { }
                    internal class JsonSerializableAttribute { }
                    internal class JsonSourceGenerationOptionsAttribute { }
                }";

            // Compile the referenced assembly first.
            Compilation referencedCompilation = CompilationHelper.CreateCompilation(referencedSource);

            // Obtain the image of the referenced assembly.
            byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation);

            // Generate the code
            string source = @"
                using System.Text.Json.Serialization;
                namespace HelloWorld
                {
                    [JsonSerializable(typeof(HelloWorld.MyType))]
                    internal partial class JsonContext : JsonSerializerContext
                    {
                    }

                    public class MyType
                    {
                        public int MyInt { get; set; }
                    }
                }";

            MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) };
            Compilation         compilation          = CompilationHelper.CreateCompilation(source, additionalReferences);
            JsonSourceGenerator generator            = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(
                compilation,
                out ImmutableArray <Diagnostic> generatorDiags, generator);

            // Make sure compilation was successful.
            Assert.Empty(generatorDiags.Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error)));
            Assert.Empty(newCompilation.GetDiagnostics().Where(diag => diag.Severity.Equals(DiagnosticSeverity.Error)));

            // Should find the generated type.
            Dictionary <string, Type> types = generator.GetSerializableTypes();

            Assert.Equal(1, types.Count);
            Assert.Equal("HelloWorld.MyType", types.Keys.First());
        }
        public void NameClashCompilation()
        {
            Compilation compilation = CompilationHelper.CreateRepeatedLocationsCompilation();

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator);

            // Make sure compilation was successful.
            CheckCompilationDiagnosticsErrors(generatorDiags);
            CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());
        }
Example #12
0
        public void WarnOnClassesWithInitOnlyProperties()
        {
            Compilation         compilation = CompilationHelper.CreateCompilationWithInitOnlyProperties();
            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." };

            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics);
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>());
        }
Example #13
0
        public void RecordDerivedFromRecordInExternalAssembly()
        {
            // Compile the referenced assembly first.
            Compilation referencedCompilation = CompilationHelper.CreateReferencedSimpleLibRecordCompilation();

            // Emit the image of the referenced assembly.
            byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation);

            string source = @"
            using System.Text.Json.Serialization;
            using ReferencedAssembly;

            namespace HelloWorld
            {
                [JsonSerializable(typeof(AppRecord))]
                internal partial class JsonContext : JsonSerializerContext
                {
                }

                internal record AppRecord : LibRecord
                {
                    public string ExtraData { get; set; }
                }
            }";

            MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) };

            Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator);

            // Make sure compilation was successful.
            CheckCompilationDiagnosticsErrors(generatorDiags);
            CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());

            Dictionary <string, Type> types = generator.GetSerializableTypes();

            Assert.Equal(1, types.Count);
            Type recordType = types["HelloWorld.AppRecord"];

            Assert.Equal("HelloWorld.AppRecord", recordType.FullName);

            string[] expectedFieldsNames   = { "Country", "PhoneNumber" };
            string[] expectedPropertyNames = { "Address1", "Address2", "City", "ExtraData", "Id", "Name", "PostalCode", "State" };
            CheckFieldsPropertiesMethods(recordType, expectedFieldsNames, expectedPropertyNames, inspectBaseTypes: true);

            Assert.Equal(1, recordType.GetConstructors().Length);
        }
Example #14
0
        public void SuccessfulSourceGeneration()
        {
            // Compile the referenced assembly first.
            Compilation campaignCompilation = CompilationHelper.CreateCampaignSummaryViewModelCompilation();
            Compilation eventCompilation    = CompilationHelper.CreateActiveOrUpcomingEventCompilation();

            // Emit the image of the referenced assembly.
            byte[] campaignImage = CompilationHelper.CreateAssemblyImage(campaignCompilation);
            byte[] eventImage    = CompilationHelper.CreateAssemblyImage(eventCompilation);

            // Main source for current compilation.
            string source = @"
            using System.Collections.Generic;
            using System.Text.Json.Serialization;
            using ReferencedAssembly;

            namespace JsonSourceGenerator
            {
                [JsonSerializable(typeof(JsonSourceGenerator.IndexViewModel)]
                public partial class JsonContext : JsonSerializerContext
                {
                }

                public class IndexViewModel
                {
                    public List<ActiveOrUpcomingEvent> ActiveOrUpcomingEvents { get; set; }
                    public CampaignSummaryViewModel FeaturedCampaign { get; set; }
                    public bool IsNewAccount { get; set; }
                    public bool HasFeaturedCampaign => FeaturedCampaign != null;
                }
            }";

            MetadataReference[] additionalReferences =
            {
                MetadataReference.CreateFromImage(campaignImage),
                MetadataReference.CreateFromImage(eventImage),
            };

            Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator);

            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, generatorDiags, Array.Empty <(Location, string)>());
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, generatorDiags, Array.Empty <(Location, string)>());
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, generatorDiags, Array.Empty <(Location, string)>());
        }
        public void CollectionDictionarySourceGeneration()
        {
            // Compile the referenced assembly first.
            Compilation referencedCompilation = CompilationHelper.CreateReferencedHighLowTempsCompilation();

            // Emit the image of the referenced assembly.
            byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation);

            string source = @"
            using System;
            using System.Collections;
            using System.Collections.Generic;
            using System.Text.Json.Serialization;
            using ReferencedAssembly;
    
            namespace HelloWorld
            {
                [JsonSerializable(typeof(HelloWorld.WeatherForecastWithPOCOs))]
                internal partial class JsonContext : JsonSerializerContext
                {
                }

                public class WeatherForecastWithPOCOs
                {
                    public DateTimeOffset Date { get; set; }
                    public int TemperatureCelsius { get; set; }
                    public string Summary { get; set; }
                    public string SummaryField;
                    public List<DateTimeOffset> DatesAvailable { get; set; }
                    public Dictionary<string, HighLowTemps> TemperatureRanges { get; set; }
                    public string[] SummaryWords { get; set; }
                }
            }";

            MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) };

            Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator);

            // Make sure compilation was successful.

            CheckCompilationDiagnosticsErrors(generatorDiags);
            CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());
        }
Example #16
0
        public void WarnOnClassesWithInaccessibleJsonIncludeProperties()
        {
            Compilation         compilation = CompilationHelper.CreateCompilationWithInaccessibleJsonIncludeProperties();
            JsonSourceGenerator generator   = new JsonSourceGenerator();

            CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator);

            string[] expectedWarningDiagnostics = new string[]
            {
                "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."
            };

            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics);
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>());
        }
        public static void LocalJsonSerializableAttributeExpectedShape(string assemblyName, bool includeSTJ)
        {
            string source = @"using System;
using System.Text.Json.Serialization;

namespace System.Text.Json.Serialization
{
    [JsonSerializable(typeof(int))]
    [JsonSerializable(typeof(string), TypeInfoPropertyName = ""Str"")]
    internal partial class JsonContext : JsonSerializerContext
    {
    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
    public sealed class JsonSerializableAttribute : JsonAttribute
    {
        public string TypeInfoPropertyName { get; set; }

        public JsonSerializableAttribute(Type type) { }
    }
}";

            Compilation         compilation = CompilationHelper.CreateCompilation(source, additionalReferences: null, assemblyName, includeSTJ);
            JsonSourceGenerator generator   = new JsonSourceGenerator();

            CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator);

            Dictionary <string, Type> types = generator.GetSerializableTypes();

            if (includeSTJ)
            {
                Assert.Equal("System.Int32", types["System.Int32"].FullName);
                Assert.Equal("System.String", types["System.String"].FullName);
            }
            else
            {
                Assert.Null(types);
            }

            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>());
        }
Example #18
0
        public void ProgramsThatDontUseGeneratorCompile()
        {
            // No STJ usage.
            string              source      = @"using System;

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 <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>());

            // With STJ usage.
            source      = @"using System.Text.Json;

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 <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>());
        }
Example #19
0
        public void NameClashSourceGeneration()
        {
            // Without resolution.
            Compilation         compilation = CompilationHelper.CreateRepeatedLocationsCompilation();
            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." };

            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, expectedWarningDiagnostics);
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>());

            // With resolution.
            compilation = CompilationHelper.CreateRepeatedLocationsWithResolutionCompilation();
            generator   = new JsonSourceGenerator();
            CompilationHelper.RunGenerators(compilation, out generatorDiags, generator);

            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Info, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Warning, Array.Empty <string>());
            CompilationHelper.CheckDiagnosticMessages(generatorDiags, DiagnosticSeverity.Error, Array.Empty <string>());
        }
        public void TypeDiscoveryPrimitiveExternalPOCO()
        {
            // Compile the referenced assembly first.
            Compilation referencedCompilation = CompilationHelper.CreateReferencedLocationCompilation();

            // Emit the image of the referenced assembly.
            byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation);

            string source = @"
            using System.Text.Json.Serialization;
            using ReferencedAssembly;

            namespace HelloWorld
            {
                [JsonSerializable(typeof(HelloWorld.MyType))]
                [JsonSerializable(typeof(ReferencedAssembly.Location))]
                internal partial class JsonContext : JsonSerializerContext
                {
                }

                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() { }
                    public void UsePrivates()
                    {
                        PrivateDouble = 0;
                        PrivateChar = ' ';
                        double x = PrivateDouble;
                        string s = PrivateChar.ToString();
                    }
                }
            }";

            MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) };

            Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out ImmutableArray <Diagnostic> generatorDiags, generator);

            // Make sure compilation was successful.
            CheckCompilationDiagnosticsErrors(generatorDiags);
            CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());

            Dictionary <string, Type> types = generator.GetSerializableTypes();

            // Check base functionality of found types.
            Assert.Equal(2, types.Count);
            Type myType    = types["HelloWorld.MyType"];
            Type notMyType = types["ReferencedAssembly.Location"];

            // Check for MyType.
            Assert.Equal("HelloWorld.MyType", myType.FullName);

            // Check for received fields, properties and methods for MyType.
            string[] expectedFieldNamesMyType    = { "PublicChar", "PublicDouble" };
            string[] expectedPropertyNamesMyType = { "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, expectedFieldNamesMyType, expectedPropertyNamesMyType, expectedMethodNamesMyType);

            // Check for NotMyType.
            Assert.Equal("ReferencedAssembly.Location", notMyType.FullName);

            // Check for received fields, properties and methods for NotMyType.
            string[] expectedFieldNamesNotMyType    = { };
            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);
        }
        public void TypeDiscoveryWithRenamedAttribute()
        {
            // Compile the referenced assembly first.
            Compilation referencedCompilation = CompilationHelper.CreateReferencedLocationCompilation();

            // Emit the image of the referenced assembly.
            byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation);
            MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) };

            string source = @"
            using System.Text.Json.Serialization;
            using ReferencedAssembly;

            using @JsonSerializable = System.Runtime.Serialization.ContractNamespaceAttribute;
            using AliasedAttribute = System.Text.Json.Serialization.JsonSerializableAttribute;

            [assembly: AliasedAttribute(typeof(HelloWorld.MyType))]
            [assembly: AliasedAttribute(typeof(ReferencedAssembly.Location))]
            [module: @JsonSerializable(""my namespace"")]

            namespace HelloWorld
            {
                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() { }
                    public void UsePrivates()
                    {
                        PrivateDouble = 0;
                        PrivateChar = ' ';
                        double d = PrivateDouble;
                        char c = PrivateChar;
                    }
                }
            }";

            Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences);

            JsonSourceGenerator generator = new JsonSourceGenerator();

            Compilation newCompilation = CompilationHelper.RunGenerators(compilation, out var generatorDiags, generator);

            // Make sure compilation was successful.
            CheckCompilationDiagnosticsErrors(generatorDiags);
            CheckCompilationDiagnosticsErrors(newCompilation.GetDiagnostics());

            // Check base functionality of found types.
            Assert.Equal(2, generator.SerializableTypes.Count);

            // Check for MyType.
            Assert.Equal("HelloWorld.MyType", generator.SerializableTypes["HelloWorld.MyType"].FullName);

            // Check for received fields, properties and methods for MyType.
            string[] expectedFieldNamesMyType    = { "PublicChar", "PublicDouble" };
            string[] expectedPropertyNamesMyType = { "PublicPropertyInt", "PublicPropertyString" };
            string[] expectedMethodNamesMyType   = { "get_PrivatePropertyInt", "get_PrivatePropertyString", "get_PublicPropertyInt", "get_PublicPropertyString", "MyMethod", "MySecondMethod", "set_PrivatePropertyInt", "set_PrivatePropertyString", "set_PublicPropertyInt", "set_PublicPropertyString", "UsePrivates" };
            CheckFieldsPropertiesMethods("HelloWorld.MyType", ref generator, expectedFieldNamesMyType, expectedPropertyNamesMyType, expectedMethodNamesMyType);

            // Check for NotMyType.
            Assert.Equal("ReferencedAssembly.Location", generator.SerializableTypes["ReferencedAssembly.Location"].FullName);

            // Check for received fields, properties and methods for NotMyType.
            string[] expectedFieldNamesNotMyType    = { };
            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("ReferencedAssembly.Location", ref generator, expectedFieldNamesNotMyType, expectedPropertyNamesNotMyType, expectedMethodNamesNotMyType);
        }
Example #22
0
        public void EmitsDocumentationOnPublicMembersAndDoesNotCauseCS1591()
        {
            // Compile the referenced assembly first.
            Compilation documentedCompilation = CompilationHelper.CreateReferencedModelWithFullyDocumentedProperties();

            // Emit the image of the referenced assembly.
            byte[] documentedImage = CompilationHelper.CreateAssemblyImage(documentedCompilation);

            // Main source for current compilation.
            string source = @"
            using System.Collections.Generic;
            using System.Text.Json.Serialization;
            using ReferencedAssembly;

            namespace JsonSourceGenerator
            {
                /// <summary>
                /// Documentation
                /// </summary>
                [JsonSerializable(typeof(DocumentedModel))]
                [JsonSerializable(typeof(DocumentedModel2<string>))]
                public partial class JsonContext : JsonSerializerContext
                {
                }

                /// <summary>
                /// Documentation
                /// </summary>
                public class DocumentedModel2<T>
                {
                    /// <summary>
                    /// Documentation
                    /// </summary>
                    public List<Model> Models { get; set; }
                    /// documentation
                    public T Prop { get; set; }
                }

                /// <summary>
                /// Documentation
                /// </summary>
                public class DocumentedModel
                {
                    /// <summary>
                    /// Documentation
                    /// </summary>
                    public List<Model> Models { get; set; }
                }
            }";

            MetadataReference[] additionalReferences =
            {
                MetadataReference.CreateFromImage(documentedImage),
            };

            Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences, configureParseOptions: options => options.WithDocumentationMode(DocumentationMode.Diagnose));

            JsonSourceGenerator generator = new JsonSourceGenerator();

            compilation = CompilationHelper.RunGenerators(compilation, out var _, generator);

            using var emitStream = new MemoryStream();
            using var xmlStream  = new MemoryStream();
            var result      = compilation.Emit(emitStream, xmlDocumentationStream: xmlStream);
            var diagnostics = result.Diagnostics;

            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Info, diagnostics, Array.Empty <(Location, string)>());
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Warning, diagnostics, Array.Empty <(Location, string)>());
            CompilationHelper.CheckDiagnosticMessages(DiagnosticSeverity.Error, diagnostics, Array.Empty <(Location, string)>());
        }