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

[AK1005] Must close sender in async lambda expression argument #87

Merged

Conversation

Arkatufus
Copy link
Contributor

Fixes #71

Changes

  • Add analyzer
  • Add unit tests

…-in-ReceiveAsync

# Conflicts:
#	src/Akka.Analyzers/Context/Core/Actor/BaseActorContext.cs
#	src/Akka.Analyzers/Utility/RuleDescriptors.cs
Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

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

One very minor change suggested, a couple of questions

id: "AK1005",
title: "Must close over `Sender` or `Self`",
category: AnalysisCategory.ActorDesign,
defaultSeverity: DiagnosticSeverity.Error,
Copy link
Member

Choose a reason for hiding this comment

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

I'd reduce this to a warning for now, in case this rule doesn't work as expected in the wild. We can always raise the severity later.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, I'll fix it now.

ReceiveAsync<string>(async str => {
var sender = Sender;
await api.AsyncLambda(async () => {
sender.Tell(new Message(str));
Copy link
Member

Choose a reason for hiding this comment

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

Just so I'm clear, it's the async lambda running inside this local function that makes accessing Context.Sender an issue, not the await-ing inside the ReceiveAsync itself, right?

Copy link
Member

Choose a reason for hiding this comment

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

And I know this is a passing case with a closure et al, but I just wanted to be clear since I'm working from the top down of the diff.

ReceiveAsync<string>(async str =>
{
await api.AsyncLambda(async () => {
Context.Sender.Tell(new Message(str));
Copy link
Member

Choose a reason for hiding this comment

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

Got it, yep I can see why this would be a problem.

Copy link
Member

Choose a reason for hiding this comment

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

Analyzer test cases look good and make sense.

var akkaActor = akkaContext.AkkaCore.Actor;

// The class declaration must implements or inherits `Akka.Actor.ActorBase`
if (!classDeclaration.IsDerivedOrImplements(semanticModel, akkaActor.ActorBaseType!))
Copy link
Member

Choose a reason for hiding this comment

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

LGTM

}
}

private sealed class BlockVisitor: CSharpSyntaxVisitor<List<Diagnostic>>
Copy link
Member

Choose a reason for hiding this comment

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

What is this visitor for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There are 2 visitors:

  • one is for collecting all lambda expression that are being passed in as an argument to a method invocation,
  • the other is a visitor that enumerates the body of said lambda to look for the use of Sender, Self, Context.Sender, and Context.Self.

The two needs to be separated because they need to be executed in step

public INamedTypeSymbol? TaskType { get; }
}

public sealed class SystemThreadingTasksContext: ISystemThreadingTasksContext
Copy link
Member

Choose a reason for hiding this comment

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

LGTM

return false;

// Property is equal to `ActorBase.Sender` or `IActorContext.Sender`
return ReferenceEquals(akkaContext.Actor.ActorBase.Sender, propertySymbol) ||
Copy link
Member

Choose a reason for hiding this comment

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

LGTM

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

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

LGTM

@Aaronontheweb Aaronontheweb merged commit ddf6d12 into akkadotnet:dev Apr 1, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AK1000 Must close over Sender and Self when accessed inside a lambda argument body
2 participants