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
6 changes: 3 additions & 3 deletions docs/Rules/EPC11.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class MyClass
public override bool Equals(object obj)
{
// Suspicious: only using static members or not using 'this' instance
return SomeStaticProperty == 42;
return SomeStaticProperty == 42; // ❌ EPC11
}
}
```
Expand All @@ -27,7 +27,7 @@ public class Person
public override bool Equals(object obj)
{
// Suspicious: parameter 'obj' is never used
return this.Name == "test";
return this.Name == "test"; // ❌ EPC11
}
}
```
Expand All @@ -49,7 +49,7 @@ public class Person
{
if (obj is Person other)
{
return this.Name == other.Name;
return this.Name == other.Name; // ✅ Correct
}
return false;
}
Expand Down
6 changes: 3 additions & 3 deletions docs/Rules/EPC12.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ try
catch (Exception ex)
{
// Only using ex.Message - this triggers the warning
Console.WriteLine(ex.Message);
Console.WriteLine(ex.Message); // ❌ EPC12
}
```

Expand All @@ -34,8 +34,8 @@ try
catch (Exception ex)
{
// Log the full exception object
Console.WriteLine(ex.ToString());
Console.WriteLine(ex.ToString()); // ✅ Correct
// Or access the exception object directly
LogException(ex);
LogException(ex); // ✅ Correct
}
```
12 changes: 6 additions & 6 deletions docs/Rules/EPC13.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ public class Example
public void ProcessData()
{
// Return value is ignored - this triggers the warning
GetImportantValue();
GetImportantValue(); // ❌ EPC13

// String methods return new strings but result is ignored
"hello".ToUpper();
"hello".ToUpper(); // ❌ EPC13

// Collection methods that return new collections
list.Where(x => x > 0);
list.Where(x => x > 0); // ❌ EPC13
}

public string GetImportantValue()
Expand All @@ -40,14 +40,14 @@ public class Example
public void ProcessData()
{
// Store the result in a variable
var importantValue = GetImportantValue();
var importantValue = GetImportantValue(); // ✅ Correct

// Use the result directly
var upperText = "hello".ToUpper();
var upperText = "hello".ToUpper(); // ✅ Correct
Console.WriteLine(upperText);

// Chain operations or store result
var filteredList = list.Where(x => x > 0).ToList();
var filteredList = list.Where(x => x > 0).ToList(); // ✅ Correct
}

public string GetImportantValue()
Expand Down
8 changes: 4 additions & 4 deletions docs/Rules/EPC15.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ The analyzer warns when `ConfigureAwait(false)` should be used but is missing. T
public async Task ProcessAsync()
{
// Missing ConfigureAwait(false) - this triggers the warning
await SomeAsyncMethod();
await SomeAsyncMethod(); // ❌ EPC15

// Also missing ConfigureAwait(false)
var result = await GetDataAsync();
var result = await GetDataAsync(); // ❌ EPC15
}
```

Expand All @@ -27,9 +27,9 @@ Add `ConfigureAwait(false)` to all await expressions:
public async Task ProcessAsync()
{
// Add ConfigureAwait(false) to avoid capturing sync context
await SomeAsyncMethod().ConfigureAwait(false);
await SomeAsyncMethod().ConfigureAwait(false); // ✅ Correct

var result = await GetDataAsync().ConfigureAwait(false);
var result = await GetDataAsync().ConfigureAwait(false); // ✅ Correct
}
```

Expand Down
10 changes: 5 additions & 5 deletions docs/Rules/EPC16.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public async Task ProcessAsync()
SomeService service = GetService(); // might return null

// Dangerous: if service is null, this returns null, and awaiting null throws NRE
await service?.ProcessAsync();
await service?.ProcessAsync(); // ❌ EPC16
}
```

Expand All @@ -24,7 +24,7 @@ public async Task<string> GetDataAsync()
var client = GetHttpClient(); // might return null

// This will throw NRE if client is null
return await client?.GetStringAsync("http://example.com");
return await client?.GetStringAsync("http://example.com"); // ❌ EPC16
}
```

Expand All @@ -40,11 +40,11 @@ public async Task ProcessAsync()
// Option 1: Check for null first
if (service != null)
{
await service.ProcessAsync();
await service.ProcessAsync(); // ✅ Correct
}

// Option 2: Use null-coalescing with Task.CompletedTask
await (service?.ProcessAsync() ?? Task.CompletedTask);
await (service?.ProcessAsync() ?? Task.CompletedTask); // ✅ Correct
}
```

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

return await client.GetStringAsync("http://example.com");
return await client.GetStringAsync("http://example.com"); // ✅ Correct
}
```
6 changes: 3 additions & 3 deletions docs/Rules/EPC17.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ The analyzer warns against using async void delegates. Unlike async void methods
public void SetupHandlers()
{
// Dangerous: async void delegate
SomeEvent += async () =>
SomeEvent += async () => // ❌ EPC17
{
await SomeAsyncMethod();
// If this throws, it will crash the app
};

// Another dangerous pattern
Task.Run(async () =>
Task.Run(async () => // ❌ EPC17
{
await ProcessAsync();
// Exceptions here are unhandled
Expand All @@ -31,7 +31,7 @@ public void SetupHandlers()
public void RegisterCallback()
{
// Async void delegate in callback
RegisterCallback(async () =>
RegisterCallback(async () => // ❌ EPC17
{
await DoWorkAsync();
});
Expand Down
12 changes: 6 additions & 6 deletions docs/Rules/EPC18.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public async Task<string> GetDataAsync()
public void ProcessData()
{
// Missing await - Task<string> converted to string
string result = GetDataAsync(); // This will be "System.Threading.Tasks.Task`1[System.String]"
string result = GetDataAsync(); // ❌ EPC18 - This will be "System.Threading.Tasks.Task`1[System.String]"

// In string interpolation
Console.WriteLine($"Result: {GetDataAsync()}"); // Prints task type, not result
Console.WriteLine($"Result: {GetDataAsync()}"); // ❌ EPC18 - Prints task type, not result

// In concatenation
string message = "Data: " + GetDataAsync(); // Concatenates with task type
string message = "Data: " + GetDataAsync(); // ❌ EPC18 - Concatenates with task type
}
```

Expand All @@ -40,12 +40,12 @@ public async Task<string> GetDataAsync()
public async Task ProcessData()
{
// Properly await the task
string result = await GetDataAsync(); // Now gets "Hello World"
string result = await GetDataAsync(); // ✅ Correct - Now gets "Hello World"

// In string interpolation
Console.WriteLine($"Result: {await GetDataAsync()}"); // Prints actual result
Console.WriteLine($"Result: {await GetDataAsync()}"); // ✅ Correct - Prints actual result

// In concatenation
string message = "Data: " + await GetDataAsync(); // Concatenates with actual result
string message = "Data: " + await GetDataAsync(); // ✅ Correct - Concatenates with actual result
}
```
14 changes: 7 additions & 7 deletions docs/Rules/EPC19.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class MyService
public void StartOperation(CancellationToken cancellationToken)
{
// Registration is not stored - potential memory leak
cancellationToken.Register(() =>
cancellationToken.Register(() => // ❌ EPC19
{
Console.WriteLine("Operation cancelled");
});
Expand All @@ -26,7 +26,7 @@ public class MyService
public async Task ProcessAsync(CancellationToken token)
{
// Registration result is ignored
token.Register(OnCancellation);
token.Register(OnCancellation); // ❌ EPC19

await DoWorkAsync();
}
Expand All @@ -49,7 +49,7 @@ public class MyService : IDisposable
public void StartOperation(CancellationToken cancellationToken)
{
// Store the registration
_registration = cancellationToken.Register(() =>
_registration = cancellationToken.Register(() => // ✅ Correct
{
Console.WriteLine("Operation cancelled");
});
Expand All @@ -58,7 +58,7 @@ public class MyService : IDisposable
public void Dispose()
{
// Dispose the registration to prevent memory leaks
_registration.Dispose();
_registration.Dispose(); // ✅ Correct
}
}
```
Expand All @@ -67,21 +67,21 @@ public class MyService : IDisposable
public async Task ProcessAsync(CancellationToken token)
{
// Store registration and dispose in finally block
var registration = token.Register(OnCancellation);
var registration = token.Register(OnCancellation); // ✅ Correct
try
{
await DoWorkAsync();
}
finally
{
registration.Dispose();
registration.Dispose(); // ✅ Correct
}
}

// Or use using statement
public async Task ProcessAsync(CancellationToken token)
{
using var registration = token.Register(OnCancellation);
using var registration = token.Register(OnCancellation); // ✅ Correct
await DoWorkAsync();
// registration automatically disposed here
}
Expand Down
8 changes: 4 additions & 4 deletions docs/Rules/EPC20.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ public void Example()
var person = new Person { Name = "John", Age = 30 };

// Using default ToString() - outputs "Person" instead of useful info
Console.WriteLine(person.ToString());
Console.WriteLine(person.ToString()); // ❌ EPC20

// Implicit ToString() call
string personString = person;
string personString = person; // ❌ EPC20

// In string interpolation
Console.WriteLine($"Person: {person}");
Console.WriteLine($"Person: {person}"); // ❌ EPC20
}
```

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

// Custom ToString() implementation
public override string ToString()
public override string ToString() // ✅ Correct
{
return $"Person(Name: {Name}, Age: {Age})";
}
Expand Down
8 changes: 4 additions & 4 deletions docs/Rules/EPC23.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public void Example()
var hashSet = new HashSet<string> { "apple", "banana", "cherry" };

// Inefficient: uses Enumerable.Contains (O(n) linear search)
bool found = hashSet.Contains("apple", StringComparer.OrdinalIgnoreCase);
bool found = hashSet.Contains("apple", StringComparer.OrdinalIgnoreCase); // ❌ EPC23

// Also inefficient when using Enumerable.Contains explicitly
bool found2 = Enumerable.Contains(hashSet, "banana");
bool found2 = Enumerable.Contains(hashSet, "banana"); // ❌ EPC23
}
```

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

// Efficient: uses HashSet.Contains (O(1) hash lookup)
bool found = hashSet.Contains("apple");
bool found = hashSet.Contains("apple"); // ✅ Correct

// If you need custom comparison, create HashSet with comparer
var caseInsensitiveSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"apple", "banana", "cherry"
};
bool found2 = caseInsensitiveSet.Contains("APPLE"); // O(1) with custom comparer
bool found2 = caseInsensitiveSet.Contains("APPLE"); // ✅ Correct - O(1) with custom comparer
}
```

Expand Down
10 changes: 5 additions & 5 deletions docs/Rules/EPC24.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ public struct Point
public void Example()
{
// Using struct with default Equals/GetHashCode as dictionary key
var pointData = new Dictionary<Point, string>();
var pointData = new Dictionary<Point, string>(); // ❌ EPC24

var point = new Point { X = 1, Y = 2 };
pointData[point] = "First point"; // Performance issue!

// HashSet also affected
var pointSet = new HashSet<Point>();
var pointSet = new HashSet<Point>(); // ❌ EPC24
pointSet.Add(point); // Performance issue!
}
```
Expand All @@ -41,18 +41,18 @@ public struct Point : IEquatable<Point>
public int Y { get; set; }

// Custom Equals implementation
public bool Equals(Point other)
public bool Equals(Point other) // ✅ Correct
{
return X == other.X && Y == other.Y;
}

public override bool Equals(object obj)
public override bool Equals(object obj) // ✅ Correct
{
return obj is Point other && Equals(other);
}

// Custom GetHashCode implementation
public override int GetHashCode()
public override int GetHashCode() // ✅ Correct
{
return HashCode.Combine(X, Y);
}
Expand Down
8 changes: 4 additions & 4 deletions docs/Rules/EPC25.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ public void Example()
var struct2 = new MyStruct { Value1 = 1, Value2 = 2 };

// Using default ValueType.Equals - slow!
bool areEqual = struct1.Equals(struct2);
bool areEqual = struct1.Equals(struct2); // ❌ EPC25

// Using default ValueType.GetHashCode - slow!
int hash = struct1.GetHashCode();
int hash = struct1.GetHashCode(); // ❌ EPC25

// In collections this causes performance issues
var dictionary = new Dictionary<MyStruct, string>();
var dictionary = new Dictionary<MyStruct, string>(); // ❌ EPC25
dictionary[struct1] = "value"; // Triggers slow hash operations
}
```
Expand All @@ -43,7 +43,7 @@ public struct MyStruct : IEquatable<MyStruct>
public int Value1 { get; set; }
public int Value2 { get; set; }

public bool Equals(MyStruct other)
public bool Equals(MyStruct other) // ✅ Correct
{
return Value1 == other.Value1 && Value2 == other.Value2;
}
Expand Down
Loading