diff --git a/Mono.Cecil/AssemblyReader.cs b/Mono.Cecil/AssemblyReader.cs index ee2c229a9..4180d7895 100644 --- a/Mono.Cecil/AssemblyReader.cs +++ b/Mono.Cecil/AssemblyReader.cs @@ -3513,9 +3513,12 @@ public void ReadCustomAttributeConstructorArguments (CustomAttribute attribute, attribute.arguments = new Collection (count); - for (int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { + var parameterType = GenericParameterResolver.ResolveParameterTypeIfNeeded ( + attribute.Constructor, parameters [i]); attribute.arguments.Add ( - ReadCustomAttributeFixedArgument (parameters [i].ParameterType)); + ReadCustomAttributeFixedArgument (parameterType)); + } } CustomAttributeArgument ReadCustomAttributeFixedArgument (TypeReference type) diff --git a/Mono.Cecil/AssemblyWriter.cs b/Mono.Cecil/AssemblyWriter.cs index 3843e85c8..b8b2b143d 100644 --- a/Mono.Cecil/AssemblyWriter.cs +++ b/Mono.Cecil/AssemblyWriter.cs @@ -2928,8 +2928,11 @@ public void WriteCustomAttributeConstructorArguments (CustomAttribute attribute) if (parameters.Count != arguments.Count) throw new InvalidOperationException (); - for (int i = 0; i < arguments.Count; i++) - WriteCustomAttributeFixedArgument (parameters [i].ParameterType, arguments [i]); + for (int i = 0; i < arguments.Count; i++) { + var parameterType = GenericParameterResolver.ResolveParameterTypeIfNeeded ( + attribute.Constructor, parameters [i]); + WriteCustomAttributeFixedArgument (parameterType, arguments [i]); + } } void WriteCustomAttributeFixedArgument (TypeReference type, CustomAttributeArgument argument) diff --git a/Test/Mono.Cecil.Tests/CustomAttributesTests.cs b/Test/Mono.Cecil.Tests/CustomAttributesTests.cs index a406c4179..00f00ca47 100644 --- a/Test/Mono.Cecil.Tests/CustomAttributesTests.cs +++ b/Test/Mono.Cecil.Tests/CustomAttributesTests.cs @@ -464,6 +464,80 @@ public void GenericParameterConstraint () }, verify: !Platform.OnMono); } + [Test] + public void GenericAttributeString () + { + TestModule ("GenericAttributes.dll", module => { + var type = module.GetType ("WithGenericAttribute_OfString"); + Assert.IsTrue (type.HasCustomAttributes); + var attributes = type.CustomAttributes; + Assert.AreEqual (1, attributes.Count); + Assert.AreEqual ("GenericAttribute`1", attributes [0].AttributeType.FullName); + var attribute = attributes [0]; + // constructor arguments + Assert.AreEqual (true, attribute.HasConstructorArguments); + var argument = attribute.ConstructorArguments.Single (); + Assert.AreEqual ("System.String", argument.Type.FullName); + Assert.AreEqual ("t", argument.Value); + // named field argument + Assert.AreEqual (true, attribute.HasFields); + var field = attribute.Fields.Single (); + Assert.AreEqual ("F", field.Name); + Assert.AreEqual ("System.String", field.Argument.Type.FullName); + Assert.AreEqual ("f", field.Argument.Value); + // named property argument + Assert.AreEqual (true, attribute.HasProperties); + var property = attribute.Properties.Single (); + Assert.AreEqual ("P", property.Name); + Assert.AreEqual ("System.String", property.Argument.Type.FullName); + Assert.AreEqual ("p", property.Argument.Value); + + }, verify: !Platform.OnMono); + } + + [Test] + public void GenericAttributeInt () + { + TestModule ("GenericAttributes.dll", module => { + var type = module.GetType ("WithGenericAttribute_OfInt"); + Assert.IsTrue (type.HasCustomAttributes); + var attributes = type.CustomAttributes; + Assert.AreEqual (1, attributes.Count); + Assert.AreEqual ("GenericAttribute`1", attributes [0].AttributeType.FullName); + var attribute = attributes [0]; + // constructor arguments + Assert.AreEqual (true, attribute.HasConstructorArguments); + var argument = attribute.ConstructorArguments.Single (); + Assert.AreEqual ("System.Int32", argument.Type.FullName); + Assert.AreEqual (1, argument.Value); + // named field argument + Assert.AreEqual (true, attribute.HasFields); + var field = attribute.Fields.Single (); + Assert.AreEqual ("F", field.Name); + Assert.AreEqual ("System.Int32", field.Argument.Type.FullName); + Assert.AreEqual (2, field.Argument.Value); + // named property argument + Assert.AreEqual (true, attribute.HasProperties); + var property = attribute.Properties.Single (); + Assert.AreEqual ("P", property.Name); + Assert.AreEqual ("System.Int32", property.Argument.Type.FullName); + Assert.AreEqual (3, property.Argument.Value); + }, verify: !Platform.OnMono); + } + + [Test] + public void ConstrainedGenericAttribute () + { + TestModule ("GenericAttributes.dll", module => { + var type = module.GetType ("WithConstrainedGenericAttribute"); + Assert.IsTrue (type.HasCustomAttributes); + var attributes = type.CustomAttributes; + Assert.AreEqual (1, attributes.Count); + var attribute = attributes [0]; + Assert.AreEqual ("ConstrainedGenericAttribute`1", attribute.AttributeType.FullName); + }, verify: !Platform.OnMono); + } + [Test] public void NullCharInString () { diff --git a/Test/Resources/assemblies/GenericAttributes.dll b/Test/Resources/assemblies/GenericAttributes.dll new file mode 100644 index 000000000..1c8e8d6b8 Binary files /dev/null and b/Test/Resources/assemblies/GenericAttributes.dll differ