Table of Contents

Roslyn analyzers reference

Conjecture includes Roslyn analyzers bundled in Conjecture.Core. They activate automatically — no additional packages needed.

Diagnostic rules

CON100: Assertion inside [Property] method

Severity: Warning
Target: void-returning [Property] methods that use framework assertions.

Consider returning bool for simpler, clearer tests.

// Triggers CON100:
[Property]
public void Bad(int value)
{
    Assert.True(value >= 0);  // CON100
}

// Preferred:
[Property]
public bool Good(int value) => value >= 0;

CON101: High-rejection Where() predicate

Severity: Warning
Target: .Where() predicates likely to reject most generated values.

High rejection rates cause poor performance and risk UnsatisfiedAssumptionException.

// Triggers CON101:
var primes = Strategy.Integers<int>(0, 1_000_000).Where(IsPrime);

// Better: generate from a small known set
var primes = Strategy.SampledFrom(new[] { 2, 3, 5, 7, 11, 13 });

CON102: Sync-over-async inside [Property]

Severity: Info
Target: .Result, .GetAwaiter().GetResult(), or .Wait() inside a [Property] method.

Make the method async instead.

// Triggers CON102:
[Property]
public bool Bad(int id)
{
    var result = _client.GetAsync($"/api/{id}").Result;  // CON102
    return result.IsSuccessStatusCode;
}

// Better:
[Property]
public async Task<bool> Good(int id)
{
    var result = await _client.GetAsync($"/api/{id}");
    return result.IsSuccessStatusCode;
}

CON103: Strategy bounds are inverted

Severity: Error
Target: Strategy factory calls where min > max.

// Triggers CON103:
Strategy.Integers<int>(100, 0)  // min (100) > max (0)

// Fix:
Strategy.Integers<int>(0, 100)

CON104: Assume.That(false) always skips

Severity: Warning
Target: Unconditional Assume.That(false) calls.

Every example is skipped — the test is effectively disabled.

// Triggers CON104:
Assume.That(false);  // test is useless

CON105: [Arbitrary] provider exists but [From<T>] not used

Severity: Info
Target: Parameters whose type has an [Arbitrary]-generated provider, but [From<T>] is absent.

[Arbitrary]
public partial record Money(decimal Amount, string Currency);

// Triggers CON105:
[Property]
public bool Test(Money money) => ...;

// Better:
[Property]
public bool Test([From<MoneyArbitrary>] Money money) => ...;

CON107: Non-deterministic operation in [Property]

Severity: Warning
Target: Calls to Guid.NewGuid(), DateTime.Now, DateTime.UtcNow, DateTimeOffset.Now, DateTimeOffset.UtcNow, Random.Shared, new Random(), Environment.TickCount, or Environment.TickCount64 inside a [Property] method.

Non-deterministic operations break shrink reproducibility.

// Triggers CON107:
[Property]
public bool Bad(int x)
{
    Guid id = Guid.NewGuid();  // CON107
    return id != Guid.Empty;
}

// Better: inject randomness via a strategy parameter
[Property]
public bool Good([From<GuidStrategy>] Guid id) => id != Guid.Empty;

CON108: Redundant Assume.That given strategy constraint

Severity: Warning
Target: Assume.That(condition) where the condition is always satisfied by a known built-in strategy (PositiveInts, NegativeInts, NonNegativeInts).

// Triggers CON108:
[Property]
public bool Bad([From<PositiveInts>] int x)
{
    Assume.That(x > 0);  // CON108: always true for PositiveInts
    return x * 2 > x;
}

// Fix: remove the redundant assumption
[Property]
public bool Good([From<PositiveInts>] int x) => x * 2 > x;

CON109: No strategy found for [Property] parameter

Severity: Warning
Target: [Property] method parameters whose type has no resolvable strategy — no built-in support, no [From<T>], and no [Arbitrary] on the type.

// Triggers CON109:
[Property]
public bool Bad(MyCustomType x) => x is not null;  // CON109

// Fix: add [Arbitrary] to the type or use [From<T>]
[Property]
public bool Good([From<MyCustomTypeStrategy>] MyCustomType x) => x is not null;

CON110: Async [Property] without await

Severity: Info
Target: [Property] methods declared async that contain no await expression.

// Triggers CON110:
[Property]
public async Task<bool> Bad(int x) { return x > 0; }  // CON110

// Fix: remove async or add an awaited call
[Property]
public bool Good(int x) => x > 0;

CON111: Target.Maximize/Minimize outside [Property]

Severity: Warning
Target: Calls to Target.Maximize(…) or Target.Minimize(…) in a method not decorated with [Property]. These calls are no-ops outside a property test body.

// Triggers CON111:
public void Helper(double x)
{
    Target.Maximize(x);  // CON111: no effect here
}

// Fix: move the call into a [Property] method
[Property]
public bool Good(double x)
{
    Target.Maximize(x);
    return x < 1000;
}

CJ0050: Suggest named extension property

Severity: Info
Target: .Where() predicates that match a named extension property: .Positive, .Negative, .NonZero, .NonEmpty.

A code fix is available.

// Triggers CJ0050:
var pos = Strategy.Integers<int>().Where(x => x > 0);  // CJ0050

// Fix: use the extension property
var pos = Strategy.Integers<int>().Positive;

Source generator diagnostics

The [Arbitrary] source generator reports its own set of diagnostics:

Concrete type diagnostics (CON200–CON202)

ID Severity Description
CON200 Error No accessible constructor found on [Arbitrary] type
CON201 Error [Arbitrary] type is not partial
CON202 Warning Constructor parameter type has no resolvable strategy

Strategy.For<T>() call-site diagnostics (CON310–CON313)

These fire at Strategy.For<T>() or [From<T>] call sites. See Reference: Strategy.For<T>() for resolution steps.

ID Severity Description
CON310 Error Strategy.For<T>() target is an interface
CON311 Error Strategy.For<T>() target is abstract with no [Arbitrary] subtypes
CON312 Error Strategy.For<T>() has no registered provider — type lacks [Arbitrary]
CON313 Warning Mutually recursive [Arbitrary] types without [StrategyMaxDepth]

Sealed hierarchy diagnostics (CON205, CON300–CON302)

These fire when [Arbitrary] is applied to an abstract class (hierarchy mode).

ID Severity Description
CON205 Warning Concrete subtype of [Arbitrary]-decorated abstract base lacks [Arbitrary]; it will not be included in the generated OneOf strategy
CON300 Error [Arbitrary] base type is not abstract
CON301 Error [Arbitrary] base type is not a class or record (interfaces are not supported)
CON302 Error No concrete [Arbitrary]-decorated subtypes found in compilation
Note

The generator only detects subtypes in the same compilation. Subtypes defined in external assemblies are silently excluded — CON205 does not fire for them. See Understanding sealed hierarchy strategies for details.

Suppressing diagnostics

Per-location:

#pragma warning disable CON100
[Property]
public void Intentionally_using_assertions(int value) { /* ... */ }
#pragma warning restore CON100

Project-wide via .editorconfig:

[*.cs]
dotnet_diagnostic.CON100.severity = none