Open sandboxFocusImprove this doc

LAMA1000: The interception scope must be inside the target of the aspect

Severity Error
Reported by Metalama.Extensions.Interceptors
Message The <Predecessor> cannot add an interceptor to '<Child>' because '<Child>' is not contained in '<Parent>'.

Cause

Metalama.Extensions.Interceptors lets an aspect or a fabric replace the calls to selected methods, in the source code of the current project, with calls to other methods. An aspect or fabric registers an interceptor with the InterceptMethods method of its adviser, builder, or amender. The declaration on which you call this method is the interception scope: only the calls located inside this declaration are intercepted.

An aspect or fabric can register interceptors only under its own target, so that it can't change the behavior of code that it doesn't own. The scope must be contained in the closest type of the aspect target. When the target is a namespace, the scope must be contained in that namespace. When the target is the compilation, any declaration of the current project is accepted, but not the declarations of referenced assemblies.

Metalama reports LAMA1000 when the scope isn't contained in the target. In the message, <Predecessor> describes the aspect or fabric, <Child> is the scope, and <Parent> is the declaration that should contain it.

In the following example, the RedirectLogging aspect is applied to Checkout, but it registers the interceptor on OrderService.

1using System.Linq;
2using Metalama.Extensions.Interceptors;
3using Metalama.Framework.Aspects;
4using Metalama.Framework.Code;
5
6namespace Doc.LAMA1000.Error;
7
8public class RedirectLoggingAttribute : TypeAspect
9{
10    public override void BuildAspect( IAspectBuilder<INamedType> builder )
11    {
12        // The aspect is applied to Checkout, but it registers the interceptor on OrderService.
13        builder.With( typeof(OrderService).AsINamedType() ).InterceptMethods(
14            b => b
15                .Type( typeof(LegacyLogger) )
16                .Methods( "Write" )
17                .RedirectToExistingMethod( typeof(Logger).AsINamedType().Methods.OfName( "Write" ).Single() ) );
18    }
19}
20
1using System;
2
3namespace Doc.LAMA1000.Error;
4
5public static class LegacyLogger
6{
7    public static void Write( string message ) => Console.WriteLine( message );
8}
9
10public static class Logger
11{
12    public static void Write( string message ) => Console.WriteLine( $"[{DateTime.Now:T}] {message}" );
13}
14
15[RedirectLogging]
Error LAMA1000: The aspect [RedirectLoggingAttribute] applied to 'Checkout' cannot add an interceptor to 'OrderService' because 'OrderService' is not contained in 'Checkout'.

16internal class Checkout
17{
18    public void Complete() => LegacyLogger.Write( "Checkout completed." );
19}
20
21internal class OrderService
22{
23    public void Place() => LegacyLogger.Write( "Order placed." );
24}
25

Resolution

Register the interceptor on the target of the aspect or on a declaration inside it, or apply the aspect to a declaration that contains the scope. To intercept calls in the whole project, use a project fabric. In the following example, the aspect is applied to OrderService and registers the interceptor on its target.

1using System.Linq;
2using Metalama.Extensions.Interceptors;
3using Metalama.Framework.Aspects;
4using Metalama.Framework.Code;
5
6namespace Doc.LAMA1000.Fixed;
7
8public class RedirectLoggingAttribute : TypeAspect
9{
10    public override void BuildAspect( IAspectBuilder<INamedType> builder )
11    {
12        // The interceptor is registered on the target of the aspect.
13        builder.InterceptMethods(
14            b => b
15                .Type( typeof(LegacyLogger) )
16                .Methods( "Write" )
17                .RedirectToExistingMethod( typeof(Logger).AsINamedType().Methods.OfName( "Write" ).Single() ) );
18    }
19}
20
Source Code
1using System;
2
3namespace Doc.LAMA1000.Fixed;
4
5public static class LegacyLogger
6{
7    public static void Write( string message ) => Console.WriteLine( message );
8}
9
10public static class Logger
11{
12    public static void Write( string message ) => Console.WriteLine( $"[{DateTime.Now:T}] {message}" );
13}
14
15internal class Checkout
16{
17    public void Complete() => LegacyLogger.Write( "Checkout completed." );
18}
19
20[RedirectLogging]
21internal class OrderService
22{
23    public void Place() => LegacyLogger.Write( "Order placed." );
24}
25
Transformed Code
1using System;
2
3namespace Doc.LAMA1000.Fixed;
4
5public static class LegacyLogger
6{
7    public static void Write(string message) => Console.WriteLine(message);
8}
9
10public static class Logger
11{
12    public static void Write(string message) => Console.WriteLine($"[{DateTime.Now:T}] {message}");
13}
14
15internal class Checkout
16{
17    public void Complete() => LegacyLogger.Write("Checkout completed.");
18}
19
20[RedirectLogging]
21internal class OrderService
22{
23    public void Place() => Logger.Write("Order placed.");
24}
25

See also