Open sandboxFocusImprove this doc

LAMA0065: The options can't be set on the declaration

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 Where method, 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
Source Code
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
Transformed Code
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

See also