| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The aspect '<AspectType>' cannot generate the forwarding constructor '<Forwarder>' because the pull strategy returned '<ReturnedKind>' for the parameter '<IntroducedParameter>'. For a forwarding constructor, the pull strategy must provide a value, for instance with PullAction.UseExpression, and must not return PullAction.None. |
Cause
When an aspect introduces a parameter into a constructor with the IntroduceParameter method and an overloading strategy like ForwardSourceConstructors, Metalama generates a forwarding constructor. This constructor keeps the original signature and calls the modified constructor with : this(...). It must pass a value for the new parameter, and it asks the pull strategy, an IPullStrategy, for this value.
Because the signature of the forwarding constructor is fixed, the pull strategy must return an action that provides a value. Metalama reports LAMA0536 when the strategy returns None, which means that no value is passed. In the message, <ReturnedKind> is the internal name of the returned action, for example DoNotPull for PullAction.None.
In the following example, the custom pull strategy of the AddTimestamp aspect returns PullAction.None.
1using System;
2using Metalama.Framework.Advising;
3using Metalama.Framework.Aspects;
4using Metalama.Framework.Code;
5
6namespace Doc.LAMA0536.Error;
7
8public class TimestampPullStrategy : IPullStrategy
9{
10 // Error: PullAction.None gives no value for the forwarding constructor to pass.
11 public PullAction GetPullAction( IParameter pulledParameter, IHasParameters targetMember ) => PullAction.None;
12}
13
14public class AddTimestampAttribute : TypeAspect
15{
16 public override void BuildAspect( IAspectBuilder<INamedType> builder )
17 {
18 foreach ( var constructor in builder.Target.Constructors )
19 {
20 builder.With( constructor )
21 .IntroduceParameter(
22 "creationTime",
23 typeof(DateTime),
24 pullStrategy: new TimestampPullStrategy(),
25 overloadingStrategy: ConstructorOverloadingStrategy.ForwardSourceConstructors );
26 }
27 }
28}
29
1namespace Doc.LAMA0536.Error;
2
3// The [AddTimestamp] aspect adds a creationTime parameter and a forwarding constructor.
4[AddTimestamp]
Error LAMA0536: The aspect 'AddTimestamp' cannot generate the forwarding constructor 'Order.Order(int)' because the pull strategy returned 'PullAction.None' for the parameter 'Order.Order(int)@creationTime'. For a forwarding constructor, the pull strategy must provide a value, for instance with PullAction.UseExpression, and must not return PullAction.None.
5internal class Order
6{
7 public Order( int id )
8 {
9 this.Id = id;
10 }
11
12 public int Id { get; }
13}
14
Resolution
Make the pull strategy return an action that provides a value:
- UseExpression or PullAction.UseConstant passes an expression or a constant, as shown in the following example.
- IntroduceParameterAndPull adds a parameter to the calling constructors; its
forwarderExpressionargument sets the value passed by the forwarding constructor.
If you don't need a custom strategy, use one of the built-in strategies of the PullStrategy class, for example UseExpression.
1using System;
2using Metalama.Framework.Advising;
3using Metalama.Framework.Aspects;
4using Metalama.Framework.Code;
5using Metalama.Framework.Code.SyntaxBuilders;
6
7namespace Doc.LAMA0536.Fixed;
8
9public class TimestampPullStrategy : IPullStrategy
10{
11 // Fixed: the forwarding constructor passes the current time.
12 public PullAction GetPullAction( IParameter pulledParameter, IHasParameters targetMember )
13 => PullAction.UseExpression( ExpressionFactory.Parse( "global::System.DateTime.Now" ) );
14}
15
16public class AddTimestampAttribute : TypeAspect
17{
18 public override void BuildAspect( IAspectBuilder<INamedType> builder )
19 {
20 foreach ( var constructor in builder.Target.Constructors )
21 {
22 builder.With( constructor )
23 .IntroduceParameter(
24 "creationTime",
25 typeof(DateTime),
26 pullStrategy: new TimestampPullStrategy(),
27 overloadingStrategy: ConstructorOverloadingStrategy.ForwardSourceConstructors );
28 }
29 }
30}
31
1namespace Doc.LAMA0536.Fixed;
2
3// The [AddTimestamp] aspect adds a creationTime parameter and a forwarding constructor.
4[AddTimestamp]
5internal class Order
6{
7 public Order( int id )
8 {
9 this.Id = id;
10 }
11
12 public int Id { get; }
13}
14
1using System;
2
3namespace Doc.LAMA0536.Fixed;
4
5// The [AddTimestamp] aspect adds a creationTime parameter and a forwarding constructor.
6[AddTimestamp]
7internal class Order
8{
9 public Order(int id, DateTime creationTime)
10 {
11 this.Id = id;
12 }
13
14 public int Id { get; }
15
16 public Order(int id) : this(id: id, creationTime: DateTime.Now)
17 {
18 }
19}
20