Open sandboxFocusImprove this doc

LAMA1010: A call can't have more than one interceptor

Severity Error
Reported by Metalama.Extensions.Interceptors
Message The <Site> is intercepted by more than one interceptor: <Sources>. At most one interceptor can apply to a call site.

Cause

Metalama.Extensions.Interceptors lets aspects and fabrics replace the calls to selected methods with calls to other methods. A call can be replaced only once, so at most one interceptor can apply to a given call.

Metalama evaluates every registration whose scope and selection contain the call. A registration can decline the call, for instance with Skip in a ForEachSite delegate. Metalama reports LAMA1010 when more than one registration returns an interceptor instead of declining. It doesn't matter whether the registrations come from different aspects, from an aspect and a fabric, from several instances of the same aspect, or from the same fabric. In that case, Metalama doesn't intercept the call.

In the message, <Site> describes the call, and <Sources> lists the aspects and fabrics whose registrations returned an interceptor.

In the following example, a fabric registers two interceptors for the calls to Printer.Print.

1using Metalama.Extensions.Interceptors;
2using Metalama.Framework.Code;
3using Metalama.Framework.Fabrics;
4using System;
5using System.Linq;
6
7namespace Doc.LAMA1010.Error;
8
9internal class Fabric : ProjectFabric
10{
11    public override void AmendProject( IProjectAmender amender )
12    {
13        amender.InterceptMethods(
14            b => b
15                .Type( typeof(Printer) )
16                .Methods( "Print" )
17                .RedirectToExistingMethod( typeof(Interceptors).AsINamedType().Methods.OfName( "Log" ).Single() ) );
18
19        // Error: this second registration returns an interceptor for the same call.
20        amender.InterceptMethods(
21            b => b
22                .Type( typeof(Printer) )
23                .Methods( "Print" )
24                .RedirectToExistingMethod( typeof(Interceptors).AsINamedType().Methods.OfName( "Trace" ).Single() ) );
25    }
26}
27
28internal static class Interceptors
29{
30    public static void Log( string value ) => Console.WriteLine( "log: " + value );
31
32    public static void Trace( string value ) => Console.WriteLine( "trace: " + value );
33}
34
1using System;
2
3namespace Doc.LAMA1010.Error;
4
5internal static class Printer
6{
7    public static void Print( string value ) => Console.WriteLine( value );
8}
9
10internal static class Program
11{
    Error LAMA1010: The call to 'Printer.Print(string)' is intercepted by more than one interceptor: the interceptor method 'Interceptors.Log(string)' registered by the fabric Doc.LAMA1010.Error.Fabric, the interceptor method 'Interceptors.Trace(string)' registered by the fabric Doc.LAMA1010.Error.Fabric. At most one interceptor can apply to a call site.

12    public static void Run() => Printer.Print( "Hello" );
13}
14

Resolution

Make sure that a single registration intercepts each call:

  • Remove one of the registrations, or merge them into one interceptor. The following example keeps a single registration.
  • Narrow the scope of the registrations, so that they no longer overlap.
  • In a ForEachSite delegate, return Skip for the calls that another registration must handle.

1using Metalama.Extensions.Interceptors;
2using Metalama.Framework.Code;
3using Metalama.Framework.Fabrics;
4using System;
5using System.Linq;
6
7namespace Doc.LAMA1010.Fixed;
8
9internal class Fabric : ProjectFabric
10{
11    public override void AmendProject( IProjectAmender amender )
12    {
13        // A single registration returns an interceptor for the call.
14        amender.InterceptMethods(
15            b => b
16                .Type( typeof(Printer) )
17                .Methods( "Print" )
18                .RedirectToExistingMethod( typeof(Interceptors).AsINamedType().Methods.OfName( "Log" ).Single() ) );
19    }
20}
21
22internal static class Interceptors
23{
24    public static void Log( string value ) => Console.WriteLine( "log: " + value );
25
26    public static void Trace( string value ) => Console.WriteLine( "trace: " + value );
27}
28
Source Code
1using System;
2
3namespace Doc.LAMA1010.Fixed;
4
5internal static class Printer
6{
7    public static void Print( string value ) => Console.WriteLine( value );
8}
9
10internal static class Program
11{
12    public static void Run() => Printer.Print( "Hello" );
13}
14
Transformed Code
1using System;
2
3namespace Doc.LAMA1010.Fixed;
4
5internal static class Printer
6{
7    public static void Print(string value) => Console.WriteLine(value);
8}
9
10internal static class Program
11{
12    public static void Run() => Interceptors.Log("Hello");
13}
14

See also