For the complete documentation index, see llms.txt. This page is also available as Markdown.

Analyzers

The Roslyn rules that ship inside Waystone.Monads, what each tier means, and how to turn a rule up or off.

What this page is for

Waystone.Monads ships a Roslyn analyzer inside the package. Install or upgrade to 7.0.0 and you get these rules. You add no reference and configure nothing.

Every rule has an ID like WM1002. The first digit tells you how much it matters:

Tier
Severity
What they report
Page

WM1xxx

Warning

Code that throws or quietly does the wrong thing at run time

WM2xxx

Suggestion

Working code that reads better another way

WM3xxx

Off

Migration aids you turn on while you adopt the library

WMSxxxx

Suggestion

Test assertions that read better another way

Warnings show up in your build. Suggestions show up in your IDE only, so they never break a build that passes today. The WM3xxx rules stay off until you enable them.

The WMS rules ship in the Waystone.Monads.Shouldly package, which you install in test projects only. They are not in the core package.

A separate set of diagnostics uses a WMG prefix. Those come from the source generator rather than the analyzer, they are all errors, and they only fire on an enum you marked with [ErrorCodeCatalog]. They are on Source generation instead.

These pages list the rules as at the version they were written for. For the set that ships in the version you installed, read Rules.cs in the repository — every descriptor is declared there in one file.

Every rule

ID
What it reports
Default

Option.Some given a value that is provably null, which always throws

Warning

null written where an Option or Result belongs

Warning

default on an Option or Result, which is null rather than the empty case

Warning

Option.Some given a value the compiler treats as maybe-null

Warning

A discarded Result, so the failure vanishes

Warning

An Option or Result declared nullable, which adds a third state

Warning

An async delegate passed to a synchronous method, so the task is never awaited

Warning

Unwrap and UnwrapErr, which throw when there is no value

Suggestion

Expect, which throws when its invariant does not hold

Suggestion

A throw inside a member that returns Result

Suggestion

An IsSome check with an Unwrap inside it

Suggestion

Map followed by Flatten, which is AndThen

Suggestion

A state check combined with an unwrap of the same value

Suggestion

UnwrapOr given the default of the type

Suggestion

An Option or Result compared to null

Suggestion

Option<Option<T>>, which has three states where two mean anything

Suggestion

Retired in 7.0.0. Result<T, T>

Not shipped

A declaration that names Some, None, Ok or Err instead of the base type

Suggestion

A nullable member sitting alongside members that use Option

Suggestion

A discarded Option

Suggestion

UnwrapOrDefault or MapOrDefault producing a value type

Suggestion

An eager argument that is not free to evaluate

Suggestion

A delegate that captures, where binding the data with With would avoid the closure

Suggestion

Two [ErrorCodeCatalog] enums that generate the same error code

Suggestion

A generated error code that ErrorCodes.txt does not list

Suggestion

An ErrorCodes.txt entry no catalog generates

Suggestion

A state check read through a property pattern

Suggestion

A Task-returning method group passed to AndThenAsync or OrElseAsync

Suggestion

An Option bound as state by With instead of zipped

Suggestion

A delegate with nothing to defer passed to a lazy member

Suggestion

A member that returns a nullable type, where Option<T> would fit

Off

A throw, where returning Result<TOk, Error> would fit

Off

An assertion on IsSome, IsOk or Unwrap instead of on the monad

Suggestion

An await wrapped in parentheses so a synchronous assertion can run

Suggestion

The id space has gaps. WM1004, WM1007, WM1009, WM1010 and WM2014 shipped in 5.x and were removed in 6.0.0. WM2010 was removed in 7.0.0. A removed id is never reused.

Changing a rule

You configure every rule through .editorconfig, the standard way. Raise one:

Silence one:

Silence one at a single line:

Put an .editorconfig in a subdirectory to scope a rule to part of your solution. Test projects are the common case. WM2001 earns its keep less in a test, where an unwrap that throws fails the test anyway.

You cannot drop the analyzer and keep the library, because both ship in one package. .editorconfig is how you turn rules off.

To raise a whole tier rather than a rule at a time, see Severity presets. One MSBuild property covers the set.

The WMS rules configure the same way, through dotnet_diagnostic.WMS2001.severity and the like. You can drop those entirely by removing the Waystone.Monads.Shouldly package reference, since the analyzer ships with it — which you cannot do for the WM rules, because they ship inside the library.

Last updated

Was this helpful?