diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1129CodeFixProvider.cs b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1129CodeFixProvider.cs index 85e624ae5..fea369877 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1129CodeFixProvider.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1129CodeFixProvider.cs @@ -214,6 +214,11 @@ private static bool IsEnumWithDefaultMember(INamedTypeSymbol namedTypeSymbol, ou /// A new member access expression. private static SyntaxNode ConstructMemberAccessSyntax(TypeSyntax typeSyntax, string memberName) { + // NOTE: This creates the correct source code when applied, but these are not necessarily the syntax + // nodes that the compiler would create from that source code. For example, the type syntax can + // contain QualifiedName nodes, whereas the compiler would have created SimpleMemberAccessExpression instead. + // This means that the validation that happens in the tests need to be turned off for some tests. + // We could have transformed the nodes to match, but we keep the code simple instead. return SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, typeSyntax, diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1131CodeFixProvider.cs b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1131CodeFixProvider.cs index a1fb6e336..02d9bc576 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1131CodeFixProvider.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.CodeFixes/ReadabilityRules/SA1131CodeFixProvider.cs @@ -66,33 +66,48 @@ private static async Task GetTransformedDocumentAsync(Document documen private static BinaryExpressionSyntax TransformExpression(BinaryExpressionSyntax binaryExpression) { + // NOTE: This code also changes the syntax node kind, besides the operator token. The modified source code would + // have been the same without this, but we do this to make tests pass with the default CodeActionValidationMode. var newLeft = binaryExpression.Right.WithTriviaFrom(binaryExpression.Left); var newRight = binaryExpression.Left.WithTriviaFrom(binaryExpression.Right); - return binaryExpression.WithLeft(newLeft).WithRight(newRight).WithOperatorToken(GetCorrectOperatorToken(binaryExpression.OperatorToken)); + GetReplacementInfo(binaryExpression.OperatorToken, out var newOperatorToken, out var newNodeKind); + return SyntaxFactory.BinaryExpression(newNodeKind, newLeft, newOperatorToken, newRight); } - private static SyntaxToken GetCorrectOperatorToken(SyntaxToken operatorToken) + private static void GetReplacementInfo(SyntaxToken operatorToken, out SyntaxToken newToken, out SyntaxKind newNodeKind) { switch (operatorToken.Kind()) { case SyntaxKind.EqualsEqualsToken: case SyntaxKind.ExclamationEqualsToken: - return operatorToken; + newToken = operatorToken; + newNodeKind = operatorToken.Parent.Kind(); + break; case SyntaxKind.GreaterThanToken: - return SyntaxFactory.Token(operatorToken.LeadingTrivia, SyntaxKind.LessThanToken, operatorToken.TrailingTrivia); + newToken = SyntaxFactory.Token(operatorToken.LeadingTrivia, SyntaxKind.LessThanToken, operatorToken.TrailingTrivia); + newNodeKind = SyntaxKind.LessThanExpression; + break; case SyntaxKind.GreaterThanEqualsToken: - return SyntaxFactory.Token(operatorToken.LeadingTrivia, SyntaxKind.LessThanEqualsToken, operatorToken.TrailingTrivia); + newToken = SyntaxFactory.Token(operatorToken.LeadingTrivia, SyntaxKind.LessThanEqualsToken, operatorToken.TrailingTrivia); + newNodeKind = SyntaxKind.LessThanOrEqualExpression; + break; case SyntaxKind.LessThanToken: - return SyntaxFactory.Token(operatorToken.LeadingTrivia, SyntaxKind.GreaterThanToken, operatorToken.TrailingTrivia); + newToken = SyntaxFactory.Token(operatorToken.LeadingTrivia, SyntaxKind.GreaterThanToken, operatorToken.TrailingTrivia); + newNodeKind = SyntaxKind.GreaterThanExpression; + break; case SyntaxKind.LessThanEqualsToken: - return SyntaxFactory.Token(operatorToken.LeadingTrivia, SyntaxKind.GreaterThanEqualsToken, operatorToken.TrailingTrivia); + newToken = SyntaxFactory.Token(operatorToken.LeadingTrivia, SyntaxKind.GreaterThanEqualsToken, operatorToken.TrailingTrivia); + newNodeKind = SyntaxKind.GreaterThanOrEqualExpression; + break; default: - return SyntaxFactory.Token(SyntaxKind.None); + newToken = SyntaxFactory.Token(SyntaxKind.None); + newNodeKind = (SyntaxKind)operatorToken.Parent.RawKind; + break; } } diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs index 35a5709ca..3cfff7e47 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/ReadabilityRules/SA1129UnitTests.cs @@ -406,7 +406,12 @@ public void TestMethod() }} "; - await VerifyCSharpFixAsync(testCode, DiagnosticResult.EmptyDiagnosticResults, fixedTestCode, CancellationToken.None).ConfigureAwait(false); + await new CSharpTest + { + TestCode = testCode, + FixedCode = fixedTestCode, + CodeActionValidationMode = CodeActionValidationMode.None, // Differences in syntax nodes (SimpleMemberAccessExpression vs QualifiedName) + }.RunAsync(CancellationToken.None).ConfigureAwait(false); } /// diff --git a/StyleCop.Analyzers/StyleCop.Analyzers.Test/Verifiers/StyleCopCodeFixVerifier`2.cs b/StyleCop.Analyzers/StyleCop.Analyzers.Test/Verifiers/StyleCopCodeFixVerifier`2.cs index 5f9be5385..3da289f01 100644 --- a/StyleCop.Analyzers/StyleCop.Analyzers.Test/Verifiers/StyleCopCodeFixVerifier`2.cs +++ b/StyleCop.Analyzers/StyleCop.Analyzers.Test/Verifiers/StyleCopCodeFixVerifier`2.cs @@ -133,7 +133,7 @@ public CSharpTest(LanguageVersion? languageVersion) .WithChangedOption(FormattingOptions.UseTabs, this.Language, this.UseTabs)); this.TestState.AdditionalFilesFactories.Add(GenerateSettingsFile); - this.CodeActionValidationMode = CodeActionValidationMode.None; + this.CodeActionValidationMode = CodeActionValidationMode.SemanticStructure; this.SolutionTransforms.Add((solution, projectId) => {