Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ If you are already using other analyzers, you can check [which rules are duplica
|[MA0169](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0169.md)|Design|Use Equals method instead of operator|⚠️|✔️|❌|
|[MA0170](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0170.md)|Design|Type cannot be used as an attribute argument|⚠️|❌|❌|
|[MA0171](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0171.md)|Usage|Use pattern matching instead of inequality operators for discrete value|ℹ️|❌|✔️|
|[MA0172](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0172.md)|Usage|Both sides of the logical operation are identical|⚠️|❌|❌|

<!-- rules -->

Expand Down
7 changes: 7 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@
|[MA0169](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0169.md)|Design|Use Equals method instead of operator|<span title='Warning'>⚠️</span>|✔️|❌|
|[MA0170](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0170.md)|Design|Type cannot be used as an attribute argument|<span title='Warning'>⚠️</span>|❌|❌|
|[MA0171](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0171.md)|Usage|Use pattern matching instead of inequality operators for discrete value|<span title='Info'>ℹ️</span>|❌|✔️|
|[MA0172](https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0172.md)|Usage|Both sides of the logical operation are identical|<span title='Warning'>⚠️</span>|❌|❌|

|Id|Suppressed rule|Justification|
|--|---------------|-------------|
Expand Down Expand Up @@ -692,6 +693,9 @@ dotnet_diagnostic.MA0170.severity = none

# MA0171: Use pattern matching instead of inequality operators for discrete value
dotnet_diagnostic.MA0171.severity = none

# MA0172: Both sides of the logical operation are identical
dotnet_diagnostic.MA0172.severity = none
```

# .editorconfig - all rules disabled
Expand Down Expand Up @@ -1206,4 +1210,7 @@ dotnet_diagnostic.MA0170.severity = none

# MA0171: Use pattern matching instead of inequality operators for discrete value
dotnet_diagnostic.MA0171.severity = none

# MA0172: Both sides of the logical operation are identical
dotnet_diagnostic.MA0172.severity = none
```
8 changes: 8 additions & 0 deletions docs/Rules/MA0172.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# MA0172 - Both sides of the logical operation are identical

This rule triggers when both sides of a logical operation (such as `&&`, `||`, `&`, `|`, `==`, `!=`, or pattern matching operations) are identical. This usually indicates a mistake or redundant code.

```csharp
_ = x == x; // non-compliant
_ = x is true or true; // non-compliant
```
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,6 @@ dotnet_diagnostic.MA0170.severity = none

# MA0171: Use pattern matching instead of inequality operators for discrete value
dotnet_diagnostic.MA0171.severity = none

# MA0172: Both sides of the logical operation are identical
dotnet_diagnostic.MA0172.severity = none
3 changes: 3 additions & 0 deletions src/Meziantou.Analyzer.Pack/configuration/none.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,6 @@ dotnet_diagnostic.MA0170.severity = none

# MA0171: Use pattern matching instead of inequality operators for discrete value
dotnet_diagnostic.MA0171.severity = none

# MA0172: Both sides of the logical operation are identical
dotnet_diagnostic.MA0172.severity = none
1 change: 1 addition & 0 deletions src/Meziantou.Analyzer/RuleIdentifiers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ internal static class RuleIdentifiers
public const string UseEqualsMethodInsteadOfOperator = "MA0169";
public const string TypeCannotBeUsedInAnAttributeParameter = "MA0170";
public const string UsePatternMatchingInsteadOfHasvalue = "MA0171";
public const string BothSideOfTheConditionAreIdentical = "MA0172";

public static string GetHelpUri(string identifier)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Collections.Immutable;
using Meziantou.Analyzer.Internals;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;

namespace Meziantou.Analyzer.Rules;

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class BothSideOfTheConditionAreIdenticalAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor Rule = new(
RuleIdentifiers.BothSideOfTheConditionAreIdentical,
title: "Both sides of the logical operation are identical",
messageFormat: "Both sides of the logical operation are identical",
RuleCategories.Usage,
DiagnosticSeverity.Warning,
isEnabledByDefault: false,
helpLinkUri: RuleIdentifiers.GetHelpUri(RuleIdentifiers.BothSideOfTheConditionAreIdentical));

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);

public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);


context.RegisterOperationAction(AnalyzeBinaryOperation, OperationKind.Binary);
context.RegisterOperationAction(AnalyzeBinaryPatternOperation, OperationKind.BinaryPattern);
}

private void AnalyzeBinaryOperation(OperationAnalysisContext context)
{
var operation = (IBinaryOperation)context.Operation;
if (operation.OperatorKind is BinaryOperatorKind.ConditionalAnd or BinaryOperatorKind.ConditionalOr or BinaryOperatorKind.And or BinaryOperatorKind.Or or BinaryOperatorKind.Equals or BinaryOperatorKind.NotEquals)
{
if (operation.Type.IsBoolean() && operation.LeftOperand.Syntax.IsEquivalentTo(operation.RightOperand.Syntax, topLevel: false))
{
context.ReportDiagnostic(Rule, operation);
}
}
}

private void AnalyzeBinaryPatternOperation(OperationAnalysisContext context)
{
var operation = (IBinaryPatternOperation)context.Operation;
if (operation.OperatorKind is BinaryOperatorKind.And or BinaryOperatorKind.Or)
{
if (operation.LeftPattern.Syntax.IsEquivalentTo(operation.RightPattern.Syntax, topLevel: false))
{
context.ReportDiagnostic(Rule, operation);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Meziantou.Analyzer.Rules;
using TestHelper;
using Xunit;

namespace Meziantou.Analyzer.Test.Rules;

public sealed class BothSideOfTheConditionAreIdenticalAnalyzerTests
{
private static ProjectBuilder CreateProjectBuilder()
{
return new ProjectBuilder()
.WithOutputKind(Microsoft.CodeAnalysis.OutputKind.ConsoleApplication)
.WithAnalyzer<BothSideOfTheConditionAreIdenticalAnalyzer>();
}

[Theory]
[InlineData("a == b")]
[InlineData("a != b")]
[InlineData("a & b")]
[InlineData("a && b")]
[InlineData("a | b")]
[InlineData("a || b")]
[InlineData("a is false")]
[InlineData("a is true")]
[InlineData("a is false or true")]
[InlineData("a is false and not true")]
public async Task DifferentCode(string expression)
{
await CreateProjectBuilder()
.WithSourceCode($$"""
var a = false;
var b = false;
var c = 0;
_ = {{expression}};
""")
.ValidateAsync();
}

[Theory]
[InlineData("[|a == a|]")]
[InlineData("[|a != a|]")]
[InlineData("[|a & a|]")]
[InlineData("[|a && a|]")]
[InlineData("[|a | a|]")]
[InlineData("[|a || a|]")]
[InlineData("a is [|true or true|]")]
[InlineData("a is [|true and true|]")]
public async Task SameCode(string expression)
{
await CreateProjectBuilder()
.WithSourceCode($$"""
var a = false;
var b = false;
var c = 0;
_ = {{expression}};
""")
.ValidateAsync();
}

}