Skip to content

Commit

Permalink
Make sure attributes used by compiler is not used in codegen + test f…
Browse files Browse the repository at this point in the history
…or required modifier (#472)
  • Loading branch information
SandstromErik authored Dec 22, 2023
1 parent f786760 commit 415f3ec
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 17 deletions.
24 changes: 7 additions & 17 deletions src/OpenRiaServices.Tools/Framework/DataContractProxyGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ internal abstract class DataContractProxyGenerator : ProxyGenerator
{
private readonly bool _isRoundtripType;
private readonly IDictionary<Type, CodeTypeDeclaration> _typeMapping;
private readonly List<Type> _attributeTypesToFilter;

/// <summary>
/// Initializes a new instance of the <see cref="DataContractProxyGenerator"/> class.
Expand All @@ -37,19 +36,6 @@ protected DataContractProxyGenerator(CodeDomClientCodeGenerator proxyGenerator,
_typeMapping = typeMapping;
NotificationMethodGen = new NotificationMethodGenerator(proxyGenerator);
_isRoundtripType = type.Attributes()[typeof(RoundtripOriginalAttribute)] != null;

// Add attributes which should be used to filter the attributes on type to be generated
_attributeTypesToFilter = new()
{
// DataContractAttribute and KnownTypeAttribute are handled seperatly
typeof(DataContractAttribute),
typeof(KnownTypeAttribute),
#if NET
// Filter out NullableAttribute and NullableContextAttribute, should only be used by compiler
Type.GetType("System.Runtime.CompilerServices.NullableAttribute"),
Type.GetType("System.Runtime.CompilerServices.NullableContextAttribute"),
#endif
};
}

/// <summary>
Expand Down Expand Up @@ -399,7 +385,8 @@ protected virtual void GenerateProperty(PropertyDescriptor propertyDescriptor)
property.Name = propertyName;
property.Type = propTypeReference;
property.Attributes = MemberAttributes.Public | MemberAttributes.Final; // final needed, else becomes virtual
List<Attribute> propertyAttributes = propertyDescriptor.ExplicitAttributes().Cast<Attribute>().ToList();
var propertyAttributes = propertyDescriptor.ExplicitAttributes().Cast<Attribute>()
.Where(a => a.GetType().Namespace != "System.Runtime.CompilerServices").ToList(); //Do not use attributes only used by the compiler

// Generate <summary> for property
string comment = string.Format(CultureInfo.CurrentCulture, Resource.CodeGen_Entity_Property_Summary_Comment, propertyName);
Expand Down Expand Up @@ -549,8 +536,11 @@ private IEnumerable<Attribute> FilterTypeAttributes(AttributeCollection typeAttr
}
}

// Filter out attributes in filteredAttributes and attributeTypesToFilter
return typeAttributes.Cast<Attribute>().Where(a => !_attributeTypesToFilter.Contains(a.GetType()) && !filteredAttributes.Contains(a));
// Filter out attributes in filteredAttributes, attributes which should only be used by the compiler,
// DataContractAttribute and KnownTypeAttribute since they are handled seperatly
return typeAttributes.Cast<Attribute>().Where(a => a.GetType().Namespace != "System.Runtime.CompilerServices"
&& a.GetType() != typeof(DataContractAttribute) && a.GetType() != typeof(KnownTypeAttribute)
&& !filteredAttributes.Contains(a));
}

/// <summary>
Expand Down
31 changes: 31 additions & 0 deletions src/OpenRiaServices.Tools/Test/CodeGenRequiredModifierTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#if NET7_0_OR_GREATER //required modifier does not work before net7
using System.ComponentModel.DataAnnotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace OpenRiaServices.Tools.Test;

/// <summary>
/// CodeGen tests for the required modifier
/// </summary>
[TestClass]
public class CodeGenRequiredModifierTests
{
[TestMethod]
[Description("CodeGen does not apply compiler exclusive attribute for required")]
public void CodeGen_Required_Modifier_Dont_Use_Compiler_Attributes()
{
MockSharedCodeService sts = TestHelper.CreateCommonMockSharedCodeService();
string generatedCode = TestHelper.GenerateCodeAssertSuccess("C#", new Type[] {typeof(Mock_CG_Required_Entity_DomainService) }, null, sts);
TestHelper.AssertGeneratedCodeDoesNotContain(generatedCode, "RequiredMember");
}
}

public class Mock_CG_Required_Entity_DomainService : GenericDomainService<Mock_CG_Required_Entity> { }

public class Mock_CG_Required_Entity
{
[Key]
public required string RequiredProperty { get; set; }
}
#endif

0 comments on commit 415f3ec

Please sign in to comment.