Invalid generated code with nested anyOf and $ref
I discovered this when trying to generate code for https://internect.info/lexicon-schema.json, but I tracked it down to this example:
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"anyOf": [
{
"type": "object",
"required": ["kind", "data"],
"additionalProperties": false,
"properties": {
"kind": { "const": "foo" },
"data": {
"anyOf": [
{
"type": "object",
"required": ["kind"],
"additionalProperties": false,
"properties": {
"kind": { "const": "bar" }
}
},
{
"type": "object",
"required": ["kind"],
"additionalProperties": false,
"properties": {
"kind": { "const": "baz" }
}
}
]
}
}
},
{
"$ref": "#/anyOf/0/properties/data/anyOf/0"
}
]
}
This produces invalid code with these errors:
0>Lexicon_g.cs(231,69): Error CS0102 : The type 'Lexicon' already contains a definition for 'AsAnyOf0Entity'
0>Lexicon_g.cs(242,17): Error CS0102 : The type 'Lexicon' already contains a definition for 'IsAnyOf0Entity'
I presume this is because the properties are named after the type, and both types named "AnyOf0Entity":
/// Gets a value indicating whether the instance is a <see cref="LexiconTest.Lexicon.AnyOf0Entity" />./// Gets a value indicating whether the instance is a <see cref="LexiconTest.Lexicon.AnyOf0Entity.DataEntity.AnyOf0Entity" />.
Oh, that's a good one! I thought I had caught all these de-duplication cases, but evidently not.
(Also you have a peculiar case there with two identical schema in the most deeply nested anyOf - is that just because you've trimmed it down to produce the example?)
(Also you have a peculiar case there with two identical schema in the most deeply nested
anyOf- is that just because you've trimmed it down to produce the example?)
Yeah, the schema I'm ingesting is auto-generated from a TypeScript validation library, so the resulting schema is a bit wonky.
I've scheduled this for a fix this week.
And that schedule whistled past at high speed. I am looking at this today.
Removed: I can repro the issue in a source generator.
The issue was possible naming collisions when using simple GetTypeName() in Is and As property name generation.
We have changed the heuristic so that it now tries the GetTypeName() form first, then falls back on the full type name (excluding namespace) then disambiguates with an incrementing numeric suffix.