Skip to content

Validate handwritten mock() method return type, visibility, and uniqueness#210

Merged
dfed merged 9 commits intomainfrom
dfed--mock-method-handwritten
Apr 4, 2026
Merged

Validate handwritten mock() method return type, visibility, and uniqueness#210
dfed merged 9 commits intomainfrom
dfed--mock-method-handwritten

Conversation

@dfed
Copy link
Copy Markdown
Owner

@dfed dfed commented Apr 4, 2026

Summary

  • Adds mockMethodIncorrectReturnType error to FixableInstantiableError that fires when a user-defined mock() method has an invalid return type
  • On concrete type declarations, the return type must be Self or the type name
  • On extension-based @Instantiable types, the return type must match the extended type (e.g. -> Container<Bool>), mirroring the corresponding instantiate() method — Self is rejected, consistent with instantiate() validation
  • Return type validation uses strippingGenerics comparison (mirroring instantiate() validation) rather than base name string matching, correctly handling nested types and generic specializations
  • Adds mock validation to the extension branch of the macro: return type, public/open visibility, per-return-type duplicate detection, and argument validation against the matching instantiate() method's dependencies
  • Fixes the not-public fix-it trivia bug in both branches (old first modifier's leading trivia wasn't cleared after inserting public)
  • Makes Initializer.init(_: FunctionDeclSyntax) and TypeDescription.strippingGenerics public so the macro module can use them
  • Updates the manual to document return type rules for concrete vs extension declarations

Test plan

  • 2 new FixableInstantiableErrorTests for description and fix-it message
  • 7 new InstantiableMacroTests for concrete types: wrong return type, array-wrapped return type, no return type, returning Self, returning the type name
  • 12 new InstantiableMacroTests for extensions: not public, wrong return type, array-wrapped return type, no return type, returning Self (rejected), returning extended type, generic specialization, duplicate same-return-type, Self + type-name pair, multiple different-return-types, missing dependency argument, matching dependency argument
  • Full suite (670 tests) passes
  • Lint passes
  • Coverage: all new code fully covered

🤖 Generated with Claude Code

dfed and others added 2 commits April 4, 2026 10:08
The @INSTANTIABLE macro now checks that a user-defined mock() method
returns Self or the declaring type name. A wrong or missing return type
produces an error with a fix-it that corrects the signature.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 4, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.94%. Comparing base (8ba585b) to head (f95c3c7).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##             main     #210    +/-   ##
========================================
  Coverage   99.94%   99.94%            
========================================
  Files          40       40            
  Lines        5422     5584   +162     
========================================
+ Hits         5419     5581   +162     
  Misses          3        3            
Files with missing lines Coverage Δ
...s/SafeDICore/Errors/FixableInstantiableError.swift 100.00% <100.00%> (ø)
Sources/SafeDICore/Models/Initializer.swift 100.00% <100.00%> (ø)
Sources/SafeDICore/Models/TypeDescription.swift 99.63% <100.00%> (ø)
...ources/SafeDIMacros/Macros/InstantiableMacro.swift 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

dfed and others added 2 commits April 4, 2026 10:58
Add return type, public, and per-return-type duplicate validation for
mock() methods declared on @INSTANTIABLE extensions. This brings
extension mock validation to parity with the concrete declaration path.

Also fix the not-public fix-it for both branches to clear the old first
modifier's leading trivia after inserting `public` before it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dfed dfed changed the title Validate return type of handwritten mock() methods Validate handwritten mock() method return type, visibility, and uniqueness Apr 4, 2026
dfed and others added 5 commits April 4, 2026 11:56
Match each mock to its corresponding instantiate() method by return
type and verify the mock has parameters for all dependencies. Also make
Initializer.init(_: FunctionDeclSyntax) public so the macro can create
Initializer instances for each extension mock function.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mirror the instantiate() validation model: compare parsed
TypeDescriptions via strippingGenerics instead of base name string
matching. This correctly handles nested types (Outer.Inner) and
canonicalizes Self to the declaring type for duplicate detection,
so `-> Self` and `-> TypeName` are treated as the same return type.

Also makes TypeDescription.strippingGenerics public so the macro
module can use it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The dependency-match step used raw mockReturnType to find the matching
instantiate() method, so mock() -> Self never matched any instantiable
and skipped argument validation entirely. Now Self is resolved to the
extended type via strippingGenerics before the lookup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Self is not a valid return type for instantiate() on extensions (the
visitor rejects it), so mock() -> Self should be rejected too. This
removes Self canonicalization from the extension branch entirely —
return type validation, duplicate detection, and argument validation
all use the raw mockReturnType directly, matching mocks to their
corresponding instantiate() methods by exact return type.

Self remains valid on concrete type declarations where it is
unambiguous.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dfed dfed marked this pull request as ready for review April 4, 2026 23:26
@dfed dfed merged commit 54179d4 into main Apr 4, 2026
19 checks passed
@dfed dfed deleted the dfed--mock-method-handwritten branch April 4, 2026 23:33
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.

1 participant