forked from mitch000001/go-hbci
-
Notifications
You must be signed in to change notification settings - Fork 0
/
segment_field_visitor.go
118 lines (111 loc) · 3.26 KB
/
segment_field_visitor.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
package generator
import (
"fmt"
"go/ast"
"go/token"
)
const segmentElementsMethodIdentifier = "elements"
const segmentElementsMethodReturnType = "[]element.DataElement"
type elementVisitor struct {
receiverName string
fileSet *token.FileSet
object *ast.Object
fields []field
err error
}
func (e *elementVisitor) Visit(node ast.Node) ast.Visitor {
if funcDecl, ok := node.(*ast.FuncDecl); ok {
if e.isElementsMethod(funcDecl) {
bodyStatements := funcDecl.Body.List
if len(bodyStatements) == 1 {
if ret, ok := bodyStatements[0].(*ast.ReturnStmt); ok {
if len(ret.Results) == 1 {
if res, ok := ret.Results[0].(*ast.CompositeLit); ok {
resType := nodeToString(res.Type, e.fileSet)
if resType == segmentElementsMethodReturnType {
for _, element := range res.Elts {
if sel, ok := element.(*ast.SelectorExpr); ok {
pos := sel.Pos()
position := e.fileSet.Position(pos)
elemField := field{Name: sel.Sel.Name, Line: position.Line}
if _, ok := sel.X.(*ast.Ident); ok {
fieldVisitor := &structFieldVisitor{fileSet: e.fileSet, fieldName: sel.Sel.Name}
ast.Walk(fieldVisitor, e.object.Decl.(*ast.TypeSpec))
if fieldVisitor.err != nil {
e.err = fieldVisitor.err
return nil
}
elemField.TypeDecl = fieldVisitor.fieldTypeDecl
} else {
e.err = fmt.Errorf("Unexpected Selector: %q", nodeToString(sel, e.fileSet))
return nil
}
if elemField.TypeDecl == "" {
e.err = fmt.Errorf("No type declaration found for element %q", sel.Sel.Name)
return nil
}
e.fields = append(e.fields, elemField)
} else {
e.err = fmt.Errorf("Unsupported element in elements method: %q", nodeToString(element, e.fileSet))
return nil
}
}
return nil
}
}
}
}
}
}
}
return e
}
func (e *elementVisitor) isElementsMethod(funcDecl *ast.FuncDecl) bool {
if funcDecl.Name.Name == segmentElementsMethodIdentifier {
if funcDecl.Recv != nil {
if fields := funcDecl.Recv.List; fields != nil {
if len(fields) == 1 {
if typ, ok := fields[0].Type.(*ast.StarExpr); ok {
if ident, ok := typ.X.(*ast.Ident); ok {
if ident.Name == e.receiverName {
return true
}
}
}
}
}
}
}
return false
}
type structFieldVisitor struct {
fileSet *token.FileSet
fieldName string
fieldTypeDecl string
err error
}
func (s *structFieldVisitor) Visit(node ast.Node) ast.Visitor {
if structType, ok := node.(*ast.StructType); ok {
if fields := structType.Fields; fields != nil {
for _, f := range fields.List {
var fieldName string
if names := f.Names; names != nil {
fieldName = nodeToString(names[0], s.fileSet)
if fieldName != s.fieldName {
continue // not the field we're looking for
}
} else {
continue // anonymous field
}
if starExpr, ok := f.Type.(*ast.StarExpr); ok {
s.fieldTypeDecl = nodeToString(starExpr.X, s.fileSet)
} else {
s.err = fmt.Errorf("Unexpected type found: %q", nodeToString(f.Type, s.fileSet))
return nil
}
}
return nil
}
}
return s
}