Skip to content

Members that differ only by word boundaries (PlayerID / PlayerId, fooBar / foo_bar) pass validation, then map to the same snake_case name, so the generated C++ header does not compile #261

Description

@matt-edmondson

What's wrong

CppGeneratorOptions.MemberNaming defaults to CppMemberNaming.SnakeCase (Schema.Cpp/CppGeneratorOptions.cs:132). CppNaming.Member (Schema.Cpp/CppNaming.cs:26) runs every member, function and parameter name through SnakeCase (CppNaming.cs:55-106). That conversion is many-to-one:

  • PlayerID and PlayerId both become player_id
  • fooBar and foo_bar both become foo_bar

Validation only rejects names that are exactly equal (Schema/Models/Schema.Validation.cs:95, where ReportDuplicates groups ordinally). The same holds for function names and parameter names (Schema.Validation.cs around lines 620 and 641). Nothing checks whether two spelled names collide: neither validation nor CppFileBuilder (around lines 222, 240 and 252) does. The generator therefore writes two declarations with the same name.

Failure scenario

Verified with the published ktsu.Schema.Cpp 1.36.11 and g++.

Take a class Player with members PlayerID: Int and PlayerId: Long. Schema.Validate() reports nothing about the names, and CppCodeGenerator.Generate emits:

struct Player
{
    std::int32_t player_id{};
    std::int64_t player_id{};
};

g++ -std=c++20 then fails with error: redeclaration of 'int64_t game::Player::player_id'.

The C# output for the same schema compiles, so the error appears only in the C++ consumer, and it points at generated code. The reflection table from CppReflectionBuilder (around line 202) names the field the same way, so it is ambiguous as well.

Suggested fix / acceptance criteria

  • When generating, refuse a class whose members map to the same C++ name, with CppGenerationException/TargetCannotExpress naming both schema names and the shared spelling. Apply the same check to interface functions and to the parameters of one function.
    • Alternatively, add a target-independent validation rule that rejects member names that are equal after folding case and underscores.
  • Add a test with PlayerID/PlayerId and another with fooBar/foo_bar. Each should be refused with a clear message rather than producing a header that does not compile.

Related, but distinct:

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions