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 AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Generally speaking you want to follow the following pattern:
* Avoid exceptions at all costs. You want to religiously `null`-check everything because you must assume that code is most frequently in an invalid state during active development.
* When asserting against a diagnostic you must use the special `{|#<num>` and `|}` tags to indicate where in the source code the squiggly lines are shown. The `<num>` is to be replaced with a 0-indexed numeral (0, 1, 2, 3) and represents the index of the diagnostic that is being reported.
* When writing tests, give the test a descriptive name that captures the nuance of the scenario it's testing. Do not hesitate to use long names if it captures the intent better.
* Make sure there are no return statements inside the `RegisterCodeFix` callback - it means the user would see a preview of the same document. Do all precondition checks before this point.

## How to run

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# CHANGELOG
https://keepachangelog.com/en/1.0.0/

## [1.31.0] - 2026-01-24
- `LoggerMessageAttribute`: This analyzer suggests converting regular logging calls to the source-generated logging pattern.

## [1.30.0] - 2026-01-23
- `StringConcatenatedInLoop`: Now also catches interpolated strings
- `StringPlaceholdersInWrongOrder`: Retains existing whitespace when applying the code fix
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<Nullable>enable</Nullable>
<LangVersion>11.0</LangVersion>
<LangVersion>12.0</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AnalysisLevel>latest</AnalysisLevel>
<NoWarn>NU1902;NU1903;NU1904</NoWarn>
Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.CodeRefactoring.Testing" Version="1.1.2" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.8.0" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Microsoft.VSSDK.BuildTools" Version="17.9.3168" />
<PackageVersion Include="NUnit" Version="4.2.2" />
Expand Down
130 changes: 66 additions & 64 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ or add a reference yourself:

```xml
<ItemGroup>
<PackageReference Include="SharpSource" Version="1.30.0" PrivateAssets="All" />
<PackageReference Include="SharpSource" Version="1.31.0" PrivateAssets="All" />
</ItemGroup>
```

Expand All @@ -33,69 +33,71 @@ Interested in contributing? Take a look at [the guidelines](./CONTRIBUTING.md)!
Detailed explanations of each analyzer can be found in the documentation: https://github.com/Vannevelj/SharpSource/tree/master/docs


| Code | Name |
|---|---|
| SS001 | AsyncMethodWithVoidReturnType |
| SS002 | DateTimeNow |
| SS003 | DivideIntegerByInteger |
| SS004 | ElementaryMethodsOfTypeInCollectionNotOverridden |
| SS005 | EqualsAndGetHashcodeNotImplementedTogether |
| SS006 | ThrowNull |
| SS007 | FlagsEnumValuesAreNotPowersOfTwo |
| SS008 | GetHashCodeRefersToMutableMember |
| SS009 | LoopedRandomInstantiation |
| SS010 | NewGuid |
| SS011 | OnPropertyChangedWithoutNameofOperator |
| SS012 | RecursiveOperatorOverload |
| SS013 | RethrowExceptionWithoutLosingStacktrace |
| SS014 | StringDotFormatWithDifferentAmountOfArguments |
| SS015 | StringPlaceholdersInWrongOrder |
| SS017 | StructWithoutElementaryMethodsOverridden |
| SS018 | SwitchDoesNotHandleAllEnumOptions |
| SS019 | SwitchIsMissingDefaultLabel |
| SS020 | TestMethodWithoutPublicModifier |
| SS021 | TestMethodWithoutTestAttribute |
| SS022 | ExceptionThrownFromImplicitOperator |
| SS023 | ExceptionThrownFromPropertyGetter |
| SS024 | ExceptionThrownFromStaticConstructor |
| SS025 | ExceptionThrownFromFinallyBlock |
| SS026 | ExceptionThrownFromEqualityOperator |
| SS027 | ExceptionThrownFromDispose |
| SS028 | ExceptionThrownFromFinalizer |
| SS029 | ExceptionThrownFromGetHashCode |
| SS030 | ExceptionThrownFromEquals |
| SS032 | ThreadSleepInAsyncMethod |
| SS033 | AsyncOverloadsAvailable |
| SS034 | AccessingTaskResultWithoutAwait |
| SS035 | SynchronousTaskWait |
| SS036 | ExplicitEnumValues |
| SS037 | HttpClientInstantiatedDirectly |
| SS038 | HttpContextStoredInField |
| SS039 | EnumWithoutDefaultValue |
| SS040 | UnusedResultOnImmutableObject |
| SS041 | UnnecessaryEnumerableMaterialization |
| SS042 | InstanceFieldWithThreadStatic |
| SS043 | MultipleFromBodyParameters |
| SS044 | AttributeMustSpecifyAttributeUsage |
| SS045 | StaticInitializerAccessedBeforeInitialization |
| SS046 | UnboundedStackalloc |
| SS047 | LinqTraversalBeforeFilter |
| SS048 | LockingOnDiscouragedObject |
| SS049 | ComparingStringsWithoutStringComparison |
| SS050 | ParameterAssignedInConstructor |
| SS051 | LockingOnMutableReference |
| SS052 | ThreadStaticWithInitializer |
| SS053 | PointlessCollectionToString |
| SS054 | NewtonsoftMixedWithSystemTextJson |
| SS055 | MultipleOrderByCalls |
| SS056 | FormReadSynchronously |
| SS057 | CollectionManipulatedDuringTraversal |
| SS058 | StringConcatenatedInLoop |
| SS059 | DisposeAsyncDisposable |
| SS060 | ConcurrentDictionaryEmptyCheck |
| SS061 | ImmutableCollectionCreatedIncorrectly |
| SS062 | ActivityWasNotStopped |
| SS063 | ValueTaskAwaitedMultipleTimes |
| Code | Name | Description |
|--------|------|-------------|
| SS001 | AsyncMethodWithVoidReturnType | Async methods should return `Task` instead of `void` to allow proper exception handling and awaiting. |
| SS002 | DateTimeNow | Use `DateTime.UtcNow` instead of `DateTime.Now` to avoid timezone-related issues. |
| SS003 | DivideIntegerByInteger | Dividing integers results in integer division; cast to floating-point if a decimal result is expected. |
| SS004 | ElementaryMethodsOfTypeInCollectionNotOverridden | Types used as collection keys should override `Equals` and `GetHashCode`. |
| SS005 | EqualsAndGetHashcodeNotImplementedTogether | `Equals` and `GetHashCode` should always be overridden together. |
| SS006 | ThrowNull | Throwing `null` will result in a `NullReferenceException` at runtime. |
| SS007 | FlagsEnumValuesAreNotPowersOfTwo | Flags enum values should be powers of two to allow proper bitwise operations. |
| SS008 | GetHashCodeRefersToMutableMember | `GetHashCode` should not reference mutable members as this breaks hash-based collections. |
| SS009 | LoopedRandomInstantiation | Creating `Random` instances in a loop can produce identical sequences; reuse a single instance. |
| SS010 | NewGuid | Use `Guid.NewGuid()` instead of `new Guid()` to generate a unique identifier. |
| SS011 | OnPropertyChangedWithoutNameofOperator | Use `nameof()` instead of hardcoded property name strings in `OnPropertyChanged`. |
| SS012 | RecursiveOperatorOverload | Operator overloads calling themselves will cause infinite recursion. |
| SS013 | RethrowExceptionWithoutLosingStacktrace | Use `throw;` instead of `throw ex;` to preserve the original stack trace. |
| SS014 | StringDotFormatWithDifferentAmountOfArguments | The number of format placeholders should match the number of arguments. |
| SS015 | StringPlaceholdersInWrongOrder | Format placeholders should be in sequential order starting from `{0}`. |
| SS017 | StructWithoutElementaryMethodsOverridden | Structs should override `Equals`, `GetHashCode`, and implement `IEquatable<T>` for performance. |
| SS018 | SwitchDoesNotHandleAllEnumOptions | Switch statements on enums should handle all possible values. |
| SS019 | SwitchIsMissingDefaultLabel | Switch statements should have a default case to handle unexpected values. |
| SS020 | TestMethodWithoutPublicModifier | Test methods must be public to be discovered by test runners. |
| SS021 | TestMethodWithoutTestAttribute | Methods that look like tests should have a test attribute to be executed. |
| SS022 | ExceptionThrownFromImplicitOperator | Implicit operators should not throw exceptions as they are called invisibly. |
| SS023 | ExceptionThrownFromPropertyGetter | Property getters should not throw exceptions; consider using a method instead. |
| SS024 | ExceptionThrownFromStaticConstructor | Exceptions in static constructors cause `TypeInitializationException` and make the type unusable. |
| SS025 | ExceptionThrownFromFinallyBlock | Exceptions in finally blocks can mask original exceptions from try blocks. |
| SS026 | ExceptionThrownFromEqualityOperator | Equality operators should not throw exceptions; return `false` for invalid comparisons. |
| SS027 | ExceptionThrownFromDispose | `Dispose` methods should not throw exceptions as they may be called during exception unwinding. |
| SS028 | ExceptionThrownFromFinalizer | Finalizers should not throw exceptions as this will terminate the process. |
| SS029 | ExceptionThrownFromGetHashCode | `GetHashCode` should not throw exceptions; return a consistent value instead. |
| SS030 | ExceptionThrownFromEquals | `Equals` should not throw exceptions; return `false` for invalid comparisons. |
| SS032 | ThreadSleepInAsyncMethod | Use `await Task.Delay()` instead of `Thread.Sleep()` in async methods to avoid blocking threads. |
| SS033 | AsyncOverloadsAvailable | Use async overloads when available to avoid blocking the calling thread. |
| SS034 | AccessingTaskResultWithoutAwait | Accessing `Task.Result` without awaiting can cause deadlocks; use `await` instead. |
| SS035 | SynchronousTaskWait | Using `.Wait()` or `.Result` on tasks can cause deadlocks; use `await` instead. |
| SS036 | ExplicitEnumValues | Enum members should have explicit values when the values are persisted or serialized. |
| SS037 | HttpClientInstantiatedDirectly | Use `IHttpClientFactory` instead of creating `HttpClient` directly to avoid socket exhaustion. |
| SS038 | HttpContextStoredInField | `HttpContext` should not be stored in fields as it's request-scoped and may be invalid later. |
| SS039 | EnumWithoutDefaultValue | Enums should have a member with value `0` to represent the default state. |
| SS040 | UnusedResultOnImmutableObject | Methods on immutable types return new instances; the result should not be discarded. |
| SS041 | UnnecessaryEnumerableMaterialization | Avoid materializing enumerables (e.g., `ToList()`) when the result is immediately enumerated. |
| SS042 | InstanceFieldWithThreadStatic | `[ThreadStatic]` only works on static fields; it has no effect on instance fields. |
| SS043 | MultipleFromBodyParameters | Web API actions can only have one `[FromBody]` parameter. |
| SS044 | AttributeMustSpecifyAttributeUsage | Custom attributes should specify `[AttributeUsage]` to define valid targets. |
| SS045 | StaticInitializerAccessedBeforeInitialization | Static field initializers may access fields before they are initialized. |
| SS046 | UnboundedStackalloc | `stackalloc` without a size limit can cause stack overflow; consider using a maximum size. |
| SS047 | LinqTraversalBeforeFilter | Apply `Where` filters before `Select` projections to avoid unnecessary work. |
| SS048 | LockingOnDiscouragedObject | Avoid locking on `this`, `typeof()`, or strings as these can cause deadlocks. |
| SS049 | ComparingStringsWithoutStringComparison | String comparisons should specify a `StringComparison` to ensure correct behavior. |
| SS050 | ParameterAssignedInConstructor | Assigning to a parameter instead of a field in a constructor is likely a mistake. |
| SS051 | LockingOnMutableReference | Locking on a field that can be reassigned may cause race conditions. |
| SS052 | ThreadStaticWithInitializer | `[ThreadStatic]` field initializers only run once; use lazy initialization instead. |
| SS053 | PointlessCollectionToString | Calling `ToString()` on collections returns the type name, not the contents. |
| SS054 | NewtonsoftMixedWithSystemTextJson | Mixing Newtonsoft.Json and System.Text.Json attributes causes serialization issues. |
| SS055 | MultipleOrderByCalls | Multiple `OrderBy` calls override each other; use `ThenBy` for secondary sorting. |
| SS056 | FormReadSynchronously | Reading form data synchronously blocks threads; use async methods instead. |
| SS057 | CollectionManipulatedDuringTraversal | Modifying a collection while iterating over it causes `InvalidOperationException`. |
| SS058 | StringConcatenatedInLoop | Use `StringBuilder` instead of string concatenation in loops for better performance. |
| SS059 | DisposeAsyncDisposable | Types implementing `IAsyncDisposable` should be disposed with `await using`. |
| SS060 | ConcurrentDictionaryEmptyCheck | Use `IsEmpty` instead of `Count == 0` on `ConcurrentDictionary` for thread safety. |
| SS061 | ImmutableCollectionCreatedIncorrectly | Use builder methods or `Create()` instead of constructors for immutable collections. |
| SS062 | ActivityWasNotStopped | `Activity` instances must be stopped to ensure telemetry data is recorded. |
| SS063 | ValueTaskAwaitedMultipleTimes | `ValueTask` can only be awaited once; store the result or convert to `Task` if needed. |
| SS064 | UnnecessaryToStringOnSpan | Avoid calling `ToString()` on spans when an overload accepting spans directly is available. |
| SS065 | LoggerMessageAttribute | Use the `[LoggerMessage]` attribute for high-performance logging instead of extension methods. |

## Configuration
Is a particular rule not to your liking? There are many ways to adjust their severity and even disable them altogether. For an overview of some of the options, check out [this document](https://docs.microsoft.com/en-gb/dotnet/fundamentals/code-analysis/suppress-warnings).
Loading
Loading