schemagen: a property/$defs name that camel-cases to RootBuilder collides with the generated builder class (generated header does not compile)
#69
Reference in new issue
Block a user
Summary
contrib/schemagen/weaseljson_schemagen.pywrites several identifiers of its own into the generated header, butBuilder._is_reserved()only reserves two of them (Root,RootScalar). A perfectly valid schema whose CamelCase type name isRootBuildertherefore gets a namespace-scopestruct RootBuilder, which collides with the builder class the generator itself emits at namespace scope:schemagen exits 0 with no diagnostic; the breakage only shows up when the generated header is compiled.
Root cause
contrib/schemagen/weaseljson_schemagen.py,Builder._is_reserved()(lines 270-274):unique_name()/_name_taken()(lines 251-268) is the only guard against collisions, so any user object/enum name equal to one of the identifiers the emitter writes is accepted. The identifiers the emitter actually writes are:Rootalias (_root_alias),RootInner(Emitter.emit), andRootBuilder(the class in_builder()'s f-string, line 971) - onlyRootis reserved;RootBuilder:Kind(line 726/1005),Cat(line 1006),SlotInfo(line 1007),Frame(line 1014) - none reserved.Reproduction 1 - property key
repro.json:Generated code (gen.h lines 16-31):
Error:
"root_builder","root-builder"and"RootBuilder"all camel-case toRootBuilder, andcamel()is applied to$defs/definitionskeys as well, so the same thing happens with:Reproduction 2 -
$defsentrySame
error: redefinition of 'RootBuilder'. An enum-valued property namedroot_builderfails too (error: use of 'RootBuilder' with tag type that does not match previous declaration), so it is not specific to nested objects.Reproduction 3 - the same gap shadows user types inside
RootBuilderObject-valued properties named
kind,cat,frame,slot_infoproducestruct Kind/struct Cat/struct Frame/struct SlotInfoat namespace scope. Inside the builder the nestedenum class Kind,enum class Cat,struct SlotInfo,struct Frameshadow them, so the generatedengage()becomes ill-formed:and for
kind/cat:Impact
Any valid JSON Schema using one of these names for an object/enum-valued property (or for a
$defsentry) produces a header that cannot be compiled. schemagen reports success, so the failure surfaces only in the consumer's build.kindandframeare ordinary JSON property names, androot_builder/RootBuilderis a plausible$defsname.Why this is not a duplicate
Root,Skip,RootScalarand duplicateArrN/Kindenumerators; the builder class nameRootBuilderis not mentioned there, is still missing from_is_reserved, and the regression tests added for #21 (test_root_alias_does_not_collide_with_user_type,test_kind_enum_does_not_duplicate_arr0,test_skip_user_type_is_allowed) do not cover it._build_object).This is a collision between a user type name and an identifier the generator itself emits at the same scope.
Suggested fix
Extend
_is_reserved()with the emitted names (RootBuilder,RootInner,Kind,Cat,SlotInfo,Frame), or rename them to a reserved prefix, and add a compile-checked regression test (the existingSchemagenCollisionTest.generate_and_compilehelper intest_schemagen.pycan be reused).