Skip to content

Qualify nested-type refs shadowed by a sibling of the same simple name#118

Closed
ghostdogpr wants to merge 1 commit into
mainfrom
fix/qualify-shadowing-nested-ref
Closed

Qualify nested-type refs shadowed by a sibling of the same simple name#118
ghostdogpr wants to merge 1 commit into
mainfrom
fix/qualify-shadowing-nested-ref

Conversation

@ghostdogpr

Copy link
Copy Markdown
Owner

Problem

qualifyReferences (used by ProtobufCodec.render and Service.render) rendered a reference to a nested type as just its bare simple name whenever the referencing scope was enclosed by the target's parent:

val inScope = scope == parent || (scope.length > pl && scope.charAt(pl) == '.' && scope.startsWith(parent))
if (inScope) name else path

This ignores proto3's innermost-scope-first name resolution. If the current message has its own nested type of the same simple name, that inner type shadows the intended one, so the emitted bare name binds to the wrong message. The .proto still parses, but the field now points at a different type — a silently corrupted schema.

Concrete case

Outer has nested Outer.Inner and nested Outer.Deep; Outer.Deep has its own nested Outer.Deep.Inner. A field in Outer.Deep referencing the outer Outer.Inner rendered as bare Inner, which under proto3 rebinds to Outer.Deep.Inner.

Fix

Resolve the bare name the way proto3 would — from scope outward to the root, first same-named declared type wins — and keep the bare name only when it lands on the intended target. Otherwise fall back to the qualified path (the existing out-of-scope rendering).

Test

ProtobufRenderSpec: a sibling-shadowing scenario asserts the ref is qualified to Outer.Inner. Red before the fix (rendered bare Inner), green after. Full core suite (138) and grpc RenderSpec/FileDescriptorSpec (43) remain green.

qualifyReferences emitted a bare simple name for any nested-type reference whose
target parent enclosed the current scope, ignoring proto3's innermost-scope-first
name resolution. When the current message had its own nested type of the same
simple name, the bare name bound to that sibling instead of the intended type, so
the rendered .proto silently pointed the field at the wrong message.

Resolve the bare name the way proto3 would (scope outward to root) and only keep
it when it lands on the intended target; otherwise fall back to the qualified path.
@ghostdogpr ghostdogpr closed this Jul 9, 2026
@ghostdogpr ghostdogpr deleted the fix/qualify-shadowing-nested-ref branch July 9, 2026 06:00
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