Skip to content

Commit

Permalink
feat: Migrate NullConditionalAssertion to IOperation (#280)
Browse files Browse the repository at this point in the history
* feat: Migrate NullConditionalAssertion to IOperation

* feat: Migrate NullConditionalAssertion to IOperation
  • Loading branch information
Meir017 authored Jan 4, 2024
1 parent ca48078 commit a34ac27
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ public class NullConditionalAssertionTests
public void NullConditionalMayNotExecuteTest(string assertion)
{
DiagnosticVerifier.VerifyDiagnostic(new DiagnosticVerifierArguments()
.WithDiagnosticAnalyzer<NullConditionalAssertionAnalyzer>()
.WithDiagnosticAnalyzer<FluentAssertionsOperationAnalyzer>()
.WithSources(Code(assertion))
.WithPackageReferences(PackageReference.FluentAssertions_6_12_0)
.WithExpectedDiagnostics(new DiagnosticResult
{
Id = NullConditionalAssertionAnalyzer.DiagnosticId,
Message = NullConditionalAssertionAnalyzer.Message,
Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Warning,
Id = FluentAssertionsOperationAnalyzer.DiagnosticId,
Message = DiagnosticMetadata.NullConditionalMayNotExecute.Message,
Severity = Microsoft.CodeAnalysis.DiagnosticSeverity.Info, // TODO: change to warning
VisitorName = nameof(DiagnosticMetadata.NullConditionalMayNotExecute),
Locations = new DiagnosticResultLocation[]
{
new DiagnosticResultLocation("Test0.cs", 11, 13)
Expand All @@ -37,12 +38,12 @@ public void NullConditionalMayNotExecuteTest(string assertion)
[DataTestMethod]
[AssertionDiagnostic("(actual?.MyProperty).Should().Be(\"test\"{0});")]
[AssertionDiagnostic("actual.MyProperty.Should().Be(actual?.MyProperty{0});")]
[AssertionDiagnostic("actual.MyList.Where(obj => obj?.ToString() == null).Count().Should().Be(0{0});")]
[AssertionDiagnostic("actual.MyList.Where(obj => obj?.ToString() == null).Should().HaveCount(6{0});")]
[Implemented]
public void NullConditionalWillStillExecuteTest(string assertion)
{
DiagnosticVerifier.VerifyDiagnostic(new DiagnosticVerifierArguments()
.WithDiagnosticAnalyzer<NullConditionalAssertionAnalyzer>()
.WithDiagnosticAnalyzer<FluentAssertionsOperationAnalyzer>()
.WithSources(Code(assertion))
.WithPackageReferences(PackageReference.FluentAssertions_6_12_0)
);
Expand Down
6 changes: 3 additions & 3 deletions src/FluentAssertions.Analyzers.Tests/Tips/SanityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -441,9 +441,9 @@ public class MyCollectionType { }";
.WithPackageReferences(PackageReference.FluentAssertions_6_12_0)
.WithExpectedDiagnostics(new DiagnosticResult()
{
Id = NullConditionalAssertionAnalyzer.DiagnosticId,
Message = NullConditionalAssertionAnalyzer.Message,
Severity = DiagnosticSeverity.Warning,
Id = FluentAssertionsOperationAnalyzer.DiagnosticId,
Message = DiagnosticMetadata.NullConditionalMayNotExecute.Message,
Severity = DiagnosticSeverity.Info, // TODO: change to warning
Locations = new[] { new DiagnosticResultLocation("Test0.cs", 13, 9) }
})
);
Expand Down
1 change: 0 additions & 1 deletion src/FluentAssertions.Analyzers/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public static class CodeSmell
{
public const string Category = "FluentAssertionCodeSmell";

public const string NullConditionalAssertion = $"{DiagnosticProperties.IdPrefix}0800";
public const string AsyncVoid = $"{DiagnosticProperties.IdPrefix}0801";
public const string ShouldEquals = $"{DiagnosticProperties.IdPrefix}0802";
}
Expand Down
1 change: 1 addition & 0 deletions src/FluentAssertions.Analyzers/Tips/DiagnosticMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ private DiagnosticMetadata(string message, string helpLink, [CallerMemberName] s
public static DiagnosticMetadata CollectionShouldEqual_CollectionShouldEquals = new("Use .Should().Equal()", string.Empty);
public static DiagnosticMetadata ShouldEquals = new("Use .Should().Be() or .Should().BeEquivalentTo or .Should().Equal() or other equivalency assertion", string.Empty);
public static DiagnosticMetadata ShouldBe_ShouldEquals = new("Use .Should().Be()", string.Empty);
public static DiagnosticMetadata NullConditionalMayNotExecute = new("Use .Should() instead of ?.Should()", string.Empty);

private static string GetHelpLink(string id) => $"https://fluentassertions.com/tips/#{id}";
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ protected override CreateChangedDocument TryComputeFix(IInvocationOperation asse
return null;
}

if (visitorName is nameof(DiagnosticMetadata.ShouldEquals))
if (visitorName is nameof(DiagnosticMetadata.ShouldEquals) or nameof(DiagnosticMetadata.NullConditionalMayNotExecute))
{
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Operations;

namespace FluentAssertions.Analyzers;
Expand Down Expand Up @@ -36,6 +37,22 @@ private static bool TryGetExceptionPropertyAssertion(IInvocationOperation assert
return false;
}

private static bool HasConditionalAccessAncestor(IInvocationOperation invocation)
{
var current = invocation.Parent;
while (current is not null)
{
if (current.Kind is OperationKind.ConditionalAccess)
{
return true;
}

current = current.Parent;
}

return false;
}

private class FluentAssertionsMetadata
{
public FluentAssertionsMetadata(Compilation compilation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ private static void AnalyzeInvocation(OperationAnalysisContext context, FluentAs
{
return;
}
if (assertion.Parent.Kind is OperationKind.ConditionalAccess)

if (HasConditionalAccessAncestor(invocation))
{
return; // Handled by NullConditionalAssertionAnalyzer
var expressionStatement = invocation.GetFirstAncestor<IExpressionStatementOperation>();
context.ReportDiagnostic(CreateDiagnostic(expressionStatement, DiagnosticMetadata.NullConditionalMayNotExecute));
return;
}

var subject = invocation.Arguments[0].Value;
Expand Down

This file was deleted.

0 comments on commit a34ac27

Please sign in to comment.