| Severity | Warning |
| Reported by | Metalama.Framework |
| Message | The <VariableKind> '<Name>' is renamed to '<NewName>' in the compiled code, because it hides the parameter '<Name>' of '<Member>', and this parameter is passed by <Description>. The compiled code no longer matches the source code, so the debugger shows the new name. Rename the <VariableKind> in the source code to remove this warning. |
Cause
The Metalama.Extensions.Interceptors package lets an aspect or fabric redirect calls to a method, and pass a parameter of the calling method to the new target, for instance with site.Caller.Parameters[0]. The redirected call then contains the name of that parameter.
When the call is inside a lambda expression or a local function that declares a lambda parameter, a local variable or a parameter with the same name, this variable hides the parameter of the calling method, and the name would designate the wrong variable. The linker therefore renames the hiding variable and its references in the compiled code, and reports LAMA0661 on its declaration. The compiled code no longer matches the source code, so the debugger shows the new name.
In the message, <VariableKind> is the kind of the renamed variable, such as lambda parameter, local variable or local function parameter, <Name> and <NewName> are its old and new names, <Member> is the calling method, and <Description> describes the redirected call.
In the following example, the UseModernLogger aspect redirects the calls to LegacyLogger.Write and passes the first parameter of the calling method. The lambda parameter id hides the parameter id of the Process method.
1using System.Linq;
2using Metalama.Extensions.Interceptors;
3using Metalama.Framework.Aspects;
4using Metalama.Framework.Code;
5
6namespace Doc.LAMA0661.Error;
7
8public class UseModernLoggerAttribute : TypeAspect
9{
10 public override void BuildAspect( IAspectBuilder<INamedType> builder )
11 {
12 // Redirect the calls of LegacyLogger.Write to Logger.Write, and pass the first parameter of the calling method.
13 builder.InterceptMethods(
14 b => b
15 .Type( typeof(LegacyLogger) )
16 .Methods( "Write" )
17 .ForEachSite(
18 site => site
19 .RedirectToExistingMethod( typeof(Logger).AsINamedType().Methods.OfName( "Write" ).Single() )
20 .WithArgs( new { requestId = site.Caller.Parameters[0] } ) ) );
21 }
22}
23
1using System;
2
3namespace Doc.LAMA0661.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, int requestId ) => Console.WriteLine( $"{message} (request {requestId})" );
13}
14
15[UseModernLogger]
16public class OrderProcessor
17{
18 public void Process( int id, int[] items )
19 {
20 LegacyLogger.Write( "Processing started." );
21
22 // The lambda parameter hides the parameter of the method.
Warning LAMA0661: The lambda parameter 'id' is renamed to 'id_1' in the compiled code, because it hides the parameter 'id' of 'OrderProcessor.Process(int, int[])', and this parameter is passed by the call 'LegacyLogger.Write( $"Item {id}." )' redirected to 'Logger.Write(string, int)' by aspect [UseModernLoggerAttribute] applied to 'OrderProcessor'. The compiled code no longer matches the source code, so the debugger shows the new name. Rename the lambda parameter in the source code to remove this warning.
23 Array.ForEach( items, id => LegacyLogger.Write( $"Item {id}." ) );
24 }
25}
26
1using System;
2
3namespace Doc.LAMA0661.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, int requestId) => Console.WriteLine($"{message} (request {requestId})");
13}
14
15[UseModernLogger]
16public class OrderProcessor
17{
18 public void Process(int id, int[] items)
19 {
20 Logger.Write(message: "Processing started.", requestId: id);
21
22 // The lambda parameter hides the parameter of the method.
23 Array.ForEach(items, id_1 => Logger.Write(message: $"Item {id_1}.", requestId: id));
24 }
25}
26
Resolution
Rename the variable in the source code so that it doesn't hide the parameter of the calling method. In the following example, the lambda parameter is named item.
1using System.Linq;
2using Metalama.Extensions.Interceptors;
3using Metalama.Framework.Aspects;
4using Metalama.Framework.Code;
5
6namespace Doc.LAMA0661.Fixed;
7
8public class UseModernLoggerAttribute : TypeAspect
9{
10 public override void BuildAspect( IAspectBuilder<INamedType> builder )
11 {
12 // Redirect the calls of LegacyLogger.Write to Logger.Write, and pass the first parameter of the calling method.
13 builder.InterceptMethods(
14 b => b
15 .Type( typeof(LegacyLogger) )
16 .Methods( "Write" )
17 .ForEachSite(
18 site => site
19 .RedirectToExistingMethod( typeof(Logger).AsINamedType().Methods.OfName( "Write" ).Single() )
20 .WithArgs( new { requestId = site.Caller.Parameters[0] } ) ) );
21 }
22}
23
1using System;
2
3namespace Doc.LAMA0661.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, int requestId ) => Console.WriteLine( $"{message} (request {requestId})" );
13}
14
15[UseModernLogger]
16public class OrderProcessor
17{
18 public void Process( int id, int[] items )
19 {
20 LegacyLogger.Write( "Processing started." );
21
22 // The lambda parameter has another name.
23 Array.ForEach( items, item => LegacyLogger.Write( $"Item {item}." ) );
24 }
25}
26
1using System;
2
3namespace Doc.LAMA0661.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, int requestId) => Console.WriteLine($"{message} (request {requestId})");
13}
14
15[UseModernLogger]
16public class OrderProcessor
17{
18 public void Process(int id, int[] items)
19 {
20 Logger.Write(message: "Processing started.", requestId: id);
21
22 // The lambda parameter has another name.
23 Array.ForEach(items, item => Logger.Write(message: $"Item {item}.", requestId: id));
24 }
25}
26