Skip to content

Commit bcb8439

Browse files
Annotate rule docs with violation markers and fix EPC20 category (#310)
Added explicit ❌ and ✅ markers to code examples in rule documentation files to clarify violations and correct usage. Also changed the category for EPC20 in DiagnosticDescriptors.cs from AsyncCategory to CodeSmellCategory for accuracy.
1 parent 5aad158 commit bcb8439

File tree

27 files changed

+147
-152
lines changed

27 files changed

+147
-152
lines changed

docs/Rules/EPC11.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class MyClass
1414
public override bool Equals(object obj)
1515
{
1616
// Suspicious: only using static members or not using 'this' instance
17-
return SomeStaticProperty == 42;
17+
return SomeStaticProperty == 42; // ❌ EPC11
1818
}
1919
}
2020
```
@@ -27,7 +27,7 @@ public class Person
2727
public override bool Equals(object obj)
2828
{
2929
// Suspicious: parameter 'obj' is never used
30-
return this.Name == "test";
30+
return this.Name == "test"; // ❌ EPC11
3131
}
3232
}
3333
```
@@ -49,7 +49,7 @@ public class Person
4949
{
5050
if (obj is Person other)
5151
{
52-
return this.Name == other.Name;
52+
return this.Name == other.Name; // ✅ Correct
5353
}
5454
return false;
5555
}

docs/Rules/EPC12.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ try
1717
catch (Exception ex)
1818
{
1919
// Only using ex.Message - this triggers the warning
20-
Console.WriteLine(ex.Message);
20+
Console.WriteLine(ex.Message); // ❌ EPC12
2121
}
2222
```
2323

@@ -34,8 +34,8 @@ try
3434
catch (Exception ex)
3535
{
3636
// Log the full exception object
37-
Console.WriteLine(ex.ToString());
37+
Console.WriteLine(ex.ToString()); // ✅ Correct
3838
// Or access the exception object directly
39-
LogException(ex);
39+
LogException(ex); // ✅ Correct
4040
}
4141
```

docs/Rules/EPC13.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ public class Example
1414
public void ProcessData()
1515
{
1616
// Return value is ignored - this triggers the warning
17-
GetImportantValue();
17+
GetImportantValue(); // ❌ EPC13
1818
1919
// String methods return new strings but result is ignored
20-
"hello".ToUpper();
20+
"hello".ToUpper(); // ❌ EPC13
2121
2222
// Collection methods that return new collections
23-
list.Where(x => x > 0);
23+
list.Where(x => x > 0); // ❌ EPC13
2424
}
2525

2626
public string GetImportantValue()
@@ -40,14 +40,14 @@ public class Example
4040
public void ProcessData()
4141
{
4242
// Store the result in a variable
43-
var importantValue = GetImportantValue();
43+
var importantValue = GetImportantValue(); // ✅ Correct
4444
4545
// Use the result directly
46-
var upperText = "hello".ToUpper();
46+
var upperText = "hello".ToUpper(); // ✅ Correct
4747
Console.WriteLine(upperText);
4848

4949
// Chain operations or store result
50-
var filteredList = list.Where(x => x > 0).ToList();
50+
var filteredList = list.Where(x => x > 0).ToList(); // ✅ Correct
5151
}
5252

5353
public string GetImportantValue()

docs/Rules/EPC15.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ The analyzer warns when `ConfigureAwait(false)` should be used but is missing. T
1212
public async Task ProcessAsync()
1313
{
1414
// Missing ConfigureAwait(false) - this triggers the warning
15-
await SomeAsyncMethod();
15+
await SomeAsyncMethod(); // ❌ EPC15
1616
1717
// Also missing ConfigureAwait(false)
18-
var result = await GetDataAsync();
18+
var result = await GetDataAsync(); // ❌ EPC15
1919
}
2020
```
2121

@@ -27,9 +27,9 @@ Add `ConfigureAwait(false)` to all await expressions:
2727
public async Task ProcessAsync()
2828
{
2929
// Add ConfigureAwait(false) to avoid capturing sync context
30-
await SomeAsyncMethod().ConfigureAwait(false);
30+
await SomeAsyncMethod().ConfigureAwait(false); // ✅ Correct
3131
32-
var result = await GetDataAsync().ConfigureAwait(false);
32+
var result = await GetDataAsync().ConfigureAwait(false); // ✅ Correct
3333
}
3434
```
3535

docs/Rules/EPC16.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public async Task ProcessAsync()
1414
SomeService service = GetService(); // might return null
1515
1616
// Dangerous: if service is null, this returns null, and awaiting null throws NRE
17-
await service?.ProcessAsync();
17+
await service?.ProcessAsync(); // ❌ EPC16
1818
}
1919
```
2020

@@ -24,7 +24,7 @@ public async Task<string> GetDataAsync()
2424
var client = GetHttpClient(); // might return null
2525
2626
// This will throw NRE if client is null
27-
return await client?.GetStringAsync("http://example.com");
27+
return await client?.GetStringAsync("http://example.com"); // ❌ EPC16
2828
}
2929
```
3030

@@ -40,11 +40,11 @@ public async Task ProcessAsync()
4040
// Option 1: Check for null first
4141
if (service != null)
4242
{
43-
await service.ProcessAsync();
43+
await service.ProcessAsync(); // ✅ Correct
4444
}
4545

4646
// Option 2: Use null-coalescing with Task.CompletedTask
47-
await (service?.ProcessAsync() ?? Task.CompletedTask);
47+
await (service?.ProcessAsync() ?? Task.CompletedTask); // ✅ Correct
4848
}
4949
```
5050

@@ -59,6 +59,6 @@ public async Task<string> GetDataAsync()
5959
return null; // or throw, or return default value
6060
}
6161

62-
return await client.GetStringAsync("http://example.com");
62+
return await client.GetStringAsync("http://example.com"); // ✅ Correct
6363
}
6464
```

docs/Rules/EPC17.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ The analyzer warns against using async void delegates. Unlike async void methods
1212
public void SetupHandlers()
1313
{
1414
// Dangerous: async void delegate
15-
SomeEvent += async () =>
15+
SomeEvent += async () => // ❌ EPC17
1616
{
1717
await SomeAsyncMethod();
1818
// If this throws, it will crash the app
1919
};
2020

2121
// Another dangerous pattern
22-
Task.Run(async () =>
22+
Task.Run(async () => // ❌ EPC17
2323
{
2424
await ProcessAsync();
2525
// Exceptions here are unhandled
@@ -31,7 +31,7 @@ public void SetupHandlers()
3131
public void RegisterCallback()
3232
{
3333
// Async void delegate in callback
34-
RegisterCallback(async () =>
34+
RegisterCallback(async () => // ❌ EPC17
3535
{
3636
await DoWorkAsync();
3737
});

docs/Rules/EPC18.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ public async Task<string> GetDataAsync()
1717
public void ProcessData()
1818
{
1919
// Missing await - Task<string> converted to string
20-
string result = GetDataAsync(); // This will be "System.Threading.Tasks.Task`1[System.String]"
20+
string result = GetDataAsync(); // ❌ EPC18 - This will be "System.Threading.Tasks.Task`1[System.String]"
2121
2222
// In string interpolation
23-
Console.WriteLine($"Result: {GetDataAsync()}"); // Prints task type, not result
23+
Console.WriteLine($"Result: {GetDataAsync()}"); // ❌ EPC18 - Prints task type, not result
2424
2525
// In concatenation
26-
string message = "Data: " + GetDataAsync(); // Concatenates with task type
26+
string message = "Data: " + GetDataAsync(); // ❌ EPC18 - Concatenates with task type
2727
}
2828
```
2929

@@ -40,12 +40,12 @@ public async Task<string> GetDataAsync()
4040
public async Task ProcessData()
4141
{
4242
// Properly await the task
43-
string result = await GetDataAsync(); // Now gets "Hello World"
43+
string result = await GetDataAsync(); // ✅ Correct - Now gets "Hello World"
4444
4545
// In string interpolation
46-
Console.WriteLine($"Result: {await GetDataAsync()}"); // Prints actual result
46+
Console.WriteLine($"Result: {await GetDataAsync()}"); // ✅ Correct - Prints actual result
4747
4848
// In concatenation
49-
string message = "Data: " + await GetDataAsync(); // Concatenates with actual result
49+
string message = "Data: " + await GetDataAsync(); // ✅ Correct - Concatenates with actual result
5050
}
5151
```

docs/Rules/EPC19.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class MyService
1414
public void StartOperation(CancellationToken cancellationToken)
1515
{
1616
// Registration is not stored - potential memory leak
17-
cancellationToken.Register(() =>
17+
cancellationToken.Register(() => // ❌ EPC19
1818
{
1919
Console.WriteLine("Operation cancelled");
2020
});
@@ -26,7 +26,7 @@ public class MyService
2626
public async Task ProcessAsync(CancellationToken token)
2727
{
2828
// Registration result is ignored
29-
token.Register(OnCancellation);
29+
token.Register(OnCancellation); // ❌ EPC19
3030
3131
await DoWorkAsync();
3232
}
@@ -49,7 +49,7 @@ public class MyService : IDisposable
4949
public void StartOperation(CancellationToken cancellationToken)
5050
{
5151
// Store the registration
52-
_registration = cancellationToken.Register(() =>
52+
_registration = cancellationToken.Register(() => // ✅ Correct
5353
{
5454
Console.WriteLine("Operation cancelled");
5555
});
@@ -58,7 +58,7 @@ public class MyService : IDisposable
5858
public void Dispose()
5959
{
6060
// Dispose the registration to prevent memory leaks
61-
_registration.Dispose();
61+
_registration.Dispose(); // ✅ Correct
6262
}
6363
}
6464
```
@@ -67,21 +67,21 @@ public class MyService : IDisposable
6767
public async Task ProcessAsync(CancellationToken token)
6868
{
6969
// Store registration and dispose in finally block
70-
var registration = token.Register(OnCancellation);
70+
var registration = token.Register(OnCancellation); // ✅ Correct
7171
try
7272
{
7373
await DoWorkAsync();
7474
}
7575
finally
7676
{
77-
registration.Dispose();
77+
registration.Dispose(); // ✅ Correct
7878
}
7979
}
8080

8181
// Or use using statement
8282
public async Task ProcessAsync(CancellationToken token)
8383
{
84-
using var registration = token.Register(OnCancellation);
84+
using var registration = token.Register(OnCancellation); // ✅ Correct
8585
await DoWorkAsync();
8686
// registration automatically disposed here
8787
}

docs/Rules/EPC20.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ public void Example()
2121
var person = new Person { Name = "John", Age = 30 };
2222

2323
// Using default ToString() - outputs "Person" instead of useful info
24-
Console.WriteLine(person.ToString());
24+
Console.WriteLine(person.ToString()); // ❌ EPC20
2525
2626
// Implicit ToString() call
27-
string personString = person;
27+
string personString = person; // ❌ EPC20
2828
2929
// In string interpolation
30-
Console.WriteLine($"Person: {person}");
30+
Console.WriteLine($"Person: {person}"); // ❌ EPC20
3131
}
3232
```
3333

@@ -42,7 +42,7 @@ public class Person
4242
public int Age { get; set; }
4343

4444
// Custom ToString() implementation
45-
public override string ToString()
45+
public override string ToString() // ✅ Correct
4646
{
4747
return $"Person(Name: {Name}, Age: {Age})";
4848
}

docs/Rules/EPC23.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ public void Example()
1616
var hashSet = new HashSet<string> { "apple", "banana", "cherry" };
1717

1818
// Inefficient: uses Enumerable.Contains (O(n) linear search)
19-
bool found = hashSet.Contains("apple", StringComparer.OrdinalIgnoreCase);
19+
bool found = hashSet.Contains("apple", StringComparer.OrdinalIgnoreCase); // ❌ EPC23
2020
2121
// Also inefficient when using Enumerable.Contains explicitly
22-
bool found2 = Enumerable.Contains(hashSet, "banana");
22+
bool found2 = Enumerable.Contains(hashSet, "banana"); // ❌ EPC23
2323
}
2424
```
2525

@@ -33,14 +33,14 @@ public void Example()
3333
var hashSet = new HashSet<string> { "apple", "banana", "cherry" };
3434

3535
// Efficient: uses HashSet.Contains (O(1) hash lookup)
36-
bool found = hashSet.Contains("apple");
36+
bool found = hashSet.Contains("apple"); // ✅ Correct
3737
3838
// If you need custom comparison, create HashSet with comparer
3939
var caseInsensitiveSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
4040
{
4141
"apple", "banana", "cherry"
4242
};
43-
bool found2 = caseInsensitiveSet.Contains("APPLE"); // O(1) with custom comparer
43+
bool found2 = caseInsensitiveSet.Contains("APPLE"); // ✅ Correct - O(1) with custom comparer
4444
}
4545
```
4646

0 commit comments

Comments
 (0)