From 032f1e49642d185831a316cdc32e5aa07ebc7e64 Mon Sep 17 00:00:00 2001 From: "andreas.hoffmann" Date: Tue, 15 Mar 2022 20:51:47 +0100 Subject: [PATCH] Added MaybeNullAttribute and fixed tests with the correct check. Changes to Compiler.cs are not necessary anymore. --- XmlSchemaClassGenerator.Tests/Compiler.cs | 59 +++++++---------------- XmlSchemaClassGenerator.Tests/XmlTests.cs | 34 ++++++------- XmlSchemaClassGenerator/TypeModel.cs | 3 +- 3 files changed, 37 insertions(+), 59 deletions(-) diff --git a/XmlSchemaClassGenerator.Tests/Compiler.cs b/XmlSchemaClassGenerator.Tests/Compiler.cs index e0492624..95453d4a 100644 --- a/XmlSchemaClassGenerator.Tests/Compiler.cs +++ b/XmlSchemaClassGenerator.Tests/Compiler.cs @@ -33,7 +33,7 @@ public static CompilationResult GenerateAssembly(Compilation compilation) }; } - private static readonly ConcurrentDictionary, Assembly>> Assemblies = new(); + private static readonly ConcurrentDictionary Assemblies = new(); private static readonly string[] DependencyAssemblies = new[] { @@ -55,33 +55,21 @@ public static CompilationResult GenerateAssembly(Compilation compilation) public static Assembly GetAssembly(string name) { Assemblies.TryGetValue(name, out var assembly); - return assembly.Item2; - } - - public static Assembly Generate(string name, string pattern, Generator generatorPrototype = null) - { - (_, var assembly) = GenerateVerbose(name, pattern, generatorPrototype); - return assembly; + return assembly; } - public static (List, Assembly) GenerateVerbose(string name, string pattern, Generator generatorPrototype = null) - { - if (Assemblies.TryGetValue(name, out var assembly)) { return (assembly.Item1, assembly.Item2); } + public static Assembly Generate(string name, string pattern, Generator generatorPrototype = null) + { + if (Assemblies.ContainsKey(name)) { return Assemblies[name]; } var files = Glob.ExpandNames(pattern).OrderByDescending(f => f); - return GenerateFilesVerbose(name, files, generatorPrototype); + return GenerateFiles(name, files, generatorPrototype); } - public static Assembly GenerateFiles(string name, IEnumerable files, Generator generatorPrototype = null) - { - (_, var assembly) = GenerateFilesVerbose(name, files, generatorPrototype); - return assembly; - } - - public static (List, Assembly) GenerateFilesVerbose(string name, IEnumerable files, Generator generatorPrototype = null) - { - if (Assemblies.TryGetValue(name, out var assembly)) { return (assembly.Item1, assembly.Item2); } + public static Assembly GenerateFiles(string name, IEnumerable files, Generator generatorPrototype = null) + { + if (Assemblies.ContainsKey(name)) { return Assemblies[name]; } generatorPrototype ??= new Generator { @@ -125,6 +113,7 @@ public static (List, Assembly) GenerateFilesVerbose(string name, IEn UniqueTypeNamesAcrossNamespaces = generatorPrototype.UniqueTypeNamesAcrossNamespaces, CreateGeneratedCodeAttributeVersion = generatorPrototype.CreateGeneratedCodeAttributeVersion, NetCoreSpecificCode = generatorPrototype.NetCoreSpecificCode, + EnableNullableReferenceAttributes = generatorPrototype.EnableNullableReferenceAttributes, NamingScheme = generatorPrototype.NamingScheme }; @@ -135,18 +124,12 @@ public static (List, Assembly) GenerateFilesVerbose(string name, IEn gen.Generate(files); - return CompileFilesVerbose(name, output.Files); + return CompileFiles(name, output.Files); } - public static Assembly CompileFiles(string name, IEnumerable files) - { - (_, var assembly) = CompileFilesVerbose(name, files); - return assembly; - } - - public static (List, Assembly) CompileFilesVerbose(string name, IEnumerable files) - { - return CompileVerbose(name, files.Select(f => File.ReadAllText(f)).ToArray()); + public static Assembly CompileFiles(string name, IEnumerable files) + { + return Compile(name, files.Select(f => File.ReadAllText(f)).ToArray()); } private static readonly LanguageVersion MaxLanguageVersion = Enum @@ -154,21 +137,15 @@ public static (List, Assembly) CompileFilesVerbose(string name, IEnu .Cast() .Max(); - public static Assembly Compile(string name, params string[] contents) + public static Assembly Compile(string name, params string[] contents) { - (_, var assembly) = CompileVerbose(name, contents); - return assembly; - } - - public static (List, Assembly) CompileVerbose(string name, params string[] contents) - { var trustedAssembliesPaths = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")).Split(Path.PathSeparator); var references = trustedAssembliesPaths .Where(p => DependencyAssemblies.Contains(Path.GetFileNameWithoutExtension(p))) .Select(p => MetadataReference.CreateFromFile(p)) .ToList(); var options = new CSharpParseOptions(kind: SourceCodeKind.Regular, languageVersion: MaxLanguageVersion); - var syntaxTrees = contents.Select(c => CSharpSyntaxTree.ParseText(c, options)).ToList(); + var syntaxTrees = contents.Select(c => CSharpSyntaxTree.ParseText(c, options)); var compilation = CSharpCompilation.Create(name, syntaxTrees) .AddReferences(references) .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); @@ -179,9 +156,9 @@ public static (List, Assembly) CompileVerbose(string name, params st Assert.True(result.Result.Success); Assert.NotNull(result.Assembly); - Assemblies[name] = Tuple.Create(syntaxTrees, result.Assembly); + Assemblies[name] = result.Assembly; - return (syntaxTrees, result.Assembly); + return result.Assembly; } } } diff --git a/XmlSchemaClassGenerator.Tests/XmlTests.cs b/XmlSchemaClassGenerator.Tests/XmlTests.cs index 9bed8e72..f32c41d8 100644 --- a/XmlSchemaClassGenerator.Tests/XmlTests.cs +++ b/XmlSchemaClassGenerator.Tests/XmlTests.cs @@ -2,6 +2,7 @@ using System.CodeDom; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; @@ -2382,27 +2383,26 @@ public void TestNullableReferenceAttributes() GenerateNamespace = key => "Test" } }; - //Unfortunately, I did not find access to the Attribute "AllowNull" in the generated Assembly. - //It is just not accessible via "CustomAttributes". - //So I have to parse the Syntax-Tree to find it. - (var syntaxTrees, _) = Compiler.GenerateVerbose(nameof(TestNullableReferenceAttributes), NullableReferenceAttributesPattern, generator); + var assembly = Compiler.Generate(nameof(TestNullableReferenceAttributes), NullableReferenceAttributesPattern, generator); void assertNullable(string typename, bool nullable) { - var root = (CompilationUnitSyntax)syntaxTrees.Single().GetRoot(); - var ns = (NamespaceDeclarationSyntax)root.Members.Single(); - var c1 = (ClassDeclarationSyntax)ns.Members.Single( - m => m is ClassDeclarationSyntax c && c.Identifier.ToString() == typename - ); - var p = (PropertyDeclarationSyntax)c1.Members.Single(m => m is PropertyDeclarationSyntax n && n.Identifier.ToString() == "Text"); - var hasAllowNullAttribute = p.AttributeLists.Any(d => d.Attributes.Any(a => a.GetText().ToString() == "System.Diagnostics.CodeAnalysis.AllowNullAttribute()")); + Type c = assembly.GetType(typename); + var property = c.GetProperty("Text"); + var setParameter = property.SetMethod.GetParameters(); + var getReturnParameter = property.GetMethod.ReturnParameter; + var allowNullableAttribute = setParameter.Single().CustomAttributes.SingleOrDefault(a => a.AttributeType == typeof(AllowNullAttribute)); + var maybeNullAttribute = getReturnParameter.CustomAttributes.SingleOrDefault(a => a.AttributeType == typeof(MaybeNullAttribute)); + var hasAllowNullAttribute = allowNullableAttribute != null; + var hasMaybeNullAttribute = maybeNullAttribute != null; Assert.Equal(nullable, hasAllowNullAttribute); + Assert.Equal(nullable, hasMaybeNullAttribute); } - assertNullable("ElementReferenceNullable", true); - assertNullable("ElementReferenceList", true); - assertNullable("ElementReferenceNonNullable", false); - assertNullable("AttributeReferenceNullable", true); - assertNullable("AttributeReferenceNonNullable", false); - assertNullable("AttributeValueNullableInt", false); + assertNullable("Test.ElementReferenceNullable", true); + assertNullable("Test.ElementReferenceList", true); + assertNullable("Test.ElementReferenceNonNullable", false); + assertNullable("Test.AttributeReferenceNullable", true); + assertNullable("Test.AttributeReferenceNonNullable", false); + assertNullable("Test.AttributeValueNullableInt", false); } [Fact, TestPriority(1)] diff --git a/XmlSchemaClassGenerator/TypeModel.cs b/XmlSchemaClassGenerator/TypeModel.cs index e3482df4..80b31f77 100644 --- a/XmlSchemaClassGenerator/TypeModel.cs +++ b/XmlSchemaClassGenerator/TypeModel.cs @@ -1127,7 +1127,8 @@ public void AddMembersTo(CodeTypeDeclaration typeDeclaration, bool withDataBindi if (isNullableReferenceType && Configuration.EnableNullableReferenceAttributes) { member.CustomAttributes.Add(new CodeAttributeDeclaration("System.Diagnostics.CodeAnalysis.AllowNullAttribute")); - } + member.CustomAttributes.Add(new CodeAttributeDeclaration("System.Diagnostics.CodeAnalysis.MaybeNullAttribute")); + } var attributes = GetAttributes(isArray).ToArray(); member.CustomAttributes.AddRange(attributes);