Skip to content

Commit

Permalink
resolve shadowing
Browse files Browse the repository at this point in the history
  • Loading branch information
candiduslynx committed Oct 8, 2023
1 parent 4518970 commit 22c1413
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 5 deletions.
47 changes: 47 additions & 0 deletions fixtures/shadowed_clashing_types.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/invopop/jsonschema/grandfather-type",
"$ref": "#/$defs/GrandfatherType",
"$defs": {
"GrandfatherType": {
"properties": {
"odd": {
"$ref": "#/$defs/Odd"
},
"link": {
"$ref": "#/$defs/GrandfatherType"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"odd",
"link"
]
},
"GrandfatherType_1": {
"properties": {
"family_name": {
"type": "string"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"family_name"
]
},
"Odd": {
"properties": {
"base": {
"$ref": "#/$defs/GrandfatherType_1"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"base"
]
}
}
}
17 changes: 14 additions & 3 deletions reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ func (r *Reflector) lookupComment(t reflect.Type, name string) string {
// addDefinition will append the provided schema. If needed, an ID and anchor will also be added.
func (r *Reflector) addDefinition(definitions Definitions, t reflect.Type, s *Schema) {
// we save both type & pkg info to match against reflected type later
s.sourceType = fullyQualifiedTypeName(t)
s._type = t

_, name := r.findDef(definitions, t)
if name == "" {
Expand Down Expand Up @@ -608,21 +608,32 @@ func (r *Reflector) findDef(definitions Definitions, t reflect.Type) (*Schema, s
if name == "" {
return nil, ""
}
sourceType := fullyQualifiedTypeName(t)

defName := name
for idx := 1; ; idx++ {
def, ok := definitions[defName]
if !ok {
return nil, defName
}
if def.sourceType == sourceType {
if sameReflectTypes(def._type, t) {
return def, defName
}
defName = name + "_" + strconv.Itoa(idx)
}
}

func sameReflectTypes(a, b reflect.Type) bool {
if a.Kind() != b.Kind() {
return false
}

if fullyQualifiedTypeName(a) != fullyQualifiedTypeName(b) {
return false
}

return a.ConvertibleTo(b) && b.ConvertibleTo(a)
}

func (r *Reflector) lookupID(t reflect.Type) ID {
if r.Lookup != nil {
if t.Kind() == reflect.Ptr {
Expand Down
15 changes: 15 additions & 0 deletions reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,3 +668,18 @@ func TestClashingTypes(t *testing.T) {
r := &Reflector{}
compareSchemaOutput(t, "fixtures/clashing_types.json", r, &Odd{})
}

func TestShadowedClashingTypes(t *testing.T) {
type Odd struct {
Base GrandfatherType `json:"base"`
}

{
type GrandfatherType struct {
Odd Odd `json:"odd"`
Link *GrandfatherType `json:"link"`
}
r := &Reflector{}
compareSchemaOutput(t, "fixtures/shadowed_clashing_types.json", r, &GrandfatherType{})
}
}
5 changes: 3 additions & 2 deletions schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package jsonschema

import (
"encoding/json"
"reflect"

orderedmap "github.com/wk8/go-ordered-map/v2"
)
Expand Down Expand Up @@ -80,8 +81,8 @@ type Schema struct {
// Special boolean representation of the Schema - section 4.3.2
boolean *bool

// sourceType is used to define whether the looked-up definition points to the proper type or not
sourceType string
// _type is used to define whether the looked-up definition points to the proper type or not
_type reflect.Type
}

var (
Expand Down

0 comments on commit 22c1413

Please sign in to comment.