-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add analyzer for invalid use of ITimerScheduler inside PreRestart and…
… AroundPreRestart (#85)
- Loading branch information
Showing
9 changed files
with
751 additions
and
1 deletion.
There are no files selected for viewing
529 changes: 529 additions & 0 deletions
529
src/Akka.Analyzers.Tests/Analyzers/AK1000/MustNotUseIWithTimersInPreRestartAnalyzerSpecs.cs
Large diffs are not rendered by default.
Oops, something went wrong.
61 changes: 61 additions & 0 deletions
61
src/Akka.Analyzers/AK1000/MustNotUseIWithTimersInPreRestartAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// ----------------------------------------------------------------------- | ||
// <copyright file="MustNotUseIWithTimersInPreRestartAnalyzer.cs" company="Akka.NET Project"> | ||
// Copyright (C) 2013-2024 .NET Foundation <https://github.com/akkadotnet/akka.net> | ||
// </copyright> | ||
// ----------------------------------------------------------------------- | ||
|
||
using System.Collections.Immutable; | ||
using Akka.Analyzers.Context; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
namespace Akka.Analyzers; | ||
|
||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public class MustNotUseIWithTimersInPreRestartAnalyzer(): AkkaDiagnosticAnalyzer(RuleDescriptors.Ak1007MustNotUseIWithTimersInPreRestart) | ||
{ | ||
public override void AnalyzeCompilation(CompilationStartAnalysisContext context, AkkaContext akkaContext) | ||
{ | ||
Guard.AssertIsNotNull(context); | ||
Guard.AssertIsNotNull(akkaContext); | ||
|
||
context.RegisterSyntaxNodeAction(ctx => | ||
{ | ||
var invocationExpr = (InvocationExpressionSyntax)ctx.Node; | ||
var semanticModel = ctx.SemanticModel; | ||
|
||
if (semanticModel.GetSymbolInfo(invocationExpr).Symbol is not IMethodSymbol methodInvocationSymbol) | ||
return; | ||
|
||
// Invocation expression must be either `ITimerScheduler.StartPeriodicTimer()` or `ITimerScheduler.StartSingleTimer()` | ||
var iWithTimers = akkaContext.AkkaCore.Actor.ITimerScheduler; | ||
var refMethods = iWithTimers.StartPeriodicTimer.AddRange(iWithTimers.StartSingleTimer); | ||
if (!methodInvocationSymbol.MatchesAny(refMethods)) | ||
return; | ||
|
||
// Grab the enclosing method declaration | ||
var methodDeclaration = invocationExpr.FirstAncestorOrSelf<MethodDeclarationSyntax>(); | ||
if (methodDeclaration is null) | ||
return; | ||
|
||
var methodDeclarationSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration); | ||
if(methodDeclarationSymbol is null) | ||
return; | ||
|
||
// Method declaration must be `ActorBase.PreRestart()` or `ActorBase.AroundPreRestart()` | ||
var actorBase = akkaContext.AkkaCore.Actor.ActorBase; | ||
refMethods = new[] { actorBase.PreRestart!, actorBase.AroundPreRestart! }.ToImmutableArray(); | ||
if (!methodDeclarationSymbol.OverridesAny(refMethods)) | ||
return; | ||
|
||
var diagnostic = Diagnostic.Create( | ||
descriptor: RuleDescriptors.Ak1007MustNotUseIWithTimersInPreRestart, | ||
location: invocationExpr.GetLocation(), | ||
messageArgs: [methodInvocationSymbol.Name, methodDeclarationSymbol.Name]); | ||
ctx.ReportDiagnostic(diagnostic); | ||
|
||
}, SyntaxKind.InvocationExpression); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
src/Akka.Analyzers/Context/Core/Actor/ITimerSchedulerContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// ----------------------------------------------------------------------- | ||
// <copyright file="ITimerSchedulerContext.cs" company="Akka.NET Project"> | ||
// Copyright (C) 2013-2024 .NET Foundation <https://github.com/akkadotnet/akka.net> | ||
// </copyright> | ||
// ----------------------------------------------------------------------- | ||
|
||
using System.Collections.Immutable; | ||
using Microsoft.CodeAnalysis; | ||
|
||
namespace Akka.Analyzers.Context.Core.Actor; | ||
|
||
public interface ITimerSchedulerContext | ||
{ | ||
public ImmutableArray<IMethodSymbol> StartPeriodicTimer { get; } | ||
public ImmutableArray<IMethodSymbol> StartSingleTimer { get; } | ||
} | ||
|
||
public sealed class EmptyTimerSchedulerContext : ITimerSchedulerContext | ||
{ | ||
public static readonly EmptyTimerSchedulerContext Instance = new(); | ||
private EmptyTimerSchedulerContext() { } | ||
public ImmutableArray<IMethodSymbol> StartPeriodicTimer => ImmutableArray<IMethodSymbol>.Empty; | ||
public ImmutableArray<IMethodSymbol> StartSingleTimer => ImmutableArray<IMethodSymbol>.Empty; | ||
} | ||
|
||
public sealed class TimerSchedulerContext : ITimerSchedulerContext | ||
{ | ||
private readonly Lazy<ImmutableArray<IMethodSymbol>> _lazyStartPeriodicTimer; | ||
private readonly Lazy<ImmutableArray<IMethodSymbol>> _lazyStartSingleTimer; | ||
|
||
private TimerSchedulerContext(AkkaCoreActorContext context) | ||
{ | ||
Guard.AssertIsNotNull(context); | ||
|
||
_lazyStartPeriodicTimer = new Lazy<ImmutableArray<IMethodSymbol>>(() => context.ITimerSchedulerType! | ||
.GetMembers(nameof(StartPeriodicTimer)).Select(m => (IMethodSymbol)m).ToImmutableArray()); | ||
_lazyStartSingleTimer = new Lazy<ImmutableArray<IMethodSymbol>>(() => context.ITimerSchedulerType! | ||
.GetMembers(nameof(StartSingleTimer)).Select(m => (IMethodSymbol)m).ToImmutableArray()); | ||
} | ||
|
||
public ImmutableArray<IMethodSymbol> StartPeriodicTimer => _lazyStartPeriodicTimer.Value; | ||
public ImmutableArray<IMethodSymbol> StartSingleTimer => _lazyStartSingleTimer.Value; | ||
|
||
public static TimerSchedulerContext Get(AkkaCoreActorContext context) | ||
{ | ||
Guard.AssertIsNotNull(context); | ||
|
||
return new TimerSchedulerContext(context); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters