From 412d5272afbe067e499be2023887152a9d1dea4c Mon Sep 17 00:00:00 2001 From: James Hargreaves Date: Tue, 27 Jun 2023 11:14:46 +0100 Subject: [PATCH] Fix RCS1146 (#1098) Co-authored-by: Josef Pihrt --- ChangeLog.md | 1 + .../Analysis/UseConditionalAccessAnalyzer.cs | 12 +++++++++++ .../RCS1146UseConditionalAccessTests.cs | 20 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 56ba8c41c6..670d905a29 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix [RCS1197](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1197.md) ([#1093](https://github.com/JosefPihrt/Roslynator/pull/1093)). - Fix [RCS1056](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1056.md) ([#1096](https://github.com/JosefPihrt/Roslynator/pull/1096)). - Fix [RCS1216](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1216.md) ([#1094](https://github.com/JosefPihrt/Roslynator/pull/1094)). +- Fix [RCS1146](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1146.md) ([#1098](https://github.com/JosefPihrt/Roslynator/pull/1098)). ## [4.3.0] - 2023-04-24 diff --git a/src/Analyzers/CSharp/Analysis/UseConditionalAccessAnalyzer.cs b/src/Analyzers/CSharp/Analysis/UseConditionalAccessAnalyzer.cs index 2959fdd407..5bd49667fe 100644 --- a/src/Analyzers/CSharp/Analysis/UseConditionalAccessAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/UseConditionalAccessAnalyzer.cs @@ -274,6 +274,18 @@ private static bool ValidateRightExpression( case SyntaxKind.GreaterThanOrEqualExpression: case SyntaxKind.EqualsExpression: { + var leftTypeSymbol = semanticModel.GetTypeSymbol(((BinaryExpressionSyntax)expression).Left); + + if (leftTypeSymbol.IsErrorType()) + return false; + + if (leftTypeSymbol.IsValueType && !CSharpFacts.IsPredefinedType(leftTypeSymbol.SpecialType)) + { + // If the LHS is a ValueTypes then making the expression conditional would change the type of the expression + // and hence we would call a different overload (a valid overload may not exists) + return false; + } + expression = ((BinaryExpressionSyntax)expression) .Right? .WalkDownParentheses(); diff --git a/src/Tests/Analyzers.Tests/RCS1146UseConditionalAccessTests.cs b/src/Tests/Analyzers.Tests/RCS1146UseConditionalAccessTests.cs index e523fc427e..f3c4c0b768 100644 --- a/src/Tests/Analyzers.Tests/RCS1146UseConditionalAccessTests.cs +++ b/src/Tests/Analyzers.Tests/RCS1146UseConditionalAccessTests.cs @@ -601,6 +601,26 @@ void M() "); } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseConditionalAccess)] + public async Task TestNoDiagnostic_LogicalAnd_ValueTypeFieldAccess() + { + await VerifyNoDiagnosticAsync(@" +struct Foo +{ + public static bool operator ==(Foo left, string right) => left.Equals(right); + public static bool operator !=(Foo left, string right) => !(left == right); +} +class C +{ + public Foo F { get; } + void M(C c) + { + if (c != null && c.F == ""someStr"") { } + } +} +"); + } + [Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.UseConditionalAccess)] public async Task TestNoDiagnostic_LogicalAnd_NullableType() {