WoofWare.FSharpAnalyzers
0.1.3
See the version list below for details.
dotnet add package WoofWare.FSharpAnalyzers --version 0.1.3
NuGet\Install-Package WoofWare.FSharpAnalyzers -Version 0.1.3
<PackageReference Include="WoofWare.FSharpAnalyzers" Version="0.1.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="WoofWare.FSharpAnalyzers" Version="0.1.3" />
<PackageReference Include="WoofWare.FSharpAnalyzers"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add WoofWare.FSharpAnalyzers --version 0.1.3
#r "nuget: WoofWare.FSharpAnalyzers, 0.1.3"
#:package WoofWare.FSharpAnalyzers@0.1.3
#addin nuget:?package=WoofWare.FSharpAnalyzers&version=0.1.3
#tool nuget:?package=WoofWare.FSharpAnalyzers&version=0.1.3
WoofWare.FSharpAnalyzers
A set of F# source analyzers, using the Ionide analyzer SDK.
They are modelled on the G-Research analyzers, but are much more opinionated. They're intended for my personal use.
Analyzers
BlockingAnalyzer
Bans the use of blocking calls like Async.RunSynchronously.
You will have to have a blocking call in your main method; use the magic suppression string ANALYZER: synchronous blocking call allowed
(optionally with a rationale appended) on the preceding line to suppress the analyzer on that line.
Rationale
Prevent sync-over-async.
ReferenceEqualsAnalyzer
Bans the use of Object.ReferenceEquals.
Use the magic suppression string ANALYZER: ReferenceEquals allowed
(optionally with a rationale appended) on the preceding line to suppress the analyzer on that line.
Rationale
Object.ReferenceEquals has two significant problems:
It silently does the wrong thing on value types. When you pass value types to
Object.ReferenceEquals, they get boxed, and the function compares the boxed instances rather than the original values. This meansObject.ReferenceEquals(42, 42)will always returnfalse, which is rarely what you want.It lacks type safety. The function accepts any two objects, making it too easy to accidentally compare objects of completely different types (e.g.,
Object.ReferenceEquals("hello", 42)), which will always returnfalsebut compiles without warning.
Instead, use a type-safe wrapper that enforces reference type constraints and type consistency:
let referenceEquals<'a when 'a : not struct> (x : 'a) (y : 'a) : bool =
obj.ReferenceEquals(x, y)
This prevents both issues: the not struct constraint prevents value types from being passed, and the type parameter 'a ensures both arguments are the same type.
TaskCompletionSourceAnalyzer
Requires TaskCompletionSource<T> to be created with TaskCreationOptions.RunContinuationsAsynchronously.
Use the magic suppression string ANALYZER: RunContinuationsAsynchronously
(optionally with a rationale appended) on the preceding line to suppress the analyzer on that line.
Rationale
By default, when you call SetResult, SetException, or SetCanceled on a TaskCompletionSource<T>, any continuations attached to the resulting task will run synchronously on the thread that completes the task. This can lead to serious problems:
Deadlocks: If the continuation tries to acquire a lock or synchronization context that the calling thread holds, you get a deadlock.
Thread-pool starvation: Continuations may perform long-running work, blocking the thread that called
SetResultand preventing it from doing other work.State corruption: The continuation runs with the calling thread's execution context, which may have unexpected side effects like running on a UI thread or within a specific synchronization context.
Always create TaskCompletionSource<T> with TaskCreationOptions.RunContinuationsAsynchronously to ensure continuations are scheduled asynchronously on the thread pool:
let tcs = TaskCompletionSource<int>(TaskCreationOptions.RunContinuationsAsynchronously)
Licence
WoofWare.FSharpAnalyzers is licensed to you under the MIT licence, a copy of which can be found at LICENCE.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- FSharp.Analyzers.SDK (>= 0.32.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.2.9 | 212 | 11/25/2025 |
| 0.2.8 | 186 | 11/25/2025 |
| 0.2.7 | 179 | 11/24/2025 |
| 0.2.6 | 183 | 11/23/2025 |
| 0.2.5 | 214 | 11/23/2025 |
| 0.2.4 | 148 | 11/23/2025 |
| 0.2.3 | 397 | 11/20/2025 |
| 0.2.2 | 354 | 11/12/2025 |
| 0.2.1 | 215 | 10/20/2025 |
| 0.1.5 | 176 | 10/19/2025 |
| 0.1.4 | 175 | 10/19/2025 |
| 0.1.3 | 621 | 10/4/2025 |
| 0.1.2 | 128 | 10/3/2025 |
| 0.1.1 | 205 | 10/3/2025 |