Skip to content

Commit 13935bd

Browse files
committed
fixes 18
1 parent 1c100bf commit 13935bd

File tree

7 files changed

+74
-40
lines changed

7 files changed

+74
-40
lines changed

src/FluentAssertions.Analyzers.Tests/Tips/SanityTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,15 @@ public void NestedAssertions_ShouldNotTrigger()
5555

5656
DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source);
5757
}
58+
59+
[TestMethod]
60+
[NotImplemented]
61+
public void DictionaryShouldContainPair_WhenPropertiesOfDifferentVariables_ShouldNotTrigger()
62+
{
63+
const string assertion = "actual.Should().ContainValue(pair.Value).And.ContainKey(otherPair.Key);";
64+
var source = GenerateCode.DictionaryAssertion(assertion);
65+
66+
DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source);
67+
}
5868
}
5969
}

src/FluentAssertions.Analyzers/Tips/Collections/CollectionShouldOnlyHaveUniqueItems.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ private static bool ArgumentInvokesDistinctMethod(SeparatedSyntaxList<ArgumentSy
4242
var visitor = new FluentAssertionsCSharpSyntaxVisitor(new MemberValidator(nameof(Enumerable.Distinct)));
4343
invocation.Accept(visitor);
4444

45-
return visitor.IsValid && VariableNameExtractor.ExtractVariabeName(arguments.First()) == VariableNameExtractor.ExtractVariabeName(invocation);
45+
return visitor.IsValid(invocation) && VariableNameExtractor.ExtractVariabeName(arguments.First()) == VariableNameExtractor.ExtractVariabeName(invocation);
4646
}
4747
return false;
4848
}

src/FluentAssertions.Analyzers/Tips/Dictionaries/DictionaryShouldContainPair.cs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,37 @@ protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
2626
yield return new ShouldContainValueAndContainKeySyntaxVisitor();
2727
}
2828
}
29-
30-
// TODO: how to extract the property accessing the Key & Value properties and compare them
29+
3130
public abstract class ContainKeyValueSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
3231
{
33-
private string KeyPropertyParentName;
34-
private string ValuePropertyParentName;
35-
3632
protected ContainKeyValueSyntaxVisitor(params MemberValidator[] members) : base(members)
3733
{
3834
}
3935

40-
public override bool IsValid => base.IsValid && KeyPropertyParentName == ValuePropertyParentName;
36+
public override bool IsValid(ExpressionSyntax expression)
37+
{
38+
if (!base.IsValid(expression)) return false;
39+
40+
var visitor = new MemberAccessExpressionsCSharpSyntaxVisitor();
41+
expression.Accept(visitor);
42+
43+
var containKey = visitor.Members.Find(member => member.Name.Identifier.Text == "ContainKey");
44+
var containValue = visitor.Members.Find(member => member.Name.Identifier.Text == "ContainValue");
45+
46+
return containKey.Parent is InvocationExpressionSyntax keyInvocation
47+
&& containValue.Parent is InvocationExpressionSyntax valueInvocation
48+
49+
&& keyInvocation.ArgumentList.Arguments is SeparatedSyntaxList<ArgumentSyntax> containKeyArguments
50+
&& valueInvocation.ArgumentList.Arguments is SeparatedSyntaxList<ArgumentSyntax> containValueArguments
51+
52+
&& containKeyArguments.First().Expression is MemberAccessExpressionSyntax keyArgument
53+
&& containValueArguments.First().Expression is MemberAccessExpressionSyntax valueArgument
54+
55+
&& keyArgument.Expression is IdentifierNameSyntax keyIdentifier
56+
&& valueArgument.Expression is IdentifierNameSyntax valueIdentifier
57+
58+
&& keyIdentifier.Identifier.Text == valueIdentifier.Identifier.Text;
59+
}
4160

4261
protected static bool KeyIsProperty(SeparatedSyntaxList<ArgumentSyntax> arguments)
4362
{
@@ -51,13 +70,9 @@ protected static bool ValueIsProperty(SeparatedSyntaxList<ArgumentSyntax> argume
5170
{
5271
if (!arguments.Any()) return false;
5372

54-
if (arguments.First().Expression is MemberAccessExpressionSyntax valueAccess
73+
return arguments.First().Expression is MemberAccessExpressionSyntax valueAccess
5574
&& valueAccess.Expression is IdentifierNameSyntax identifier
56-
&& valueAccess.Name.Identifier.Text == "Value")
57-
{
58-
return true;
59-
}
60-
return false;
75+
&& valueAccess.Name.Identifier.Text == "Value";
6176
}
6277
}
6378

@@ -136,4 +151,4 @@ private SeparatedSyntaxList<ArgumentSyntax> GetArgumentsWithFirstAsPairIdentifie
136151
return arguments.Replace(argument, argument.WithExpression(identifier));
137152
}
138153
}
139-
}
154+
}

src/FluentAssertions.Analyzers/Utilities/FluentAssertionsAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ protected virtual Diagnostic AnalyzeExpression(ExpressionSyntax expression)
5656
{
5757
expression.Accept(visitor);
5858

59-
if (visitor.IsValid)
59+
if (visitor.IsValid(expression))
6060
{
6161
return CreateDiagnostic(visitor, expression);
6262
}

src/FluentAssertions.Analyzers/Utilities/FluentAssertionsCSharpSyntaxVisitor.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
using Microsoft.CodeAnalysis;
2-
using Microsoft.CodeAnalysis.CSharp;
1+
using Microsoft.CodeAnalysis.CSharp;
32
using Microsoft.CodeAnalysis.CSharp.Syntax;
4-
using System;
53
using System.Collections.Immutable;
6-
using System.Linq;
74

85
namespace FluentAssertions.Analyzers
96
{
@@ -14,7 +11,7 @@ public class FluentAssertionsCSharpSyntaxVisitor : CSharpSyntaxVisitor
1411
public ImmutableStack<MemberValidator> AllMembers { get; }
1512
public ImmutableStack<MemberValidator> Members { get; private set; }
1613

17-
public virtual bool IsValid => Members.IsEmpty;
14+
public virtual bool IsValid(ExpressionSyntax expression) => Members.IsEmpty;
1815

1916
public virtual ImmutableDictionary<string, string> ToDiagnosticProperties() => ImmutableDictionary<string, string>.Empty
2017
.Add(Constants.DiagnosticProperties.VisitorName, GetType().Name)

src/FluentAssertions.Analyzers/Utilities/FluentAssertionsCodeFixProvider.cs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ protected ExpressionSyntax GetNewExpression(ExpressionSyntax expression, NodeRep
6161
{
6262
var visitor = new MemberAccessExpressionsCSharpSyntaxVisitor();
6363
expression.Accept(visitor);
64-
var members = new LinkedList<MemberAccessExpressionSyntax>(visitor.Members);
64+
var members = new LinkedList<MemberAccessExpressionSyntax>(visitor.Members);
6565

6666
var current = members.Last;
6767
while (current != null)
@@ -78,24 +78,5 @@ protected ExpressionSyntax GetNewExpression(ExpressionSyntax expression, NodeRep
7878

7979
throw new System.InvalidOperationException("should not get here");
8080
}
81-
82-
protected class MemberAccessExpressionsCSharpSyntaxVisitor : CSharpSyntaxVisitor
83-
{
84-
public List<MemberAccessExpressionSyntax> Members { get; } = new List<MemberAccessExpressionSyntax>();
85-
86-
public override void VisitInvocationExpression(InvocationExpressionSyntax node) => Visit(node.Expression);
87-
88-
public sealed override void VisitExpressionStatement(ExpressionStatementSyntax node) => Visit(node.Expression);
89-
90-
91-
public sealed override void VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
92-
{
93-
if (node.Name.Identifier.Text != "And")
94-
{
95-
Members.Add(node);
96-
}
97-
Visit(node.Expression);
98-
}
99-
}
10081
}
10182
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CodeActions;
3+
using Microsoft.CodeAnalysis.CodeFixes;
4+
using Microsoft.CodeAnalysis.CSharp;
5+
using Microsoft.CodeAnalysis.CSharp.Syntax;
6+
using System.Collections.Generic;
7+
using System.Collections.Immutable;
8+
using System.Threading;
9+
using System.Threading.Tasks;
10+
11+
namespace FluentAssertions.Analyzers
12+
{
13+
public class MemberAccessExpressionsCSharpSyntaxVisitor : CSharpSyntaxVisitor
14+
{
15+
public List<MemberAccessExpressionSyntax> Members { get; } = new List<MemberAccessExpressionSyntax>();
16+
17+
public override void VisitInvocationExpression(InvocationExpressionSyntax node) => Visit(node.Expression);
18+
19+
public sealed override void VisitExpressionStatement(ExpressionStatementSyntax node) => Visit(node.Expression);
20+
21+
22+
public sealed override void VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
23+
{
24+
if (node.Name.Identifier.Text != "And")
25+
{
26+
Members.Add(node);
27+
}
28+
Visit(node.Expression);
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)