diff --git a/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentReader.cs b/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentReader.cs index 049304131..246f8a27f 100644 --- a/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentReader.cs +++ b/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentReader.cs @@ -39,7 +39,7 @@ public void ReadValue(in BlobReadContext context, ref BinaryStreamReader reader, string? typeFullName = reader.ReadSerString(); var type = typeFullName is not null ? TypeNameParser.Parse(module, typeFullName) - : context.ReaderContext.BadImageAndReturn("Type full name in attribute argument is null."); + : null; Elements.Add(type); return; diff --git a/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentWriter.cs b/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentWriter.cs index c691a57cf..71049ab4b 100644 --- a/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentWriter.cs +++ b/src/AsmResolver.DotNet/Signatures/CustomAttributeArgumentWriter.cs @@ -52,6 +52,13 @@ private void WriteElement(TypeSignature argumentType, object? element) private void WriteNullElement(TypeSignature argumentType) { var writer = _context.Writer; + + if (argumentType.IsTypeOf("System", "Type")) + { + writer.WriteSerString(default(string)); + return; + } + switch (argumentType.ElementType) { case ElementType.String: diff --git a/test/AsmResolver.DotNet.Tests/CustomAttributeTest.cs b/test/AsmResolver.DotNet.Tests/CustomAttributeTest.cs index 903b65c44..3c7da128b 100644 --- a/test/AsmResolver.DotNet.Tests/CustomAttributeTest.cs +++ b/test/AsmResolver.DotNet.Tests/CustomAttributeTest.cs @@ -139,6 +139,16 @@ public void FixedEnumArgument(bool rebuild) Assert.Equal((int) TestEnum.Value3, argument.Element); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public void FixedNullTypeArgument(bool rebuild) + { + var attribute = GetCustomAttributeTestCase(nameof(CustomAttributesTestClass.FixedNullTypeArgument), rebuild); + var fixedArg = Assert.Single(attribute.Signature.FixedArguments); + Assert.Null(fixedArg.Element); + } + [Theory] [InlineData(false)] [InlineData(true)] diff --git a/test/TestBinaries/DotNet/AsmResolver.DotNet.TestCases.CustomAttributes/CustomAttributesTestClass.cs b/test/TestBinaries/DotNet/AsmResolver.DotNet.TestCases.CustomAttributes/CustomAttributesTestClass.cs index e56c33afe..852f2d44f 100644 --- a/test/TestBinaries/DotNet/AsmResolver.DotNet.TestCases.CustomAttributes/CustomAttributesTestClass.cs +++ b/test/TestBinaries/DotNet/AsmResolver.DotNet.TestCases.CustomAttributes/CustomAttributesTestClass.cs @@ -1,133 +1,138 @@ -using System; -using System.Collections.Generic; - -// Disable warnings for unused members. -#pragma warning disable 67 - -namespace AsmResolver.DotNet.TestCases.CustomAttributes -{ - [TestCase] - public class CustomAttributesTestClass - { - [TestCase] - public event EventHandler TestEvent; - - [TestCase] - public int TestField; - - [TestCase] - public void TestMethod([TestCase] int testParameter) - { - } - - [TestCase] - public int TestProperty - { - [TestCase] - get; - [TestCase] - set; - } - - [TestCase(1)] - public void FixedInt32Argument() - { - } - - [TestCase("String fixed arg")] - public void FixedStringArgument() - { - } - - [TestCase(TestEnum.Value3)] - public void FixedEnumArgument() - { - } - - [TestCase(typeof(string))] - public void FixedTypeArgument() - { - } - - [TestCase(typeof(KeyValuePair))] - public void FixedComplexTypeArgument() - { - } - - [TestCase(2, "Fixed arg", TestEnum.Value3)] - public void FixedMultipleArguments() - { - } - - [TestCase(IntValue = 2)] - public void NamedInt32Argument() - { - } - - [TestCase(StringValue = "String named arg")] - public void NamedStringArgument() - { - } - - [TestCase(EnumValue = TestEnum.Value2)] - public void NamedEnumArgument() - { - } - - [TestCase(TypeValue = typeof(int))] - public void NamedTypeArgument() - { - } - - [TestCase(typeof(TestGenericType))] - public void GenericType() - { - } - - [TestCase(typeof(TestGenericType[]))] - public void GenericTypeArray() - { - } - - [TestCase((object) 123)] - public void Int32PassedAsObject() - { - } - - [TestCase((object) typeof(int))] - public void TypePassedAsObject() - { - } - - [TestCase(new int[] {1, 2, 3, 4})] - public void FixedInt32ArrayArgument() - { - } - - [TestCase(default(int[]))] - public void FixedInt32ArrayNullArgument() - { - } - - [TestCase(new int[0])] - public void FixedInt32ArrayEmptyArgument() - { - } - - [TestCase((object) new int[] {1, 2, 3, 4})] - public void FixedInt32ArrayAsObjectArgument() - { - } - - [TestCase((object) default(int[]))] - public void FixedInt32ArrayAsObjectNullArgument() - { - } - - [TestCase((object) new int[0])] - public void FixedInt32ArrayAsObjectEmptyArgument() - { - } - - } -} \ No newline at end of file +using System; +using System.Collections.Generic; + +// Disable warnings for unused members. +#pragma warning disable 67 + +namespace AsmResolver.DotNet.TestCases.CustomAttributes +{ + [TestCase] + public class CustomAttributesTestClass + { + [TestCase] + public event EventHandler TestEvent; + + [TestCase] + public int TestField; + + [TestCase] + public void TestMethod([TestCase] int testParameter) + { + } + + [TestCase] + public int TestProperty + { + [TestCase] + get; + [TestCase] + set; + } + + [TestCase(1)] + public void FixedInt32Argument() + { + } + + [TestCase("String fixed arg")] + public void FixedStringArgument() + { + } + + [TestCase(TestEnum.Value3)] + public void FixedEnumArgument() + { + } + + [TestCase(typeof(string))] + public void FixedTypeArgument() + { + } + + [TestCase(typeof(KeyValuePair))] + public void FixedComplexTypeArgument() + { + } + + [TestCase(2, "Fixed arg", TestEnum.Value3)] + public void FixedMultipleArguments() + { + } + + [TestCase(IntValue = 2)] + public void NamedInt32Argument() + { + } + + [TestCase(StringValue = "String named arg")] + public void NamedStringArgument() + { + } + + [TestCase(EnumValue = TestEnum.Value2)] + public void NamedEnumArgument() + { + } + + [TestCase(TypeValue = typeof(int))] + public void NamedTypeArgument() + { + } + + [TestCase(typeof(TestGenericType))] + public void GenericType() + { + } + + [TestCase(typeof(TestGenericType[]))] + public void GenericTypeArray() + { + } + + [TestCase((object) 123)] + public void Int32PassedAsObject() + { + } + + [TestCase((object) typeof(int))] + public void TypePassedAsObject() + { + } + + [TestCase(new int[] {1, 2, 3, 4})] + public void FixedInt32ArrayArgument() + { + } + + [TestCase(default(int[]))] + public void FixedInt32ArrayNullArgument() + { + } + + [TestCase(new int[0])] + public void FixedInt32ArrayEmptyArgument() + { + } + + [TestCase((object) new int[] {1, 2, 3, 4})] + public void FixedInt32ArrayAsObjectArgument() + { + } + + [TestCase((object) default(int[]))] + public void FixedInt32ArrayAsObjectNullArgument() + { + } + + [TestCase((object) new int[0])] + public void FixedInt32ArrayAsObjectEmptyArgument() + { + } + + [TestCase((Type) null)] + public void FixedNullTypeArgument() + { + } + + } +}