Skip to content
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

Merged
merged 6 commits into from
Apr 16, 2024

Conversation

RikkiGibson
Copy link
Contributor

@RikkiGibson RikkiGibson commented Apr 12, 2024

Fixes #72478

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Apr 12, 2024
@RikkiGibson RikkiGibson changed the title Interceptors cond access Support intercepting invocation within conditional access Apr 12, 2024
@@ -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()
Copy link
Contributor Author

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.

Copy link
Contributor Author

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)

@RikkiGibson RikkiGibson marked this pull request as ready for review April 15, 2024 20:56
@RikkiGibson RikkiGibson requested a review from a team as a code owner April 15, 2024 20:56
@RikkiGibson
Copy link
Contributor Author

@cston @jcouv for review of a small fix

@@ -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:
Copy link
Member

@cston cston Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case

Is this case redundant given the { Parent: SimpleNameSyntax { Parent: MemberBindingExpressionSyntax memberBinding } rhs1 } when memberBinding.Name == rhs1 case below? #Resolved

Copy link
Contributor Author

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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case { Parent: SimpleNameSyntax { Parent: MemberAccessExpressionSyntax

Is this case redundant given the { Parent: SimpleNameSyntax { Parent: MemberAccessExpressionSyntax memberAccess } rhs } when memberAccess.Name == rhs case below?

Copy link
Contributor Author

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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expectedOutput: "1"

Consider testing intercepting with c == null as well.

static void Main()
{
    F(new C());
    F(null);
}

static void F(C c)
{
    c?.M();
}

static void Main()
{
var c = new C();
c?.M();
Copy link
Member

@jcouv jcouv Apr 15, 2024

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);
Copy link
Member

@jcouv jcouv Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C?

Do we need the ? annotation on C here? That gives M1 a different signature than M.
nit: consider also verifying that M receives the proper values and is not invoked in the null case. #Closed

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")]
Copy link
Member

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?

Copy link
Contributor Author

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.)

Copy link
Member

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

Copy link
Member

@jcouv jcouv left a 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)

@jcouv jcouv self-assigned this Apr 15, 2024
@RikkiGibson RikkiGibson requested a review from jcouv April 15, 2024 23:34
verify: Verification.Fails,
expectedOutput: "1");
verifier.VerifyDiagnostics();
}
Copy link
Member

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

Copy link
Member

@jcouv jcouv left a 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

@RikkiGibson RikkiGibson enabled auto-merge (squash) April 16, 2024 19:35
@RikkiGibson RikkiGibson merged commit e8bb458 into dotnet:main Apr 16, 2024
24 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Apr 16, 2024
@RikkiGibson RikkiGibson deleted the interceptors-cond-access branch April 16, 2024 21:42
@dibarbet dibarbet modified the milestones: Next, 17.11 P1 Apr 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot intercept conditional access or pointer member access invocations
4 participants