Skip to content

feat: add nullability filters and assertions for members#332

Merged
vbreuss merged 3 commits into
mainfrom
feature/nullability-assertions
Jun 6, 2026
Merged

feat: add nullability filters and assertions for members#332
vbreuss merged 3 commits into
mainfrom
feature/nullability-assertions

Conversation

@vbreuss
Copy link
Copy Markdown
Member

@vbreuss vbreuss commented Jun 6, 2026

  • IsNullable() / IsNotNullable() on single properties and fields
  • AreNullable() / AreNotNullable() on property and field collections
  • WhichAreNullable() / WhichAreNotNullable() filters for properties and fields
  • OnlyHasNullableMembers() / OnlyHasNonNullableMembers() on single types
  • OnlyHaveNullableMembers() / OnlyHaveNonNullableMembers() on type collections
  • WhichOnlyHaveNullableMembers() / WhichOnlyHaveNonNullableMembers() type filters

Nullability covers Nullable<T> value types and nullable reference types.
Detection uses NullabilityInfoContext on .NET 8+ and falls back to reading
the NullableAttribute / NullableContextAttribute metadata on netstandard2.0.


@vbreuss vbreuss self-assigned this Jun 6, 2026
@vbreuss vbreuss added the enhancement New feature or request label Jun 6, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 6, 2026

Test Results

    13 files  ±  0      13 suites  ±0   10m 28s ⏱️ +47s
 6 672 tests +158   6 669 ✅ +158   3 💤 ±0  0 ❌ ±0 
39 877 runs  +948  39 864 ✅ +948  13 💤 ±0  0 ❌ ±0 

Results for commit fe45383. ± Comparison against base commit 2defc14.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 6, 2026

🚀 Benchmark Results

Details

BenchmarkDotNet v0.15.8, Linux Ubuntu 24.04.4 LTS (Noble Numbat)
AMD EPYC 9V74 2.87GHz, 1 CPU, 4 logical and 2 physical cores
.NET SDK 10.0.300
[Host] : .NET 10.0.8 (10.0.8, 10.0.826.23019), X64 RyuJIT x86-64-v3
DefaultJob : .NET 10.0.8 (10.0.8, 10.0.826.23019), X64 RyuJIT x86-64-v3

Method Mean Error StdDev Gen0 Allocated
TypeIsNotStatic_aweXpect 207.9 ns 0.66 ns 0.55 ns 0.0386 648 B

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 6, 2026

👽 Mutation Results

Mutation testing badge

aweXpect.Reflection

Details
File Score Killed Survived Timeout No Coverage Ignored Compile Errors Total Detected Total Undetected Total Mutants
Filters/FieldFilters.WhichAreNullable.cs 100.00% 3 0 0 0 0 0 3 0 3
Filters/PropertyFilters.WhichAreNullable.cs 100.00% 3 0 0 0 0 0 3 0 3
Filters/TypeFilters.WhichOnlyHaveNullableMembers.cs 100.00% 4 0 0 0 0 0 4 0 4
Helpers/MemberViolationRenderer.cs 93.75% 15 1 0 0 4 16 15 1 36
Helpers/NullabilityHelpers.cs 68.49% 50 8 0 15 27 34 50 23 134
ThatField.IsNullable.cs 100.00% 10 0 0 0 3 6 10 0 19
ThatFields.AreNullable.cs 100.00% 20 0 0 0 4 12 20 0 36
ThatProperties.AreNullable.cs 100.00% 20 0 0 0 4 12 20 0 36
ThatProperty.IsNullable.cs 100.00% 10 0 0 0 3 6 10 0 19
ThatType.OnlyHasNonNullableMembers.cs 88.24% 15 2 0 0 3 6 15 2 26
ThatType.OnlyHasNullableMembers.cs 88.24% 15 2 0 0 3 6 15 2 26
ThatTypes.OnlyHaveNonNullableMembers.cs 92.86% 13 1 0 0 3 4 13 1 21
ThatTypes.OnlyHaveNullableMembers.cs 92.86% 13 1 0 0 3 4 13 1 21

The final mutation score is 86.43%

Coverage Thresholds: high:80 low:60 break:0

vbreuss added 3 commits June 6, 2026 10:08
Implements #330:
- `IsNullable()` / `IsNotNullable()` on single properties and fields
- `AreNullable()` / `AreNotNullable()` on property and field collections
- `WhichAreNullable()` / `WhichAreNotNullable()` filters for properties and fields
- `OnlyHasNullableMembers()` / `OnlyHasNonNullableMembers()` on single types
- `OnlyHaveNullableMembers()` / `OnlyHaveNonNullableMembers()` on type collections
- `WhichOnlyHaveNullableMembers()` / `WhichOnlyHaveNonNullableMembers()` type filters

Nullability covers `Nullable<T>` value types and nullable reference types.
Detection uses `NullabilityInfoContext` on .NET 8+ and falls back to reading
the `NullableAttribute` / `NullableContextAttribute` metadata on netstandard2.0.
Decode the NullableAttribute / NullableContextAttribute metadata on every
target framework instead of using NullabilityInfoContext on .NET 8+, so the
same member yields the same result everywhere. This fixes two cross-framework
divergences found in review:
- [AllowNull] / [MaybeNull] post-condition attributes made members count as
  nullable on .NET 8+ but not on netstandard2.0
- unconstrained generic type parameters (T) counted as nullable on .NET 8+
  but not on netstandard2.0

Also partition members in a single pass in the OnlyHas… type constraints and
pin the edge-case semantics (arrays, indexers, generics, post-condition
attributes) with tests.
- resolve members declared as a bare generic type parameter through the
  constructed base type, so that e.g. a member of type T accessed via a
  type deriving from Base<string?> counts as nullable
- fail AreNotNullable for null entries in the collection, consistent with
  AreNotStatic/AreNotReadOnly and the singular IsNotNullable
- add optional MemberScope parameter to OnlyHas(Non)NullableMembers,
  OnlyHave(Non)NullableMembers and WhichOnlyHave(Non)NullableMembers
- mark NullableWriteOnlyProperty test helpers as static and suppress
  CS0436 for the Nullable polyfill in the internal test project (sonar)
@vbreuss vbreuss force-pushed the feature/nullability-assertions branch from 69b9c77 to fe45383 Compare June 6, 2026 08:11
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 6, 2026

@vbreuss vbreuss merged commit c890856 into main Jun 6, 2026
12 checks passed
@vbreuss vbreuss deleted the feature/nullability-assertions branch June 6, 2026 08:32
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 7, 2026

This is addressed in release v2.0.0.

@github-actions github-actions Bot added the state: released The issue is released label Jun 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request state: released The issue is released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add nullability assertions for members (nullable reference type metadata)

1 participant