-
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
Support intercepting invocation within conditional access #72998
Support intercepting invocation within conditional access #72998
Conversation
9e7a1e9
to
d77473e
Compare
@@ -7199,4 +7199,173 @@ static void Main() | |||
Assert.Equal("(7,9)", locationSpecifier.GetDisplayLocation()); | |||
AssertEx.Equal("""[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "jB4qgCy292LkEGCwmD+R6FIAAAA=")]""", locationSpecifier.GetInterceptsLocationAttributeSyntax()); | |||
} | |||
|
|||
[Fact] | |||
public void ConditionalAccess_01() |
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.
Should probably also test cond-access on a nullable value type.
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.
Have to punt out the extension method scenario for this. It's another "receiver is not a variable" case (where calling the method directly in source would be an error). #71657 (comment)
@@ -1039,11 +1039,13 @@ private void DecodeInterceptsLocationChecksumBased(DecodeWellKnownAttributeArgum | |||
switch (referencedToken) | |||
{ | |||
case { Parent: SimpleNameSyntax { Parent: MemberAccessExpressionSyntax { Parent: InvocationExpressionSyntax } memberAccess } rhs } when memberAccess.Name == rhs: | |||
case { Parent: SimpleNameSyntax { Parent: MemberBindingExpressionSyntax { Parent: InvocationExpressionSyntax } memberBinding } rhs1 } when memberBinding.Name == rhs1: |
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.
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.
No, the case below is for an error reporting path (the MemberBinding's parent is not an Invocation).
@@ -1039,11 +1039,13 @@ private void DecodeInterceptsLocationChecksumBased(DecodeWellKnownAttributeArgum | |||
switch (referencedToken) | |||
{ | |||
case { Parent: SimpleNameSyntax { Parent: MemberAccessExpressionSyntax { Parent: InvocationExpressionSyntax } memberAccess } rhs } when memberAccess.Name == rhs: |
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.
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.
No, the case below is for an error reporting path (the MemberAccess's parent is not an Invocation).
} | ||
""", "Interceptors.cs", RegularWithInterceptors); | ||
|
||
var verifier = CompileAndVerify([source, interceptors, s_attributesTree], expectedOutput: "1"); |
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.
static void Main() | ||
{ | ||
var c = new C(); | ||
c?.M(); |
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.
It would be good for tests on new interceptable locations to also verify the GetInterceptorMethod
API #Closed
static class Interceptors | ||
{ | ||
{{locationSpecifier.GetInterceptsLocationAttributeSyntax()}} | ||
public static void M1(this C? c) => Console.Write(1); |
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.
comp = CreateCompilation([source, interceptors, s_attributesTree]); | ||
comp.VerifyEmitDiagnostics( | ||
// Interceptors.cs(6,6): error CS9151: Possible method name 'P' cannot be intercepted because it is not being invoked. | ||
// [global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "q2jDXUSFcU71GJHh7313cHEAAABQcm9ncmFtLmNz")] |
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.
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "q2jDXUSFcU71GJHh7313cHEAAABQcm9ncmFtLmNz")]
Not related to this PR: Have we considered making GetInterceptsLocationAttributeSyntax
output a comment with a human-readable location as you suggested source generators should do when writing an [InterceptsLocation(...)]
attribute?
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.
It's possible, but for output which is most appropriate over multiple lines, it seems better to avoid having to handle indentation and so on. (even if generator author doesn't care about unnecessary name qualifiers, they probably care about reasonable indentation and whitespace.)
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.
To avoid indentation problems, the comment could be at the end of the line: [global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "abc")] // file.cs(1, 2)
or even using /* file.cs(1, 2) */
comment
src/Compilers/CSharp/Test/Semantic/Semantics/InterceptorsTests.cs
Outdated
Show resolved
Hide resolved
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.
Done with review pass (iteration 3)
verify: Verification.Fails, | ||
expectedOutput: "1"); | ||
verifier.VerifyDiagnostics(); | ||
} |
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.
Consider checking GetInterceptorMethod
on pointer accesses too
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.
LGTM Thanks (iteration 5) with a small test suggestion to consider
Fixes #72478