Name shared path parameter helper types once, hashing cross-path collisions#2476
Conversation
…codegen#2466)" This reverts commit a07731d.
Greptile SummaryThis PR fixes the "redeclared in this block" compile error for path-item-level
Confidence Score: 5/5Safe to merge; the fix correctly eliminates the redeclared-in-this-block compile error, preserves historical undecorated names for non-colliding parameters, and the new fixture provides compile-time guards for all four code paths. The core logic — pre-passing to count collisions, assigning FNV hash tokens, emitting shared type definitions once per path item, and skipping shared params in per-operation type collection — is sound. The generated fixture compiles and validates all scenarios. The two observations (potential over-disambiguation when the same path-item pointer appears twice in enumerateSharedParamScopes, and misleading doc comments on non-colliding shared types) are both edge-case quality issues that do not affect correctness or compilation. No files require special attention; pkg/codegen/operations.go has the main algorithmic change but is well-covered by the new test fixture.
|
| Filename | Overview |
|---|---|
| pkg/codegen/operations.go | Core logic for shared parameter pre-pass: resolveSharedParameters, enumerateSharedParamScopes, describeSharedParameters, assignScopeTokens, sharedParameterTypeDefs, and paramNeedsHoisting are all new. The ParameterDefinition struct gains a Shared bool, and GenerateTypeDefsForOperation now skips shared params. Minor: the nameCounts counting loop lacks the path-item deduplication guard that the result-building loop has. |
| pkg/codegen/templates/param-types.tmpl | Adds a {{if .Comment}} branch so pre-formatted doc comments on disambiguated (hash-prefixed) types are emitted verbatim. Non-colliding shared types still fall through to the "defines parameters for {opid}" default, which misattributes them to the first operation rather than the path item. |
| internal/test/parameters/shared_collision/spec.yaml | New fixture covering all four scenarios: within-path multi-method shared param (wid), cross-path colliding shared param (id, hash-disambiguated), non-colliding single-method param (ref), callback shared param (cbid), and webhook shared param (whid). |
| internal/test/parameters/shared_collision/shared_collision.gen.go | Generated output looks correct: hash-prefixed Hd147675Id0/Hd147675Id1 and Hdf81445Id0/Hdf81445Id1 for colliding paths, bare Wid0/Wid1 and Ref0/Ref1 for non-colliding paths, Whid0/Whid1 emitted once for the two-method webhook, Cbid0/Cbid1 emitted once for the two-method callback. |
| internal/test/parameters/shared_collision/shared_collision_test.go | Compile-time guards via blank var declarations for all shared types (Wid0/Wid1, Ref0/Ref1, Whid0/Whid1, Cbid0/Cbid1), plus a runtime regex test asserting that bare Id0/Id1 are absent and exactly two hash-prefixed id variants exist. |
| internal/test/spec_validation/spec_validation_test.go | The old shared_path_param_type_collision.yaml rejection test is removed (collision is now resolved gracefully by hashing instead of rejected at validation time). No other changes. |
| internal/test/parameters/shared_anyof/doc.go | Entire shared_anyof fixture deleted; the new shared_collision fixture covers all the same scenarios (within-path multi-method, webhook, callback) plus the new cross-path collision case. |
Reviews (2): Last reviewed commit: "Name shared path parameter helper types ..." | Re-trigger Greptile
…isions Closes: oapi-codegen#2090 A parameter declared at the path-item level is inherited by every method on the path. Its hoisted helper types -- the members of an inline anyOf/oneOf and similar -- were named from the parameter alone and declared once per operation, so a path with more than one method redeclared them ("Id0 redeclared in this block"). The same bare names also collided across different paths that reuse the same parameter, which is the common REST case of an {id} shared by sibling paths. Resolve path-item-level parameters in a single pre-pass (resolveSharedParameters): describe each scope's shared parameters once, count how many scopes hoist a helper type under each name, and emit each scope's helper types once for its path item rather than once per operation. A name produced by two or more scopes is disambiguated by prefixing that scope's parameters with a short, stable FNV hash of the scope, extended to the full hash only if two scopes' short hashes clash. A parameter that does not collide keeps its historical undecorated name, so existing generated code is unaffected -- the only outputs that change are specs that previously failed to compile. Applied uniformly to regular paths, webhooks, and callbacks, which share the one global Go type namespace. Disambiguated types carry a doc comment explaining the hash prefix and pointing back to the source path. Adds internal/test/parameters/shared_collision covering a shared anyOf parameter across multiple methods on a path (bare, emitted once), the same parameter reused across sibling paths (hash-disambiguated), and a non-colliding single-method parameter (unchanged). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
207fd38 to
4f69fd3
Compare
Closes: #2090