Skip to content

Unitialized analyzer#938

Open
JoschkaBC wants to merge 6 commits into
SteveDunn:mainfrom
JoschkaBC:unitialized-analyzer
Open

Unitialized analyzer#938
JoschkaBC wants to merge 6 commits into
SteveDunn:mainfrom
JoschkaBC:unitialized-analyzer

Conversation

@JoschkaBC

Copy link
Copy Markdown

fixex #934
closes #936

Adds a new analyzer VOG038 that tries to detect the pattern described in ##934.
Also adds two code fixes to make these properties either nullable or required.

Concerns

Use cases in which uninitialized members are expected

In some cases it would be inconvenient to always suppress this warning, because the member is set dynamically and some point in time. Like in an EFCore Interceptor.
The analyzer warning is correct in those cases, but one may want to suppress the warning easily across their code base.
For this [MayBeUninitialized] was added. This attribute suppresses the analyzer for a given member.
It will also flow down to interface implementations or overwrites.

Example

``` c# interface IAuditable { [MayBeUninitialized] DateModifiedVo DateModified {get;} } public DbEntity : IAuditable { // This is set by an EFCore Interceptor and should not be modified or supplied by the user // It will be unitialized between the instantiation and a SaveChanges call // But the warning will be suppressed by thanks to the attribute on the interface public DateModifiedVo DateModified { get; private init; } } ```

Complex constructor assignments

Sometimes a constructor sets values through helper methods.
And we cannot detect this, because traversing down the entire call tree would be very complex, error prone and expensive.
.NET also recognizes this as a problem with required members and introduces the constructor attribute [SetsRequiredMembers].
This PR adds an equivalent [SetsUninitializedMembers] which will mark a constructor as "this constructor always initialized all value objects".
Yielding the full responsibility back to the user.


AI Summary of the changes

1. New Analyzer: DoNotUseUninitializedMembersAnalyzer (VOG038)

  • Monitors properties and fields whose types are Vogen Value Objects.
  • Reports a warning if a member is:
    • Not nullable.
    • Not marked as required.
    • Not assigned an inline initializer.
    • Not assigned in all constructors of the containing type.
  • Supports both static and instance members.
  • Correctly handles auto-properties and manual backing fields.

2. New Attributes for Control

  • [MayBeUninitialized]: Can be applied to a property or field to explicitly suppress the VOG038 warning for that member.
  • [SetsUninitializedMembers]: Can be applied to a constructor to indicate that it handles the initialization of all members, similar to how [SetsRequiredMembers] works in C#.

3. Code Fixers

Provided two automated fixes for the VOG038 diagnostic:

  • Mark member as 'required': Adds the required modifier to the property or field.
  • Make member type nullable: Changes the member type to its nullable equivalent (e.g., MyVo to MyVo?).

@SteveDunn

Copy link
Copy Markdown
Owner

Many thanks! I just merge mine, but I'll take a look at this one too to see if there's any difference in functionality. The fixers will be very handy!

@JoschiZ

JoschiZ commented May 10, 2026

Copy link
Copy Markdown
Contributor

The very important main difference is, that your version does not cover assignments in constructors and ignores fields all together.
Especially the assignemts in constructors feels like an necessary feature to not produce as many false positives.

Thats the main complexity in my implementation. (2 different accounts, because the work was mainly done during working hours).

Not sure about all the edge cases.
But the easy way to compare would obviously be to just quickly copy paste the unit test from this branch into yours.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants