Open sandboxFocusImprove this doc

LAMA0069: A diagnostic can be reported or suppressed only inside the type or namespace of the aspect or fabric

Severity Error
Reported by Metalama.Framework
Message The <AspectOrFabric> cannot report or suppress a diagnostic on '<Declaration>' because it is not contained in '<Container>'.

Cause

Aspects and fabrics can report or suppress diagnostics on several declarations at once by calling the ReportDiagnostic or SuppressDiagnostic extension methods on a query, for instance one built with SelectMany. However, the scope of these declarations is limited:

  • An aspect or a type fabric can report or suppress diagnostics only on its target type and on the declarations contained in this type, such as its members and nested types. For an aspect applied to a member, the scope is the declaring type of the member.
  • A namespace fabric can report or suppress diagnostics only on declarations contained in its namespace.
  • A project fabric can report or suppress diagnostics on any declaration of the current project.

Except for project fabrics, the declaration must also belong to the current project, not to a referenced assembly.

Metalama reports LAMA0069 when the query selects a declaration outside of this scope. In the message, <AspectOrFabric> describes the aspect or fabric, <Declaration> is the selected declaration, and <Container> is the type or namespace in which the declaration should be contained.

In the following example, a type fabric of OrderService tries to report a warning on the methods of the base class, ServiceBase.

1using Metalama.Framework.Code;
2using Metalama.Framework.Diagnostics;
3using Metalama.Framework.Fabrics;
4
5namespace Doc.LAMA0069.Error;
6
7internal class ServiceBase
8{
9    public void Ping() { }
10}
11
12internal class OrderService : ServiceBase
13{
14    public void PlaceOrder( int productId ) { }
15
    Error LAMA0069: The type fabric on 'Doc.LAMA0069.Error.OrderService' cannot report or suppress a diagnostic on 'ServiceBase.Ping()' because it is not contained in 'OrderService'.

16    private class Fabric : TypeFabric
17    {
18        private static readonly DiagnosticDefinition<IMethod> _legacyMethod = new(
19            "DOC001",
20            Severity.Warning,
21            "The method '{0}' is a legacy method and should not be used in new code." );
22
23        public override void AmendType( ITypeAmender amender )
24        {
25            // Error: a type fabric can't report diagnostics on the members of the base class.
26            amender.SelectMany( t => t.BaseType!.Methods ).ReportDiagnostic( m => _legacyMethod.WithArguments( m ) );
27        }
28    }
29}
30

Resolution

Report or suppress the diagnostic from a place whose scope contains the target declaration:

  • Move the type fabric to the type that declares the target declarations, as in the following example.
  • Use a project fabric, which can report diagnostics on any declaration of the project.
  • To report diagnostics on the classes derived from a type, use an inherited aspect instead of selecting the derived types.

Source Code
1using Metalama.Framework.Code;
2using Metalama.Framework.Diagnostics;
3using Metalama.Framework.Fabrics;
4
5namespace Doc.LAMA0069.Fixed;
6
7internal class ServiceBase
8{



9    public void Ping() { }
10
11    private class Fabric : TypeFabric



12    {
13        private static readonly DiagnosticDefinition<IMethod> _legacyMethod = new(
14            "DOC001",
15            Severity.Info,
16            "The method '{0}' is a legacy method and should not be used in new code." );
17
18        public override void AmendType( ITypeAmender amender )
19        {
20            // Fixed: the fabric is moved to the type that declares the methods.
21            amender.SelectMany( t => t.Methods ).ReportDiagnostic( m => _legacyMethod.WithArguments( m ) );
22        }
23    }
24}




25
26internal class OrderService : ServiceBase


27{

28    public void PlaceOrder( int productId ) { }
29}
30
Transformed Code
1using Metalama.Framework.Code;
2using Metalama.Framework.Diagnostics;
3using Metalama.Framework.Fabrics;
4
5namespace Doc.LAMA0069.Fixed;
6
7
8#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
9
10internal class ServiceBase
11{
12    public void Ping() { }
13
14
15#pragma warning disable CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
16
17    private class Fabric : TypeFabric
18    {
19        private static readonly DiagnosticDefinition<IMethod> _legacyMethod = new(
20            "DOC001",
21            Severity.Info,
22            "The method '{0}' is a legacy method and should not be used in new code.");
23
24        public override void AmendType(ITypeAmender amender) => throw new System.NotSupportedException("Compile-time-only code cannot be called at run-time.");
25    }
26



27#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
28
29
30}
31
32#pragma warning restore CS0067, CS8618, CS0162, CS0169, CS0414, CA1822, CA1823, IDE0051, IDE0052
33
34
35
36internal class OrderService : ServiceBase
37{
38    public void PlaceOrder(int productId) { }
39}
40

See also