-
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.
* Check for `TimeSpan.Zero` on `Ask` and `Ask<T>` operationrs close #11 close akkadotnet/akka.net#6131 * working on specs * sdfsdf * have tests finally starting to pass * cleaning up tests and unused code * disabled variable scanning - not supported yet
- Loading branch information
1 parent
5482a51
commit 4258d1c
Showing
6 changed files
with
213 additions
and
3 deletions.
There are no files selected for viewing
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
132 changes: 132 additions & 0 deletions
132
src/Akka.Analyzers.Tests/Analyzers/AK2000/MustNotUseTimeSpanZeroWithAskAnalyzerSpecs.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,132 @@ | ||
// ----------------------------------------------------------------------- | ||
// <copyright file="MustNotUseTimeSpanZeroWithAskAnalyzerSpecs.cs" company="Akka.NET Project"> | ||
// Copyright (C) 2015-2023 .NET Petabridge, LLC | ||
// </copyright> | ||
// ----------------------------------------------------------------------- | ||
|
||
using Verify = Akka.Analyzers.Tests.Utility.AkkaVerifier<Akka.Analyzers.AK2000.MustNotUseTimeSpanZeroWithAskAnalyzer>; | ||
|
||
namespace Akka.Analyzers.Tests.Analyzers.AK2000; | ||
|
||
public class MustNotUseTimeSpanZeroWithAskAnalyzerSpecs | ||
{ | ||
public static readonly TheoryData<string> SuccessCases = new() | ||
{ | ||
// Explicit non-zero TimeSpan | ||
@"using Akka.Actor; | ||
using System.Threading.Tasks; | ||
using System; | ||
public static class MyActorCaller{ | ||
public static Task<string> Call(IActorRef actor){ | ||
return actor.Ask<string>(""hello"", TimeSpan.FromSeconds(1)); | ||
} | ||
}", | ||
|
||
// Implicit timeout - handled by Akka.NET default timeout | ||
@"using Akka.Actor; | ||
using System.Threading.Tasks; | ||
using System; | ||
public static class MyActorCaller{ | ||
public static Task<string> Call(IActorRef actor){ | ||
return actor.Ask<string>(""hello""); | ||
} | ||
}" | ||
}; | ||
|
||
[Theory] | ||
[MemberData(nameof(SuccessCases))] | ||
public Task SuccessCase(string code) | ||
{ | ||
return Verify.VerifyAnalyzer(code); | ||
} | ||
|
||
[Fact] | ||
public Task FailureCaseExplicitZeroTimeSpanGeneric() | ||
{ | ||
var code = | ||
@"using Akka.Actor; | ||
using System.Threading.Tasks; | ||
using System; | ||
public static class MyActorCaller{ | ||
public static Task<string> Call(IActorRef actor){ | ||
return actor.Ask<string>(""hello"", TimeSpan.Zero); | ||
} | ||
}"; | ||
var expectedDiagnostic = Verify.Diagnostic().WithSpan(7, 44, 7, 57); // Adjust the line and character positions | ||
return Verify.VerifyAnalyzer(code, expectedDiagnostic); | ||
} | ||
|
||
[Fact] | ||
public Task FailureCaseExplicitZeroTimeSpanNonGeneric() | ||
{ | ||
var code = | ||
@"using Akka.Actor; | ||
using System.Threading.Tasks; | ||
using System; | ||
public static class MyActorCaller{ | ||
public static Task Call(IActorRef actor){ | ||
return actor.Ask(""hello"", TimeSpan.Zero); | ||
} | ||
}"; | ||
var expectedDiagnostic = Verify.Diagnostic().WithSpan(7, 36, 7, 49); // Adjust the line and character positions | ||
return Verify.VerifyAnalyzer(code, expectedDiagnostic); | ||
} | ||
|
||
|
||
[Fact] | ||
public Task FailureCaseExplicitZeroTimeSpanWithNamedArgumentAndOtherArguments() | ||
{ | ||
var code = | ||
@"using Akka.Actor; | ||
using System.Threading.Tasks; | ||
using System; | ||
public static class MyActorCaller{ | ||
public static Task<string> Call(IActorRef actor, string message){ | ||
return actor.Ask<string>(message, timeout: TimeSpan.Zero, cancellationToken: default); | ||
} | ||
}"; | ||
var expectedDiagnostic = Verify.Diagnostic().WithSpan(7, 44, 7, 66); | ||
return Verify.VerifyAnalyzer(code, expectedDiagnostic); | ||
} | ||
|
||
[Fact(Skip = "Variable analysis not yet implemented")] | ||
public Task FailureCaseTimeSpanVariableSetToDefault() | ||
{ | ||
var code = | ||
@"using Akka.Actor; | ||
using System.Threading.Tasks; | ||
using System; | ||
public static class MyActorCaller{ | ||
public static Task<string> Call(IActorRef actor){ | ||
TimeSpan myTs = default; | ||
return actor.Ask<string>(""hello"", timeout: myTs); | ||
} | ||
}"; | ||
var expectedDiagnostic = Verify.Diagnostic().WithLocation(7, 19); // Adjust accordingly | ||
return Verify.VerifyAnalyzer(code, expectedDiagnostic); | ||
} | ||
|
||
[Fact(Skip = "Variable analysis not yet implemented")] | ||
public Task FailureCaseTimeSpanVariableSetToTimeSpanZero() | ||
{ | ||
var code = | ||
@"using Akka.Actor; | ||
using System.Threading.Tasks; | ||
using System; | ||
public static class MyActorCaller{ | ||
public static Task<string> Call(IActorRef actor){ | ||
TimeSpan myTs = TimeSpan.Zero; | ||
return actor.Ask<string>(""hello"", timeout: myTs); | ||
} | ||
}"; | ||
var expectedDiagnostic = Verify.Diagnostic().WithLocation(7, 19); // Adjust accordingly | ||
return Verify.VerifyAnalyzer(code, expectedDiagnostic); | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
src/Akka.Analyzers/AK2000/MustNotUseTimeSpanZeroWithAskAnalyzer.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,59 @@ | ||
// ----------------------------------------------------------------------- | ||
// <copyright file="MustNotUseTimeSpanZeroWithAskAnalyzer.cs" company="Akka.NET Project"> | ||
// Copyright (C) 2015-2023 .NET Petabridge, LLC | ||
// </copyright> | ||
// ----------------------------------------------------------------------- | ||
|
||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
||
namespace Akka.Analyzers.AK2000; | ||
|
||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public class MustNotUseTimeSpanZeroWithAskAnalyzer() | ||
: AkkaDiagnosticAnalyzer(RuleDescriptors.Ak2000DoNotUseZeroTimeoutWithAsk) | ||
{ | ||
public override void AnalyzeCompilation(CompilationStartAnalysisContext context, AkkaContext akkaContext) | ||
{ | ||
Guard.AssertIsNotNull(context); | ||
Guard.AssertIsNotNull(akkaContext); | ||
|
||
context.RegisterSyntaxNodeAction(ctx => | ||
{ | ||
var invocationExpr = (InvocationExpressionSyntax)ctx.Node; | ||
|
||
if (ctx.SemanticModel.GetSymbolInfo(invocationExpr).Symbol is IMethodSymbol { Name: "Ask" } methodSymbol && | ||
methodSymbol.Parameters.Any(p => p.Type.ToString() == "System.TimeSpan?")) | ||
{ | ||
foreach (var argument in invocationExpr.ArgumentList.Arguments) | ||
{ | ||
if (ctx.SemanticModel.GetTypeInfo(argument.Expression).Type is INamedTypeSymbol argType && | ||
argType.ConstructedFrom.ToString() == "System.TimeSpan") | ||
{ | ||
if (argument.Expression is MemberAccessExpressionSyntax { Name.Identifier.ValueText: "Zero" }) | ||
{ | ||
var diagnostic = Diagnostic.Create(RuleDescriptors.Ak2000DoNotUseZeroTimeoutWithAsk, | ||
argument.GetLocation()); | ||
ctx.ReportDiagnostic(diagnostic); | ||
} | ||
else if (argument.Expression is IdentifierNameSyntax identifierName) | ||
{ | ||
var symbol = ctx.SemanticModel.GetSymbolInfo(identifierName).Symbol; | ||
if (symbol is ILocalSymbol | ||
{ | ||
HasConstantValue: true, ConstantValue: not null | ||
} localSymbol && localSymbol.ConstantValue.Equals(TimeSpan.Zero)) | ||
{ | ||
var diagnostic = Diagnostic.Create(RuleDescriptors.Ak2000DoNotUseZeroTimeoutWithAsk, | ||
argument.GetLocation()); | ||
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> | ||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ak1000/@EntryIndexedValue">True</s:Boolean> | ||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=ak2000/@EntryIndexedValue">True</s:Boolean> | ||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=utility/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> |
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