Skip to content

fix: CMTK0006 counts an assignment through a cast of this - #243

Merged
CaffeinatedCoder merged 3 commits into
release/2.3.1from
fix/explicit-interface-assignment-silent-2-3-1
Oct 31, 2026
Merged

CaffeinatedCoder merged 3 commits into
release/2.3.1from
fix/explicit-interface-assignment-silent-2-3-1

Conversation

@CaffeinatedCoder

Copy link
Copy Markdown
Owner

Closes #231

Problem

UnassignedNoDefaultMemberAnalyzer.Assignments.Collect recorded a property assignment only on a bare IInstanceReferenceOperation and added the referenced property. A class reaches its own explicit interface implementation only through a cast, ((IHasId)this).Id = id: its Instance is a conversion over this, and its property is IHasId.Id, not the class's implementation that is the candidate. So CMTK0006 reported a member every constructor assigns, which fails a warnings-as-errors build.

Change

  • UnassignedNoDefaultMemberAnalyzer.cs: Collect strips conversions down to this, for fields and properties, and maps an interface's property to the analysed type's implementation (FindImplementationForInterfaceMember). Tuple elements and ref/out arguments go through the same Collect. A local holding this is not followed: IHasId self = this; self.Id = id; stays reported (the issue left this to the fix; the README says so).
  • Sibling (Found-By: VA, its own commit): Collect took any instance reference as this, so a constructor whose only assignment was new Twin(0) { Id = x } or other with { Id = x } counted as assigning its own Id, and CMTK0006 was silent. Only the containing instance counts now.
  • Analyzers README: the CMTK0006 section says the cast counts and the alias doesn't; claim K06-an-explicit-implementation-through-a-cast holds it. Remarks on the analyzer updated.
  • CHANGELOG under 2.3.1: the fix under ### Fixed, the sibling under ### Changed since a warnings-as-errors build can now fail. Both are a Warning, so no exception to decision 34.

Tests

  • A_member_assigned_through_a_cast_of_this_stays_silent, across the forms that assign a member in a constructor: this., a cast of this to an interface the member implements explicitly, implicitly, to the second of two, to a generic one, a cast to the class itself (field), deconstruction through the cast, and out through the cast. All seven were reported before.
  • A_cast_assigns_only_the_member_it_reaches_on_this: two constructors where only one assigns through the cast name the other; a cast of another instance assigns nothing; a local alias stays reported.
  • An_initializer_of_another_instance_assigns_nothing_on_this: an object initializer and a with of another instance report.
  • Reverting the source fails all three; keeping the interface's property instead of mapping it fails the first two; reverting the sibling fails its row (0 reports where 2 are expected).
  • Analyzers (3,692), Conventions (2,016), Samples (150) and Oracles (51) green locally through tools/BuildVerdict; the solution builds clean.

🤖 Generated with Claude Code

CaffeinatedCoder and others added 2 commits October 31, 2026 08:32
…the class's implementation

Assignments.Collect recorded a property assignment only on a bare
IInstanceReferenceOperation and added the referenced property. A class
reaches its own explicit interface implementation only through a cast,
((IHasId)this).Id = id, whose Instance is a conversion over this and
whose property is the interface's, not the candidate. So a member every
constructor assigned was reported, failing a warnings-as-errors build.

Collect now strips conversions down to this, for fields and properties
alike, and maps an interface's property to the analysed type's
implementation (FindImplementationForInterfaceMember). Tuple elements
and ref/out arguments go through the same Collect. A local holding this
is not followed: IHasId self = this; self.Id = id stays reported, as
the README now says.

Input class (AIS): the forms that assign a member in a constructor.
Plain and this. (silent before and after), a cast of this to an
interface the member implements explicitly, implicitly, to the second
of two it implements and to a generic one, a cast to the class itself
for a field, deconstruction through the cast, and out through the cast:
all seven were reported, the same cause, and are silent now. Two
constructors where one assigns through the cast still name the other,
and a cast of another instance assigns nothing.

Reverting the source fails both rows; mapping nothing (casts stripped,
the interface's property kept) fails both as well.

Closes #231

Defect-Class: AIS
Found-By: CA
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…signing this one

Collect took any IInstanceReferenceOperation as this. An object
initializer's receiver and a with expression's are instance references
too, of the object they create. So a constructor whose only assignment
was _ = new Twin(0) { Id = x } counted as assigning its own Id, and the
member nothing set on this instance was not reported. Only the
containing type's instance counts now.

Found running #231's input class (the forms that assign a member in a
constructor) across what the receiver is: this, a cast of it, another
instance, a local alias, an object initializer and a with. The last two
were silent; both report now.

Reverting the source fails the row: 0 reports where 2 are expected.

Refs #231

Defect-Class: AIS
Found-By: VA
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CaffeinatedCoder CaffeinatedCoder added this to the 2.3.1 milestone Oct 31, 2026
@CaffeinatedCoder CaffeinatedCoder added bug Something isn't working severity/low Cosmetic, message or documentation-level difference package/analyzers Affects CodoMetis.TypeKit.Analyzers area/value-objects Value-object contracts and what the aspects generate for them labels Oct 31, 2026
# Conflicts:
#	CHANGELOG.md
#	test/oracles/claims.json
@CaffeinatedCoder
CaffeinatedCoder merged commit 88ae0fe into release/2.3.1 Oct 31, 2026
10 checks passed
@CaffeinatedCoder
CaffeinatedCoder deleted the fix/explicit-interface-assignment-silent-2-3-1 branch October 31, 2026 08:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/value-objects Value-object contracts and what the aspects generate for them bug Something isn't working package/analyzers Affects CodoMetis.TypeKit.Analyzers severity/low Cosmetic, message or documentation-level difference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant