-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix intercepting a struct or enum base method #71655
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3423,6 +3423,36 @@ static class D | |
Diagnostic(ErrorCode.ERR_InterceptorSignatureMismatch, @"InterceptsLocation(""Program.cs"", 11, 9)").WithArguments("Program.InterceptableMethod(ref readonly int)", "D.Interceptor(in int)").WithLocation(17, 6)); | ||
} | ||
|
||
[Fact] | ||
public void SignatureMismatch_10() | ||
{ | ||
var source = """ | ||
using System.Runtime.CompilerServices; | ||
using System; | ||
|
||
struct Program | ||
{ | ||
public void InterceptableMethod() => Console.Write("Original"); | ||
|
||
public static void Main() | ||
{ | ||
new Program().InterceptableMethod(); | ||
} | ||
} | ||
|
||
static class D | ||
{ | ||
[InterceptsLocation("Program.cs", 10, 23)] | ||
public static void Interceptor(this in Program x) => Console.Write("Intercepted"); | ||
} | ||
"""; | ||
var comp = CreateCompilation(new[] { (source, "Program.cs"), s_attributesSource }, parseOptions: RegularWithInterceptors); | ||
comp.VerifyEmitDiagnostics( | ||
// Program.cs(16,6): error CS9148: Interceptor must have a 'this' parameter matching parameter 'ref Program this' on 'Program.InterceptableMethod()'. | ||
// [InterceptsLocation("Program.cs", 10, 23)] | ||
Diagnostic(ErrorCode.ERR_InterceptorMustHaveMatchingThisParameter, @"InterceptsLocation(""Program.cs"", 10, 23)").WithArguments("ref Program this", "Program.InterceptableMethod()").WithLocation(16, 6)); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
[Fact] | ||
public void ScopedMismatch_01() | ||
{ | ||
|
@@ -4827,4 +4857,201 @@ public static void Interceptor() { } | |
// [InterceptsLocation("Program.cs", 5, 3)] | ||
Diagnostic(ErrorCode.ERR_InterceptorCannotUseUnmanagedCallersOnly, @"InterceptsLocation(""Program.cs"", 5, 3)").WithLocation(14, 6)); | ||
} | ||
|
||
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/70841")] | ||
public void InterceptorEnumBaseMethod() | ||
{ | ||
var program = (""" | ||
using System; | ||
|
||
var value = MyEnum.Second; | ||
Console.WriteLine(value.ToString()); | ||
|
||
public enum MyEnum | ||
{ | ||
First, | ||
Second, | ||
} | ||
""", "Program.cs"); | ||
|
||
var interceptor = (""" | ||
using System.Runtime.CompilerServices; | ||
|
||
namespace MyInterceptors | ||
{ | ||
public static class Interceptors | ||
{ | ||
[InterceptsLocation(@"Program.cs", 4, 25)] | ||
public static string OtherToString(this System.Enum value) | ||
=> "Wrong Value" + value; | ||
} | ||
} | ||
""", "Interceptor.cs"); | ||
|
||
var verifier = CompileAndVerify(new[] { program, s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "Second"); | ||
verifier.VerifyDiagnostics(); | ||
verifier.VerifyIL("<top-level-statements-entry-point>", """ | ||
{ | ||
// Code size 21 (0x15) | ||
.maxstack 1 | ||
.locals init (MyEnum V_0) //value | ||
IL_0000: ldc.i4.1 | ||
IL_0001: stloc.0 | ||
IL_0002: ldloca.s V_0 | ||
IL_0004: constrained. "MyEnum" | ||
IL_000a: callvirt "string object.ToString()" | ||
IL_000f: call "void System.Console.WriteLine(string)" | ||
IL_0014: ret | ||
} | ||
"""); | ||
|
||
verifier = CompileAndVerify(new[] { program, interceptor, s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "Wrong ValueSecond"); | ||
verifier.VerifyDiagnostics(); | ||
verifier.VerifyIL("<top-level-statements-entry-point>", """ | ||
{ | ||
// Code size 17 (0x11) | ||
.maxstack 1 | ||
IL_0000: ldc.i4.1 | ||
IL_0001: box "MyEnum" | ||
IL_0006: call "string MyInterceptors.Interceptors.OtherToString(System.Enum)" | ||
IL_000b: call "void System.Console.WriteLine(string)" | ||
IL_0010: ret | ||
} | ||
"""); | ||
} | ||
|
||
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/70841")] | ||
public void InterceptorStructBaseMethod() | ||
{ | ||
var program = (""" | ||
using System; | ||
|
||
MyStruct value = default; | ||
Console.WriteLine(value.Equals((object)1)); | ||
|
||
public struct MyStruct { } | ||
""", "Program.cs"); | ||
|
||
var interceptor = (""" | ||
using System.Runtime.CompilerServices; | ||
|
||
namespace MyInterceptors | ||
{ | ||
public static class Interceptors | ||
{ | ||
[InterceptsLocation(@"Program.cs", 4, 25)] | ||
public static bool Equals(this System.ValueType value, object other) => true; | ||
} | ||
} | ||
""", "Interceptor.cs"); | ||
|
||
var verifier = CompileAndVerify(new[] { program, s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "False"); | ||
verifier.VerifyDiagnostics(); | ||
verifier.VerifyIL("<top-level-statements-entry-point>", """ | ||
{ | ||
// Code size 33 (0x21) | ||
.maxstack 2 | ||
.locals init (MyStruct V_0) //value | ||
IL_0000: ldloca.s V_0 | ||
IL_0002: initobj "MyStruct" | ||
IL_0008: ldloca.s V_0 | ||
IL_000a: ldc.i4.1 | ||
IL_000b: box "int" | ||
IL_0010: constrained. "MyStruct" | ||
IL_0016: callvirt "bool object.Equals(object)" | ||
IL_001b: call "void System.Console.WriteLine(bool)" | ||
IL_0020: ret | ||
} | ||
"""); | ||
|
||
verifier = CompileAndVerify(new[] { program, interceptor, s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "True"); | ||
verifier.VerifyDiagnostics(); | ||
verifier.VerifyIL("<top-level-statements-entry-point>", """ | ||
{ | ||
// Code size 31 (0x1f) | ||
.maxstack 2 | ||
.locals init (MyStruct V_0) | ||
IL_0000: ldloca.s V_0 | ||
IL_0002: initobj "MyStruct" | ||
IL_0008: ldloc.0 | ||
IL_0009: box "MyStruct" | ||
IL_000e: ldc.i4.1 | ||
IL_000f: box "int" | ||
IL_0014: call "bool MyInterceptors.Interceptors.Equals(System.ValueType, object)" | ||
IL_0019: call "void System.Console.WriteLine(bool)" | ||
IL_001e: ret | ||
} | ||
"""); | ||
} | ||
|
||
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/70841")] | ||
public void InterceptorStructConstrainedInterfaceMethod() | ||
{ | ||
var program = (""" | ||
using System; | ||
|
||
C.M(default(MyStruct)); | ||
|
||
class C | ||
{ | ||
public static void M<T>(T t) where T : struct, I | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or alternatively, perhaps remove all constraints and test a call to a virtual method on static void M<T>(T t)
{
t.ToString();
} |
||
{ | ||
t.IM(); | ||
} | ||
} | ||
|
||
public struct MyStruct : I | ||
{ | ||
public void IM() | ||
{ | ||
Console.Write("Original"); | ||
} | ||
} | ||
|
||
public interface I | ||
{ | ||
void IM(); | ||
} | ||
""", "Program.cs"); | ||
|
||
var interceptor = (""" | ||
using System.Runtime.CompilerServices; | ||
using System; | ||
|
||
namespace MyInterceptors | ||
{ | ||
public static class Interceptors | ||
{ | ||
[InterceptsLocation(@"Program.cs", 9, 11)] | ||
public static void IM(this I @this) { Console.Write("Interceptor"); } | ||
} | ||
} | ||
""", "Interceptor.cs"); | ||
|
||
var verifier = CompileAndVerify(new[] { program, s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "Original"); | ||
verifier.VerifyDiagnostics(); | ||
verifier.VerifyIL("C.M<T>(T)", """ | ||
{ | ||
// Code size 14 (0xe) | ||
.maxstack 1 | ||
IL_0000: ldarga.s V_0 | ||
IL_0002: constrained. "T" | ||
IL_0008: callvirt "void I.IM()" | ||
IL_000d: ret | ||
} | ||
"""); | ||
|
||
verifier = CompileAndVerify(new[] { program, interceptor, s_attributesSource }, parseOptions: RegularWithInterceptors, expectedOutput: "Interceptor"); | ||
verifier.VerifyDiagnostics(); | ||
verifier.VerifyIL("C.M<T>(T)", """ | ||
{ | ||
// Code size 12 (0xc) | ||
.maxstack 1 | ||
IL_0000: ldarg.0 | ||
IL_0001: box "T" | ||
IL_0006: call "void MyInterceptors.Interceptors.IM(I)" | ||
IL_000b: ret | ||
} | ||
"""); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can try to add a clarifying comment here in a follow-up PR.