diff --git a/CHANGELOG.md b/CHANGELOG.md index bfef439bc2..4882062564 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Castle Core Changelog +## Unreleased + +Bugfixes: +- Nested custom attribute types do not get replicated (@stakx, #638) + ## 5.1.0 (2022-08-02) Enhancements: diff --git a/src/Castle.Core.Tests/DynamicProxy.Tests/ClassWithAttributesTestCase.cs b/src/Castle.Core.Tests/DynamicProxy.Tests/ClassWithAttributesTestCase.cs index 0acfa572c5..fd8d893eda 100644 --- a/src/Castle.Core.Tests/DynamicProxy.Tests/ClassWithAttributesTestCase.cs +++ b/src/Castle.Core.Tests/DynamicProxy.Tests/ClassWithAttributesTestCase.cs @@ -112,6 +112,53 @@ public void EnsureProxyHasAttributesOnGenericArgument() Assert.IsTrue(nameProperty.IsDefined(typeof(NonInheritableAttribute), false)); } + [Test] + public void EnsureProxyHasNestedAttributesOnClassAndMethods() + { + var instance = (HasNestedNonInheritableAttribute)generator.CreateClassProxy(typeof(HasNestedNonInheritableAttribute), new StandardInterceptor()); + + object[] attributes = instance.GetType().GetCustomAttributes(typeof(Nested.NonInheritableAttribute), false).ToArray(); + Assert.AreEqual(1, attributes.Length); + Assert.IsInstanceOf(typeof(Nested.NonInheritableAttribute), attributes[0]); + + attributes = instance.GetType().GetMethod("OnMethod").GetCustomAttributes(typeof(Nested.NonInheritableAttribute), false).ToArray(); + Assert.AreEqual(1, attributes.Length); + Assert.IsInstanceOf(typeof(Nested.NonInheritableAttribute), attributes[0]); + } + + [Test] + public void EnsureProxyHasNestedAttributesOnProperties() + { + var proxy = generator.CreateClassProxy(); + var nameProperty = proxy.GetType().GetProperty("OnProperty"); + Assert.IsTrue(nameProperty.IsDefined(typeof(Nested.NonInheritableAttribute), false)); + } + + [Test, Ignore("Not supported. Is it possible? There seems to be no API to allow that.")] + public void EnsureProxyHasNestedAttributesOnOnReturn() + { + var proxy = generator.CreateClassProxy(); + var nameProperty = proxy.GetType().GetMethod("OnReturn").ReturnParameter; + Assert.IsTrue(nameProperty.IsDefined(typeof(Nested.NonInheritableAttribute), false)); + } + + [Test] + public void EnsureProxyHasNestedAttributesOnParameter() + { + var proxy = generator.CreateClassProxy(); + ParameterInfo nameProperty = proxy.GetType().GetMethod("OnParameter").GetParameters().Single(); + Assert.IsTrue(nameProperty.IsDefined(typeof(Nested.NonInheritableAttribute), false)); + } + + [Test] + [Platform(Exclude = "Mono", Reason = "Mono does not currently emit custom attributes on generic type parameters of methods. See https://github.com/mono/mono/issues/8512.")] + public void EnsureProxyHasNestedAttributesOnGenericArgument() + { + var proxy = generator.CreateClassProxy(); + var nameProperty = proxy.GetType().GetMethod("OnGenericArgument").GetGenericArguments().Single(); + Assert.IsTrue(nameProperty.IsDefined(typeof(Nested.NonInheritableAttribute), false)); + } + [Test] public void Can_proxy_type_with_non_inheritable_attribute_depending_on_array_of_something_via_property() { diff --git a/src/Castle.Core.Tests/DynamicProxy.Tests/Classes/HasNestedNonInheritableAttribute.cs b/src/Castle.Core.Tests/DynamicProxy.Tests/Classes/HasNestedNonInheritableAttribute.cs new file mode 100644 index 0000000000..57c922ab94 --- /dev/null +++ b/src/Castle.Core.Tests/DynamicProxy.Tests/Classes/HasNestedNonInheritableAttribute.cs @@ -0,0 +1,45 @@ +// Copyright 2004-2022 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Tests.Classes +{ + [Nested.NonInheritable] + public class HasNestedNonInheritableAttribute + { + [Nested.NonInheritable] + public virtual void OnMethod() + { + } + + [Nested.NonInheritable] + public virtual string OnProperty + { + get; set; + } + + [return: Nested.NonInheritable] + public virtual int OnReturn() + { + return 1; + } + + public virtual void OnParameter([Nested.NonInheritable] int arg) + { + } + + public virtual void OnGenericArgument<[Nested.NonInheritable] T>() + { + } + } +} diff --git a/src/Castle.Core.Tests/DynamicProxy.Tests/Classes/NestedNonInheritableAttribute.cs b/src/Castle.Core.Tests/DynamicProxy.Tests/Classes/NestedNonInheritableAttribute.cs new file mode 100644 index 0000000000..a0ebf7e238 --- /dev/null +++ b/src/Castle.Core.Tests/DynamicProxy.Tests/Classes/NestedNonInheritableAttribute.cs @@ -0,0 +1,29 @@ +// Copyright 2004-2022 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.DynamicProxy.Tests.Classes +{ + using System; + + public partial class Nested + { +#if FEATURE_SERIALIZATION + [Serializable] +#endif + [AttributeUsage(AttributeTargets.All, Inherited = false)] + public class NonInheritableAttribute : Attribute + { + } + } +} diff --git a/src/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs b/src/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs index e773080c6b..6d41677fa1 100644 --- a/src/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs +++ b/src/Castle.Core/DynamicProxy/Internal/AttributeUtil.cs @@ -185,7 +185,7 @@ public static IEnumerable GetNonInheritableAttributes(this /// private static bool ShouldSkipAttributeReplication(Type attribute, bool ignoreInheritance) { - if (attribute.IsPublic == false) + if (attribute.IsPublic == false && attribute.IsNestedPublic == false) { return true; }