-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecl.go
119 lines (103 loc) · 2.8 KB
/
decl.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package mingo
import (
"go/ast"
"github.com/bobg/errors"
)
// Bool result tells whether the max known Go version has been reached.
func (p *pkgScanner) decl(decl ast.Decl) (bool, error) {
switch decl := decl.(type) {
case *ast.FuncDecl:
return p.funcDecl(decl)
case *ast.GenDecl:
return p.genDecl(decl)
}
return false, nil
}
func (p *pkgScanner) funcDecl(decl *ast.FuncDecl) (bool, error) {
if isMax, err := p.fieldList(decl.Recv); err != nil || isMax {
return isMax, errors.Wrapf(err, "scanning receiver for func %s", decl.Name.Name)
}
// Generics are supported in Go 1.18 and later.
if decl.Type.TypeParams != nil && len(decl.Type.TypeParams.List) > 0 {
p.result(posResult{
version: 18,
pos: p.fset.Position(decl.Pos()),
desc: "generic func decl",
})
}
if isMax, err := p.fieldList(decl.Type.Params); err != nil || isMax {
return isMax, errors.Wrapf(err, "scanning params for func %s", decl.Name.Name)
}
if isMax, err := p.fieldList(decl.Type.Results); err != nil || isMax {
return false, errors.Wrapf(err, "scanning results for func %s", decl.Name.Name)
}
return p.funcBody(decl.Body)
}
func (p *pkgScanner) fieldList(list *ast.FieldList) (bool, error) {
if list == nil {
return false, nil
}
for _, field := range list.List {
if isMax, err := p.field(field); err != nil || isMax {
return isMax, err
}
}
return false, nil
}
func (p *pkgScanner) field(field *ast.Field) (bool, error) {
return p.expr(field.Type)
}
func (p *pkgScanner) genDecl(decl *ast.GenDecl) (bool, error) {
for _, spec := range decl.Specs {
if isMax, err := p.spec(spec); err != nil || isMax {
return isMax, err
}
}
return false, nil
}
func (p *pkgScanner) spec(spec ast.Spec) (bool, error) {
switch spec := spec.(type) {
case *ast.ValueSpec:
return p.valueSpec(spec)
case *ast.TypeSpec:
return p.typeSpec(spec)
}
return false, nil
}
func (p *pkgScanner) valueSpec(spec *ast.ValueSpec) (bool, error) {
if isMax, err := p.expr(spec.Type); err != nil || isMax {
return isMax, err
}
for _, value := range spec.Values {
if isMax, err := p.expr(value); err != nil || isMax {
return isMax, err
}
}
return false, nil
}
func (p *pkgScanner) typeSpec(spec *ast.TypeSpec) (bool, error) {
if spec.Assign.IsValid() {
if spec.TypeParams != nil && len(spec.TypeParams.List) > 0 {
p.result(posResult{
version: 24,
pos: p.fset.Position(spec.Pos()),
desc: "generic type alias",
})
} else {
p.result(posResult{
version: 9,
pos: p.fset.Position(spec.Pos()),
desc: "type alias",
})
}
}
// Generics are supported in Go 1.18 and later.
if spec.TypeParams != nil && len(spec.TypeParams.List) > 0 {
p.result(posResult{
version: 18,
pos: p.fset.Position(spec.Pos()),
desc: "generic type decl",
})
}
return p.expr(spec.Type)
}