ArxOne / MrAdvice

.NET aspect weaver (build task under NuGet package)
MIT License
308 stars 45 forks source link

[bug] Advice Attribute with Generic not working on separate project #209

Open moonheart opened 3 weeks ago

moonheart commented 3 weeks ago

reproduction repo: https://github.com/moonheart/MrAdvice_issue

Details

There are two advices in ClassLibrary1: GenericAdvice<TReturn> and NonGenericAdvice, when building finished, the NonGenericAdvice works as intended, but GenericAdvice<TReturn> only works in the same project as the advice .

public class GenericAdvice<TReturn>: Attribute, IMethodAdvice
{
    public void Advise(MethodAdviceContext context)
    {
        if (context.IsTargetMethodAsync)
        {
            context.ReturnValue = Task.FromResult((object)2);
        }
        else
        {
            context.ReturnValue = 2;
        }
    }
}

public class NonGenericAdvice: Attribute, IMethodAdvice
{
    public void Advise(MethodAdviceContext context)
    {
        if (context.IsTargetMethodAsync)
        {
            context.ReturnValue = Task.FromResult((object)2);
        }
        else
        {
            context.ReturnValue = 2;
        }
    }
}

Class in same project works:

namespace ClassLibrary1
{
  public class MyClass2
  {
    [GenericAdvice<List<int>>]
    public Task<int> Method1()
    {
      // ISSUE: method reference
      // ISSUE: method reference
      // ISSUE: method reference
      return (Task<int>) ⚡Invocation.ProceedAspect((object) this, __methodref (MyClass2.Method1), __methodref (MyClass2.Method1′), __methodref (MyClass2.Method1″));
    }

    [NonGenericAdvice]
    public Task<int> Method2()
    {
      // ISSUE: method reference
      // ISSUE: method reference
      // ISSUE: method reference
      return (Task<int>) ⚡Invocation.ProceedAspect((object) this, __methodref (MyClass2.Method2), __methodref (MyClass2.Method2′), __methodref (MyClass2.Method2″));
    }

    [ExecutionPoint]
    private Task<int> Method1′()
    {
      // ISSUE: object of a compiler-generated type is created
      // ISSUE: variable of a compiler-generated type
      MyClass2.<Method1>d__0 stateMachine = new MyClass2.<Method1>d__0();
      // ISSUE: reference to a compiler-generated field
      stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
      // ISSUE: reference to a compiler-generated field
      stateMachine.<>4__this = this;
      // ISSUE: reference to a compiler-generated field
      stateMachine.<>1__state = -1;
      // ISSUE: reference to a compiler-generated field
      stateMachine.<>t__builder.Start<MyClass2.<Method1>d__0>(ref stateMachine);
      // ISSUE: reference to a compiler-generated field
      return stateMachine.<>t__builder.Task;
    }

    private static object Method1″([In] object obj0, [In] object[] obj1)
    {
      return (object) ((MyClass2) obj0).Method1′();
    }

    [ExecutionPoint]
    private Task<int> Method2′()
    {
      // ISSUE: object of a compiler-generated type is created
      // ISSUE: variable of a compiler-generated type
      MyClass2.<Method2>d__1 stateMachine = new MyClass2.<Method2>d__1();
      // ISSUE: reference to a compiler-generated field
      stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
      // ISSUE: reference to a compiler-generated field
      stateMachine.<>4__this = this;
      // ISSUE: reference to a compiler-generated field
      stateMachine.<>1__state = -1;
      // ISSUE: reference to a compiler-generated field
      stateMachine.<>t__builder.Start<MyClass2.<Method2>d__1>(ref stateMachine);
      // ISSUE: reference to a compiler-generated field
      return stateMachine.<>t__builder.Task;
    }

    private static object Method2″([In] object obj0, [In] object[] obj1)
    {
      return (object) ((MyClass2) obj0).Method2′();
    }
  }
}

Class in different project not work:


public class MyClass1
{
  public async Task<int> Method1()
  {
    await Task.Delay(1); // <----- not weaved
    return 1;
  }

  [NonGenericAdvice]
  public Task<int> Method2()
  {
    // ISSUE: method reference
    // ISSUE: method reference
    // ISSUE: method reference
    return (Task<int>) ⚡Invocation.ProceedAspect((object) this, __methodref (MyClass1.Method2), __methodref (MyClass1.Method2′), __methodref (MyClass1.Method2″));
  }

  [ExecutionPoint]
  private Task<int> Method2′()
  {
    // ISSUE: object of a compiler-generated type is created
    // ISSUE: variable of a compiler-generated type
    MyClass1.<Method2>d__1 stateMachine = new MyClass1.<Method2>d__1();
    // ISSUE: reference to a compiler-generated field
    stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
    // ISSUE: reference to a compiler-generated field
    stateMachine.<>4__this = this;
    // ISSUE: reference to a compiler-generated field
    stateMachine.<>1__state = -1;
    // ISSUE: reference to a compiler-generated field
    stateMachine.<>t__builder.Start<MyClass1.<Method2>d__1>(ref stateMachine);
    // ISSUE: reference to a compiler-generated field
    return stateMachine.<>t__builder.Task;
  }

  private static object Method2″([In] object obj0, [In] object[] obj1)
  {
    return (object) ((MyClass1) obj0).Method2′();
  }
}