Skip to content

Commit 4288bf9

Browse files
authored
Merge branch 'main' into copilot/fix-207
2 parents f3d313f + 9bfd6f3 commit 4288bf9

29 files changed

Lines changed: 1256 additions & 744 deletions

.editorconfig

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,58 @@ dotnet_diagnostic.CS7035.severity = none
112112
# We do not need compile-time generated RegExs in Unit Tests. We'll prefer code readability.
113113
dotnet_diagnostic.SYSLIB1045.severity = none
114114

115+
dotnet_diagnostic.MSTEST0001.severity = error
116+
dotnet_diagnostic.MSTEST0002.severity = error
117+
dotnet_diagnostic.MSTEST0003.severity = error
118+
dotnet_diagnostic.MSTEST0004.severity = error
119+
dotnet_diagnostic.MSTEST0005.severity = error
120+
dotnet_diagnostic.MSTEST0006.severity = error
121+
dotnet_diagnostic.MSTEST0007.severity = error
122+
dotnet_diagnostic.MSTEST0008.severity = error
123+
dotnet_diagnostic.MSTEST0009.severity = error
124+
dotnet_diagnostic.MSTEST0010.severity = error
125+
dotnet_diagnostic.MSTEST0011.severity = error
126+
dotnet_diagnostic.MSTEST0012.severity = error
127+
dotnet_diagnostic.MSTEST0013.severity = error
128+
dotnet_diagnostic.MSTEST0014.severity = error
129+
dotnet_diagnostic.MSTEST0015.severity = error
130+
dotnet_diagnostic.MSTEST0016.severity = error
131+
dotnet_diagnostic.MSTEST0017.severity = error
132+
dotnet_diagnostic.MSTEST0018.severity = error
133+
dotnet_diagnostic.MSTEST0019.severity = none # Do not prefer TestInitialize over constructors
134+
dotnet_diagnostic.MSTEST0020.severity = error
135+
dotnet_diagnostic.MSTEST0021.severity = error
136+
dotnet_diagnostic.MSTEST0022.severity = error
137+
dotnet_diagnostic.MSTEST0023.severity = error
138+
dotnet_diagnostic.MSTEST0024.severity = error
139+
dotnet_diagnostic.MSTEST0025.severity = error
140+
dotnet_diagnostic.MSTEST0026.severity = error
141+
dotnet_diagnostic.MSTEST0027.severity = error
142+
dotnet_diagnostic.MSTEST0028.severity = error
143+
dotnet_diagnostic.MSTEST0029.severity = error
144+
dotnet_diagnostic.MSTEST0030.severity = error
145+
dotnet_diagnostic.MSTEST0031.severity = error
146+
dotnet_diagnostic.MSTEST0032.severity = error
147+
dotnet_diagnostic.MSTEST0033.severity = error
148+
dotnet_diagnostic.MSTEST0034.severity = error
149+
dotnet_diagnostic.MSTEST0035.severity = error
150+
dotnet_diagnostic.MSTEST0036.severity = error
151+
dotnet_diagnostic.MSTEST0037.severity = error
152+
dotnet_diagnostic.MSTEST0038.severity = error
153+
dotnet_diagnostic.MSTEST0039.severity = error
154+
dotnet_diagnostic.MSTEST0040.severity = error
155+
dotnet_diagnostic.MSTEST0041.severity = error
156+
dotnet_diagnostic.MSTEST0042.severity = error
157+
dotnet_diagnostic.MSTEST0043.severity = error
158+
dotnet_diagnostic.MSTEST0044.severity = error
159+
dotnet_diagnostic.MSTEST0045.severity = error
160+
dotnet_diagnostic.MSTEST0046.severity = error
161+
dotnet_diagnostic.MSTEST0047.severity = error
162+
dotnet_diagnostic.MSTEST0048.severity = error
163+
dotnet_diagnostic.MSTEST0049.severity = error
164+
dotnet_diagnostic.MSTEST0050.severity = error
165+
166+
115167
dotnet_diagnostic.IDE0001.severity = error
116168
dotnet_diagnostic.IDE0002.severity = error
117169
dotnet_diagnostic.IDE0003.severity = error

Documentation/Diagnostics/PH2033.md

Lines changed: 0 additions & 71 deletions
This file was deleted.

Documentation/Diagnostics/PH2035.md

Lines changed: 0 additions & 61 deletions
This file was deleted.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# PH2144: Backwards for-loop boundary check should use >= 0 instead of > 0
2+
3+
| Property | Value |
4+
|--|--|
5+
| Package | [Philips.CodeAnalysis.MaintainabilityAnalyzers](https://www.nuget.org/packages/Philips.CodeAnalysis.MaintainabilityAnalyzers) |
6+
| Diagnostic ID | PH2144 |
7+
| Category | [Maintainability](../Maintainability.md) |
8+
| Analyzer | [AvoidIncorrectForLoopConditionAnalyzer](https://github.com/philips-software/roslyn-analyzers/blob/main/Philips.CodeAnalysis.MaintainabilityAnalyzers/Maintainability/AvoidIncorrectForLoopConditionAnalyzer.cs)
9+
| CodeFix | Yes |
10+
| Severity | Error |
11+
| Enabled By Default | Yes |
12+
13+
## Introduction
14+
15+
When looping backwards from a collection count to 0, use `>= 0` instead of `> 0` to ensure the element at index 0 is processed. Using `> 0` in the loop condition causes the loop to skip the element at index 0, which is often unintended.
16+
17+
## How to solve
18+
19+
Change the loop condition from `> 0` to `>= 0` to include the element at index 0.
20+
21+
## Example
22+
23+
Code that triggers a diagnostic:
24+
``` cs
25+
class BadExample
26+
{
27+
public void BadMethod()
28+
{
29+
var list = new List<int> { 1, 2, 3, 4, 5 };
30+
31+
// This loop skips the element at index 0
32+
for (var index = list.Count - 1; index > 0; index--)
33+
{
34+
Console.WriteLine(list[index]);
35+
}
36+
}
37+
}
38+
39+
```
40+
41+
And the replacement code:
42+
``` cs
43+
class GoodExample
44+
{
45+
public void GoodMethod()
46+
{
47+
var list = new List<int> { 1, 2, 3, 4, 5 };
48+
49+
// This loop processes all elements including index 0
50+
for (var index = list.Count - 1; index >= 0; index--)
51+
{
52+
Console.WriteLine(list[index]);
53+
}
54+
}
55+
}
56+
57+
```
58+
59+
## Configuration
60+
61+
This analyzer does not offer any special configuration. The general ways of [suppressing](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/suppress-warnings) diagnostics apply.
62+
63+
## Legitimate Use Cases and Workarounds
64+
65+
In rare cases, you may intentionally want to skip the element at index 0 in a backwards loop. When this is the case, the analyzer will produce a false positive. Here are several clean workarounds to avoid triggering the analyzer while preserving the intended behavior:
66+
67+
### Workaround 1: Use `>= 1` instead of `> 0`
68+
``` cs
69+
// Instead of: for (var i = array.Length - 1; i > 0; i--)
70+
for (var i = array.Length - 1; i >= 1; i--) // Mathematically equivalent but clearer intent
71+
{
72+
// Process elements from index 1 to array.Length - 1 (skipping index 0)
73+
}
74+
```
75+
76+
### Workaround 2: Make the exclusion explicit with variables
77+
``` cs
78+
// Make it clear that you're intentionally excluding the first element
79+
var startIndex = array.Length - 1;
80+
var stopBeforeIndex = 1; // Stop before index 0, not including it
81+
for (var i = startIndex; i >= stopBeforeIndex; i--)
82+
{
83+
// Process elements from index 1 to array.Length - 1 (skipping index 0)
84+
}
85+
```
86+
87+
### Workaround 3: Use array slicing (C# 8.0+)
88+
``` cs
89+
// Process only the sub-array excluding the first element, then iterate normally
90+
var elementsToProcess = array[1..]; // Skip index 0
91+
for (var i = elementsToProcess.Length - 1; i >= 0; i--)
92+
{
93+
// Process elements (original indices 1 to array.Length - 1)
94+
DoSomething(elementsToProcess[i]);
95+
}
96+
```
97+
98+
### Workaround 4: Use LINQ when appropriate
99+
``` cs
100+
// For simple operations, LINQ can be clearer
101+
array.Skip(1).Reverse().ToList().ForEach(element => DoSomething(element));
102+
```
103+
104+
These workarounds make the intent clearer to both the analyzer and future maintainers of the code.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# PH2147: Avoid variables named exactly '_'
2+
3+
| Property | Value |
4+
|--|--|
5+
| Package | [Philips.CodeAnalysis.MaintainabilityAnalyzers](https://www.nuget.org/packages/Philips.CodeAnalysis.MaintainabilityAnalyzers) |
6+
| Diagnostic ID | PH2147 |
7+
| Category | [Naming](../Naming.md) |
8+
| Analyzer | [AvoidVariableNamedUnderscoreAnalyzer](https://github.com/philips-software/roslyn-analyzers/blob/main/Philips.CodeAnalysis.MaintainabilityAnalyzers/Naming/AvoidVariableNamedUnderscoreAnalyzer.cs)
9+
| CodeFix | No |
10+
| Severity | Error |
11+
| Enabled By Default | Yes |
12+
13+
## Introduction
14+
15+
This rule flags variables (local variables, foreach variables, for loop variables, using variables, and out parameters) that are named exactly `_` (single underscore).
16+
17+
## Reason
18+
19+
Variables named exactly `_` can be confused with C# discards. This can lead to unintended behavior where developers think they are using a discard but are actually creating a variable that captures the value.
20+
21+
## How to fix violations
22+
23+
Either use a proper discard (if you don't need the value) or use a more descriptive variable name (if you do need the value).
24+
25+
## Examples
26+
27+
### Incorrect
28+
29+
```csharp
30+
// Local variable - looks like discard but is actually a variable
31+
byte[] _ = ExtractData(reader);
32+
33+
// ForEach variable - confusing
34+
foreach (var _ in items)
35+
{
36+
// code
37+
}
38+
39+
// Out parameter - looks like discard
40+
if (int.TryParse(input, out int _))
41+
{
42+
// code
43+
}
44+
```
45+
46+
### Correct
47+
48+
```csharp
49+
// Use a proper discard if you don't need the value
50+
_ = ExtractData(reader);
51+
52+
// Or use a descriptive name if you do need the value
53+
byte[] data = ExtractData(reader);
54+
55+
// ForEach with discard
56+
foreach (var _ in items)
57+
{
58+
// Use discard syntax instead
59+
}
60+
61+
// Out parameter with discard
62+
if (int.TryParse(input, out _))
63+
{
64+
// code
65+
}
66+
67+
// Or with a descriptive name
68+
if (int.TryParse(input, out int result))
69+
{
70+
// code using result
71+
}
72+
```
73+
74+
## Configuration
75+
76+
This rule is enabled by default with Error severity.
77+
78+
## Suppression
79+
80+
```csharp
81+
[SuppressMessage("Philips.CodeAnalysis.MaintainabilityAnalyzers", "PH2147:Avoid variables named exactly '_'", Justification = "Reviewed.")]
82+
```

0 commit comments

Comments
 (0)