Open sandboxFocusImprove this doc

LAMA0043: An aspect suggests a code fix

Severity Hidden
Reported by Metalama.Extensions.CodeFixes
Message Code fix

Cause

In Roslyn, a code fix must be attached to a diagnostic. When an aspect, a fabric, or a validator wants to offer a code fix without reporting any warning or error, it calls one of the Suggest extension methods of the Metalama.Extensions.CodeFixes package, for instance builder.Diagnostics.Suggest( codeFix, declaration ). Metalama then reports LAMA0043, defined by SuggestionDiagnostic, at the given location and attaches the code fix to it.

LAMA0043 has the Hidden severity: it doesn't appear in the error list and doesn't affect the build. Its only effect is that the IDE offers the code fix in the lightbulb or refactoring menu when the caret is on the declaration.

In the following example, the Log aspect suggests a code fix that excludes a method from logging. The snapshot shows the hidden diagnostics and the title of their code fixes.

1using Metalama.Extensions.CodeFixes;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5using System.Linq;
6
7namespace Doc.LAMA0043.Error;
8
9[AttributeUsage( AttributeTargets.Method )]
10public class NotLoggedAttribute : Attribute { }
11
12public class LogAttribute : TypeAspect
13{
14    public override void BuildAspect( IAspectBuilder<INamedType> builder )
15    {
16        base.BuildAspect( builder );
17
18        foreach ( var method in builder.Target.Methods )
19        {
20            if ( method.Attributes.Any( a => a.Type.IsConvertibleTo( typeof(NotLoggedAttribute) ) ) )
21            {
22                continue;
23            }
24
25            builder.With( method ).Override( nameof(this.LogMethod) );
26
27            // Suggest a code fix without reporting a visible diagnostic.
28            builder.Diagnostics.Suggest(
29                CodeFixFactory.AddAttribute( method, typeof(NotLoggedAttribute), "Exclude from logging" ),
30                method );
31        }
32    }
33
34    [Template]
35    public dynamic? LogMethod()
36    {
37        Console.WriteLine( $"Executing {meta.Target.Method}." );
38
39        return meta.Proceed();
40    }
41}
42
Source Code
1namespace Doc.LAMA0043.Error;
2
3// The [Log] aspect suggests a code fix for each method, carried by LAMA0043.


4[Log]
5internal class AccountService
6{
7    private decimal _balance = 100;
8
9    public void Withdraw( decimal amount ) => this._balance -= amount;
10
11    public decimal GetBalance() => this._balance;
12}




13
Transformed Code
1using System;
2
3namespace Doc.LAMA0043.Error;
4
5// The [Log] aspect suggests a code fix for each method, carried by LAMA0043.
6[Log]
7internal class AccountService
8{
9    private decimal _balance = 100;
10
11    public void Withdraw(decimal amount)
12    {
13        Console.WriteLine("Executing AccountService.Withdraw(decimal).");
14        this._balance -= amount;
15    }
16
17    public decimal GetBalance()
18    {
19        Console.WriteLine("Executing AccountService.GetBalance().");
20        return this._balance;
21    }
22}
23

Resolution

LAMA0043 doesn't indicate a problem, so no resolution is needed. You can apply the suggested code fix from the IDE or ignore it.

The following example shows the code after you apply the code fix suggested for GetBalance. The method now has the [NotLogged] attribute, so the aspect no longer logs it and no longer suggests the code fix there.

1using Metalama.Extensions.CodeFixes;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using System;
5using System.Linq;
6
7namespace Doc.LAMA0043.Fixed;
8
9[AttributeUsage( AttributeTargets.Method )]
10public class NotLoggedAttribute : Attribute { }
11
12public class LogAttribute : TypeAspect
13{
14    public override void BuildAspect( IAspectBuilder<INamedType> builder )
15    {
16        base.BuildAspect( builder );
17
18        foreach ( var method in builder.Target.Methods )
19        {
20            if ( method.Attributes.Any( a => a.Type.IsConvertibleTo( typeof(NotLoggedAttribute) ) ) )
21            {
22                continue;
23            }
24
25            builder.With( method ).Override( nameof(this.LogMethod) );
26
27            // Suggest a code fix without reporting a visible diagnostic.
28            builder.Diagnostics.Suggest(
29                CodeFixFactory.AddAttribute( method, typeof(NotLoggedAttribute), "Exclude from logging" ),
30                method );
31        }
32    }
33
34    [Template]
35    public dynamic? LogMethod()
36    {
37        Console.WriteLine( $"Executing {meta.Target.Method}." );
38
39        return meta.Proceed();
40    }
41}
42
Source Code
1namespace Doc.LAMA0043.Fixed;
2


3[Log]
4internal class AccountService
5{
6    private decimal _balance = 100;
7
8    public void Withdraw( decimal amount ) => this._balance -= amount;
9
10    // The code fix added [NotLogged], so the aspect no longer logs this method or suggests the fix here.




11    [NotLogged]
12    public decimal GetBalance() => this._balance;
13}
14
Transformed Code
1using System;
2
3namespace Doc.LAMA0043.Fixed;
4
5[Log]
6internal class AccountService
7{
8    private decimal _balance = 100;
9
10    public void Withdraw(decimal amount)
11    {
12        Console.WriteLine("Executing AccountService.Withdraw(decimal).");
13        this._balance -= amount;
14    }
15
16    // The code fix added [NotLogged], so the aspect no longer logs this method or suggests the fix here.
17    [NotLogged]
18    public decimal GetBalance() => this._balance;
19}
20

See also