| Severity | Error |
| Reported by | Metalama.Framework |
| Message | The option '<OptionName>' cannot be applied to the <DeclarationKind> '<Target>' because <Reason>. |
Cause
Aspects can expose configuration through hierarchical options, which are classes implementing IHierarchicalOptions<T>. Like an aspect, an options class can also implement IEligible<T> and define eligibility conditions in its BuildEligibility method. These conditions describe the declarations on which the options can be set.
Metalama reports LAMA0065 when you set options on a declaration, typically with the SetOptions method in a fabric, but the declaration doesn't satisfy one of these conditions. In the message, <OptionName> is the name of the options class, <DeclarationKind> and <Target> are the kind and the name of the declaration, and <Reason> explains which condition failed.
In the following example, LoggingOptions can only be set on non-static types, but the fabric sets the options on all types of the project, including the static class MathHelper.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0065.Error;
6
7public class LogAttribute : OverrideMethodAspect
8{
9 public override dynamic? OverrideMethod()
10 {
11 var options = meta.Target.Method.DeclaringType.Enhancements().GetOptions<LoggingOptions>();
12
13 Console.WriteLine( $"{options.Category}: Executing {meta.Target.Method}." );
14
15 return meta.Proceed();
16 }
17}
18
1using Metalama.Framework.Fabrics;
2using Metalama.Framework.Options;
3
4namespace Doc.LAMA0065.Error;
5
6public class Fabric : ProjectFabric
7{
8 public override void AmendProject( IProjectAmender amender )
9 {
10 // Error: the options are also set on static types, which are not eligible.
11 amender
12 .SelectMany( c => c.Types )
13 .SetOptions( new LoggingOptions { Category = "Calculation" } );
14 }
15}
16
1using Metalama.Framework.Code;
2using Metalama.Framework.Eligibility;
3using Metalama.Framework.Options;
4
5namespace Doc.LAMA0065.Error;
6
7// Options for the [Log] aspect.
8public class LoggingOptions : IHierarchicalOptions<INamedType>, IEligible<INamedType>
9{
10 public string? Category { get; init; }
11
12 object IIncrementalObject.ApplyChanges( object changes, in ApplyChangesContext context )
13 {
14 var other = (LoggingOptions) changes;
15
16 return new LoggingOptions { Category = other.Category ?? this.Category };
17 }
18
19 public void BuildEligibility( IEligibilityBuilder<INamedType> builder )
20 {
21 // The options can only be set on non-static types.
22 builder.MustNotBeStatic();
23 }
24}
25
1namespace Doc.LAMA0065.Error;
2
3internal class Calculator
4{
5 [Log]
6 public int Add( int a, int b ) => MathHelper.Sum( a, b );
7}
8
9// This static class doesn't satisfy the eligibility conditions of LoggingOptions.
Error LAMA0065: The option 'LoggingOptions' cannot be applied to the type 'MathHelper' because 'MathHelper' must not be static.
10internal static class MathHelper
11{
12 public static int Sum( int a, int b ) => a + b;
13}
14
Resolution
Depending on your intent, do one of the following:
- Filter the declarations on which you set the options, for instance with the
Wheremethod, so that only eligible declarations are selected. The following example skips static types. - Change the declaration so that it satisfies the condition given in the message.
- If you're the author of the options class and the condition is too strict, relax the condition in its BuildEligibility method.
1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0065.Fixed;
6
7public class LogAttribute : OverrideMethodAspect
8{
9 public override dynamic? OverrideMethod()
10 {
11 var options = meta.Target.Method.DeclaringType.Enhancements().GetOptions<LoggingOptions>();
12
13 Console.WriteLine( $"{options.Category}: Executing {meta.Target.Method}." );
14
15 return meta.Proceed();
16 }
17}
18
1using Metalama.Framework.Fabrics;
2using Metalama.Framework.Options;
3using System.Linq;
4
5namespace Doc.LAMA0065.Fixed;
6
7public class Fabric : ProjectFabric
8{
9 public override void AmendProject( IProjectAmender amender )
10 {
11 // Fixed: the options are set only on non-static types.
12 amender
13 .SelectMany( c => c.Types.Where( t => !t.IsStatic ) )
14 .SetOptions( new LoggingOptions { Category = "Calculation" } );
15 }
16}
17
1using Metalama.Framework.Code;
2using Metalama.Framework.Eligibility;
3using Metalama.Framework.Options;
4
5namespace Doc.LAMA0065.Fixed;
6
7// Options for the [Log] aspect.
8public class LoggingOptions : IHierarchicalOptions<INamedType>, IEligible<INamedType>
9{
10 public string? Category { get; init; }
11
12 object IIncrementalObject.ApplyChanges( object changes, in ApplyChangesContext context )
13 {
14 var other = (LoggingOptions) changes;
15
16 return new LoggingOptions { Category = other.Category ?? this.Category };
17 }
18
19 public void BuildEligibility( IEligibilityBuilder<INamedType> builder )
20 {
21 // The options can only be set on non-static types.
22 builder.MustNotBeStatic();
23 }
24}
25
1namespace Doc.LAMA0065.Fixed;
2
3internal class Calculator
4{
5 [Log]
6 public int Add( int a, int b ) => MathHelper.Sum( a, b );
7}
8
9// This static class doesn't satisfy the eligibility conditions of LoggingOptions.
10internal static class MathHelper
11{
12 public static int Sum( int a, int b ) => a + b;
13}
14
1using System;
2
3namespace Doc.LAMA0065.Fixed;
4
5internal class Calculator
6{
7 [Log]
8 public int Add(int a, int b)
9 {
10 Console.WriteLine("Calculation: Executing Calculator.Add(int, int).");
11 return MathHelper.Sum(a, b);
12 }
13}
14
15// This static class doesn't satisfy the eligibility conditions of LoggingOptions.
16internal static class MathHelper
17{
18 public static int Sum(int a, int b) => a + b;
19}
20