Skip to content

Commit e5d507d

Browse files
authored
enhancement for PR #1387: evaluate const across packages (#1388)
* enhancement: evaluate const across packages
1 parent 8117f4c commit e5d507d

14 files changed

Lines changed: 229 additions & 181 deletions

const.go

Lines changed: 3 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -2,121 +2,14 @@ package swag
22

33
import (
44
"go/ast"
5-
"go/token"
6-
"strconv"
75
)
86

9-
// ConstVariable a model to record an const variable
7+
// ConstVariable a model to record a const variable
108
type ConstVariable struct {
119
Name *ast.Ident
1210
Type ast.Expr
1311
Value interface{}
1412
Comment *ast.CommentGroup
15-
}
16-
17-
// EvaluateValue evaluate the value
18-
func (cv *ConstVariable) EvaluateValue(constTable map[string]*ConstVariable) interface{} {
19-
if expr, ok := cv.Value.(ast.Expr); ok {
20-
value, evalType := evaluateConstValue(cv.Name.Name, cv.Name.Obj.Data.(int), expr, constTable, make(map[string]struct{}))
21-
if cv.Type == nil && evalType != nil {
22-
cv.Type = evalType
23-
}
24-
if value != nil {
25-
cv.Value = value
26-
}
27-
return value
28-
}
29-
return cv.Value
30-
}
31-
32-
func evaluateConstValue(name string, iota int, expr ast.Expr, constTable map[string]*ConstVariable, recursiveStack map[string]struct{}) (interface{}, ast.Expr) {
33-
if len(name) > 0 {
34-
if _, ok := recursiveStack[name]; ok {
35-
return nil, nil
36-
}
37-
recursiveStack[name] = struct{}{}
38-
}
39-
40-
switch valueExpr := expr.(type) {
41-
case *ast.Ident:
42-
if valueExpr.Name == "iota" {
43-
return iota, nil
44-
}
45-
if constTable != nil {
46-
if cv, ok := constTable[valueExpr.Name]; ok {
47-
if expr, ok = cv.Value.(ast.Expr); ok {
48-
value, evalType := evaluateConstValue(valueExpr.Name, cv.Name.Obj.Data.(int), expr, constTable, recursiveStack)
49-
if cv.Type == nil {
50-
cv.Type = evalType
51-
}
52-
if value != nil {
53-
cv.Value = value
54-
}
55-
return value, evalType
56-
}
57-
return cv.Value, cv.Type
58-
}
59-
}
60-
case *ast.BasicLit:
61-
switch valueExpr.Kind {
62-
case token.INT:
63-
x, err := strconv.ParseInt(valueExpr.Value, 10, 64)
64-
if err != nil {
65-
return nil, nil
66-
}
67-
return int(x), nil
68-
case token.STRING, token.CHAR:
69-
return valueExpr.Value[1 : len(valueExpr.Value)-1], nil
70-
}
71-
case *ast.UnaryExpr:
72-
x, evalType := evaluateConstValue("", iota, valueExpr.X, constTable, recursiveStack)
73-
switch valueExpr.Op {
74-
case token.SUB:
75-
return -x.(int), evalType
76-
case token.XOR:
77-
return ^(x.(int)), evalType
78-
}
79-
case *ast.BinaryExpr:
80-
x, evalTypex := evaluateConstValue("", iota, valueExpr.X, constTable, recursiveStack)
81-
y, evalTypey := evaluateConstValue("", iota, valueExpr.Y, constTable, recursiveStack)
82-
evalType := evalTypex
83-
if evalType == nil {
84-
evalType = evalTypey
85-
}
86-
switch valueExpr.Op {
87-
case token.ADD:
88-
if ix, ok := x.(int); ok {
89-
return ix + y.(int), evalType
90-
} else if sx, ok := x.(string); ok {
91-
return sx + y.(string), evalType
92-
}
93-
case token.SUB:
94-
return x.(int) - y.(int), evalType
95-
case token.MUL:
96-
return x.(int) * y.(int), evalType
97-
case token.QUO:
98-
return x.(int) / y.(int), evalType
99-
case token.REM:
100-
return x.(int) % y.(int), evalType
101-
case token.AND:
102-
return x.(int) & y.(int), evalType
103-
case token.OR:
104-
return x.(int) | y.(int), evalType
105-
case token.XOR:
106-
return x.(int) ^ y.(int), evalType
107-
case token.SHL:
108-
return x.(int) << y.(int), evalType
109-
case token.SHR:
110-
return x.(int) >> y.(int), evalType
111-
}
112-
case *ast.ParenExpr:
113-
return evaluateConstValue("", iota, valueExpr.X, constTable, recursiveStack)
114-
case *ast.CallExpr:
115-
//data conversion
116-
if ident, ok := valueExpr.Fun.(*ast.Ident); ok && len(valueExpr.Args) == 1 && IsGolangPrimitiveType(ident.Name) {
117-
arg, _ := evaluateConstValue("", iota, valueExpr.Args[0], constTable, recursiveStack)
118-
return arg, nil
119-
}
120-
}
121-
return nil, nil
13+
File *ast.File
14+
Pkg *PackageDefinitions
12215
}

enums.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const (
55
enumCommentsExtension = "x-enum-comments"
66
)
77

8-
// EnumValue a model to record an enum const variable
8+
// EnumValue a model to record an enum consts variable
99
type EnumValue struct {
1010
key string
1111
Value interface{}

gen/gen.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ func (g *Gen) Build(config *Config) error {
162162

163163
g.debug.Printf("Generate swagger docs....")
164164

165-
p := swag.New(swag.SetMarkdownFileDirectory(config.MarkdownFilesDir),
165+
p := swag.New(
166+
swag.SetParseDependency(config.ParseDependency),
167+
swag.SetMarkdownFileDirectory(config.MarkdownFilesDir),
166168
swag.SetDebugger(config.Debugger),
167169
swag.SetExcludedDirsAndFiles(config.Excludes),
168170
swag.SetCodeExamplesDirectory(config.CodeExampleFilesDir),
@@ -174,7 +176,6 @@ func (g *Gen) Build(config *Config) error {
174176

175177
p.PropNamingStrategy = config.PropNamingStrategy
176178
p.ParseVendor = config.ParseVendor
177-
p.ParseDependency = config.ParseDependency
178179
p.ParseInternal = config.ParseInternal
179180
p.RequiredByDefault = config.RequiredByDefault
180181

generics.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (t *genericTypeSpec) TypeName() string {
2626
return t.Name
2727
}
2828

29-
func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, original *TypeSpecDef, fullGenericForm string, parseDependency bool) *TypeSpecDef {
29+
func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, original *TypeSpecDef, fullGenericForm string) *TypeSpecDef {
3030
if original == nil || original.TypeSpec.TypeParams == nil || len(original.TypeSpec.TypeParams.List) == 0 {
3131
return original
3232
}
@@ -51,7 +51,7 @@ func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, origi
5151
arrayDepth++
5252
}
5353

54-
typeDef := pkgDefs.FindTypeSpec(genericParam, file, parseDependency)
54+
typeDef := pkgDefs.FindTypeSpec(genericParam, file)
5555
if typeDef != nil {
5656
genericParam = typeDef.TypeName()
5757
if _, ok := pkgDefs.uniqueDefinitions[genericParam]; !ok {
@@ -95,7 +95,7 @@ func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, origi
9595
NamePos: original.TypeSpec.Name.NamePos,
9696
Obj: original.TypeSpec.Name.Obj,
9797
},
98-
Type: pkgDefs.resolveGenericType(original.File, original.TypeSpec.Type, genericParamTypeDefs, parseDependency),
98+
Type: pkgDefs.resolveGenericType(original.File, original.TypeSpec.Type, genericParamTypeDefs),
9999
Doc: original.TypeSpec.Doc,
100100
Assign: original.TypeSpec.Assign,
101101
},
@@ -159,7 +159,7 @@ func (pkgDefs *PackagesDefinitions) getParametrizedType(genTypeSpec *genericType
159159
return &ast.Ident{Name: genTypeSpec.Name}
160160
}
161161

162-
func (pkgDefs *PackagesDefinitions) resolveGenericType(file *ast.File, expr ast.Expr, genericParamTypeDefs map[string]*genericTypeSpec, parseDependency bool) ast.Expr {
162+
func (pkgDefs *PackagesDefinitions) resolveGenericType(file *ast.File, expr ast.Expr, genericParamTypeDefs map[string]*genericTypeSpec) ast.Expr {
163163
switch astExpr := expr.(type) {
164164
case *ast.Ident:
165165
if genTypeSpec, ok := genericParamTypeDefs[astExpr.Name]; ok {
@@ -171,18 +171,18 @@ func (pkgDefs *PackagesDefinitions) resolveGenericType(file *ast.File, expr ast.
171171
}
172172
case *ast.ArrayType:
173173
return &ast.ArrayType{
174-
Elt: pkgDefs.resolveGenericType(file, astExpr.Elt, genericParamTypeDefs, parseDependency),
174+
Elt: pkgDefs.resolveGenericType(file, astExpr.Elt, genericParamTypeDefs),
175175
Len: astExpr.Len,
176176
Lbrack: astExpr.Lbrack,
177177
}
178178
case *ast.StarExpr:
179179
return &ast.StarExpr{
180180
Star: astExpr.Star,
181-
X: pkgDefs.resolveGenericType(file, astExpr.X, genericParamTypeDefs, parseDependency),
181+
X: pkgDefs.resolveGenericType(file, astExpr.X, genericParamTypeDefs),
182182
}
183183
case *ast.IndexExpr, *ast.IndexListExpr:
184184
fullGenericName, _ := getGenericFieldType(file, expr, genericParamTypeDefs)
185-
typeDef := pkgDefs.FindTypeSpec(fullGenericName, file, parseDependency)
185+
typeDef := pkgDefs.FindTypeSpec(fullGenericName, file)
186186
if typeDef != nil {
187187
return typeDef.TypeSpec.Type
188188
}
@@ -205,7 +205,7 @@ func (pkgDefs *PackagesDefinitions) resolveGenericType(file *ast.File, expr ast.
205205
Comment: field.Comment,
206206
}
207207

208-
newField.Type = pkgDefs.resolveGenericType(file, field.Type, genericParamTypeDefs, parseDependency)
208+
newField.Type = pkgDefs.resolveGenericType(file, field.Type, genericParamTypeDefs)
209209

210210
newStructTypeDef.Fields.List = append(newStructTypeDef.Fields.List, newField)
211211
}

generics_other.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type genericTypeSpec struct {
1515
Name string
1616
}
1717

18-
func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, original *TypeSpecDef, fullGenericForm string, parseDependency bool) *TypeSpecDef {
18+
func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, original *TypeSpecDef, fullGenericForm string) *TypeSpecDef {
1919
return original
2020
}
2121

generics_other_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ func TestParametrizeStruct(t *testing.T) {
3232
},
3333
}
3434

35-
tr := pd.parametrizeGenericType(&ast.File{}, tSpec, "", false)
35+
tr := pd.parametrizeGenericType(&ast.File{}, tSpec, "")
3636
assert.Equal(t, tr, tSpec)
3737

38-
tr = pd.parametrizeGenericType(&ast.File{}, tSpec, "", true)
38+
tr = pd.parametrizeGenericType(&ast.File{}, tSpec, "")
3939
assert.Equal(t, tr, tSpec)
4040
}
4141

generics_test.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ func TestParseGenericsPackageAlias(t *testing.T) {
110110
expected, err := os.ReadFile(filepath.Join(searchDir, "expected.json"))
111111
assert.NoError(t, err)
112112

113-
p := New()
114-
p.ParseDependency = true
113+
p := New(SetParseDependency(true))
115114
err = p.ParseAPI(searchDir, mainAPIFile, defaultParseDepth)
116115
assert.NoError(t, err)
117116
b, err := json.MarshalIndent(p.swagger, "", " ")
@@ -133,7 +132,7 @@ func TestParametrizeStruct(t *testing.T) {
133132
Name: &ast.Ident{Name: "Field"},
134133
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
135134
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
136-
}}, "test.Field[string, []string]", false)
135+
}}, "test.Field[string, []string]")
137136
assert.NotNil(t, typeSpec)
138137
assert.Equal(t, "$test.Field-string-array_string", typeSpec.Name())
139138
assert.Equal(t, "test.Field-string-array_string", typeSpec.TypeName())
@@ -146,7 +145,7 @@ func TestParametrizeStruct(t *testing.T) {
146145
Name: &ast.Ident{Name: "Field"},
147146
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}}},
148147
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
149-
}}, "test.Field[string, string]", false)
148+
}}, "test.Field[string, string]")
150149
assert.Nil(t, typeSpec)
151150

152151
// definition contains two type params, but only one is used
@@ -157,7 +156,7 @@ func TestParametrizeStruct(t *testing.T) {
157156
Name: &ast.Ident{Name: "Field"},
158157
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
159158
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
160-
}}, "test.Field[string]", false)
159+
}}, "test.Field[string]")
161160
assert.Nil(t, typeSpec)
162161

163162
// name is not a valid type name
@@ -168,7 +167,7 @@ func TestParametrizeStruct(t *testing.T) {
168167
Name: &ast.Ident{Name: "Field"},
169168
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
170169
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
171-
}}, "test.Field[string", false)
170+
}}, "test.Field[string")
172171
assert.Nil(t, typeSpec)
173172

174173
typeSpec = pd.parametrizeGenericType(
@@ -178,7 +177,7 @@ func TestParametrizeStruct(t *testing.T) {
178177
Name: &ast.Ident{Name: "Field"},
179178
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
180179
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
181-
}}, "test.Field[string, [string]", false)
180+
}}, "test.Field[string, [string]")
182181
assert.Nil(t, typeSpec)
183182

184183
typeSpec = pd.parametrizeGenericType(
@@ -188,7 +187,7 @@ func TestParametrizeStruct(t *testing.T) {
188187
Name: &ast.Ident{Name: "Field"},
189188
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
190189
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
191-
}}, "test.Field[string, ]string]", false)
190+
}}, "test.Field[string, ]string]")
192191
assert.Nil(t, typeSpec)
193192
}
194193

0 commit comments

Comments
 (0)