Skip to content

Commit

Permalink
add support for generic attributes (#117)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianoc committed Oct 23, 2022
1 parent 5a176eb commit 345e3e8
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
class C<T>
{
public void Method(T t) {}
}

class UsageOfNonGenericMethodOnGenericType
{
void M(C<int> c) => c.Method(42);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ class MyGenericAttribute<T> : System.Attribute
public T Value {get; set; }
}

/*
[MyGeneric<int>]
[MyGeneric<int>(42)]
[MyGeneric<string>("gen-attr-value")]
[MyGeneric<bool>(Value = true)]
class Foo {}
*/
[MyGeneric<bool>(true)]
[MyGeneric<string>("str", Value="Other str")]
class Foo {}
6 changes: 6 additions & 0 deletions Cecilifier.Core.Tests/Tests/Integration/GenericsTestCase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,11 @@ public void TestCoContraVariance()
{
AssertResourceTest(@"Generics/CoContraVariance");
}

[Test]
public void TestUsageOfNonGenericMethodOnGenericType()
{
AssertResourceTest("Generics/UsageOfNonGenericMethodOnGenericType");
}
}
}
19 changes: 19 additions & 0 deletions Cecilifier.Core.Tests/Tests/Unit/AttributesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,25 @@ public void TestGenericAttributeDefinition()
@"\s+.+(gp_T_\d+) = new Mono.Cecil.GenericParameter\(""T"", \1\);" +
@"\s+.+\1.GenericParameters.Add\(\2\);"));
}

[TestCase("[MyGeneric<int>]", "Int32", TestName="Value Type")]
[TestCase("[MyGeneric<string>]", "String", TestName = "Reference Type")]
[TestCase("[MyGeneric<Foo<int>>]", @"cls_foo_\d+.MakeGenericInstanceType\(.+Int32\)", TestName = "Generic Type")]
public void TestGenericAttributeUsage(string attribute, string expectedType)
{
var result = RunCecilifier($@"
{GenericAttributeDefinition}
{attribute}
class Foo<TFoo> {{ }}");

var cecilifiedCode = result.GeneratedCode.ReadToEnd();
Assert.That(
cecilifiedCode,
Does.Match(
$@"(?s)var (attr_myGeneric_1_\d+) = new CustomAttribute\(new MethodReference\((ctor_myGenericAttribute_\d+)\.Name.+\2\.ReturnType\).+DeclaringType = cls_myGenericAttribute_\d+.MakeGenericInstanceType\(.*{expectedType}\).+\);\s+" +
@"cls_foo_\d+\.CustomAttributes\.Add\(\1\);"));
}

private const string AttributeDefinition = "class MyAttribute : System.Attribute { public MyAttribute(string message) {} } ";
private const string GenericAttributeDefinition = @"
Expand Down
6 changes: 1 addition & 5 deletions Cecilifier.Core/AST/SyntaxWalkerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -822,11 +822,7 @@ private static IEnumerable<string> ProcessNormalMemberAttribute(IVisitorContext
// Attribute is defined in the same assembly. We need to find the variable that holds its "ctor declaration"
var attrCtor = attrType.GetMembers().OfType<IMethodSymbol>().SingleOrDefault(m => m.MethodKind == MethodKind.Constructor && m.Parameters.Length == attrArgs.Length);
EnsureForwardedMethod(context, context.Naming.SyntheticVariable(attribute.Name.ValueText().AttributeName(), ElementKind.Constructor), attrCtor, Array.Empty<TypeParameterSyntax>());
var attrCtorVar = context.DefinitionVariables.GetMethodVariable(attrCtor.AsMethodDefinitionVariable());
if (!attrCtorVar.IsValid)
throw new Exception($"Could not find variable for {attrCtor.ContainingType.Name} ctor.");

return attrCtorVar.VariableName;
return attrCtor.MethodResolverExpression(context);
});

return attrsExp;
Expand Down
5 changes: 5 additions & 0 deletions Cecilifier.Core/Misc/NameSyntaxExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@ public class SimpleNameExtractor : CSharpSyntaxVisitor<string>
{
return node.Identifier.Text;
}

public override string VisitGenericName(GenericNameSyntax node)
{
return $"{node.Identifier.Text}_{node.Arity}";
}
}
}

0 comments on commit 345e3e8

Please sign in to comment.