-
Notifications
You must be signed in to change notification settings - Fork 0
/
util.go
154 lines (138 loc) · 3.36 KB
/
util.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"path/filepath"
"strconv"
"strings"
)
var fset *token.FileSet
func getImports(dir string) *DepSet {
var pf *ast.File
var err error
fset = token.NewFileSet()
files := getGoFiles(dir)
dset := NewDepSet()
for _, file := range files {
if showCalls == true {
pf, err = parser.ParseFile(fset, file, nil, 0)
// Build a map with the imports mapping to the files
for _, s := range pf.Imports {
pname := strings.Trim(s.Path.Value, "\"")
if debug {
fmt.Printf("Import found: %s imports %s\n", file, pname)
}
dset.AddImport(pname, file)
}
if debug {
for _, pkg := range dset.Packages() {
fmt.Printf("Imported: %s\n", pkg)
}
}
// ast.Inspect(pf, parseCalls)
ast.Walk(finder{
find: findCalls,
dset: dset,
}, pf)
} else {
pf, err = parser.ParseFile(fset, file, nil, parser.ImportsOnly)
// Build a map with the imports mapping to the files
for _, s := range pf.Imports {
pname := strings.Trim(s.Path.Value, "\"")
dset.AddImport(pname, file)
}
}
if err != nil {
// fmt.Println(err)
}
/*
* We'll need to AND the imports and the keys in the
* package calls map to trim out keys from the latter
* which are not actually packages.
* We also need to figure out how to account for methods -
* since the qualifier (X node) in those cases is the
* method receiver, not the package.
*/
}
return dset
}
func getGoFiles(dir string) []string {
var flist []string
files, err := ioutil.ReadDir(dir)
if err != nil {
return nil
}
for _, f := range files {
if strings.HasSuffix(f.Name(), ".go") == true {
fullpath := filepath.Join(dir, f.Name())
flist = append(flist, fullpath)
}
}
return flist
}
/*
* Below here is the plumbing to use with ast.Walk()
*/
/*
* findCalls() parses the node passed in and, if it's a
* SelectorExpr (which any call to a function/method will be)
* populates the map passed in as the second argument.
* This is the function used for finder.find().
*
* Functions will have the package as the X node,
* whereas methods will have the object identifier as the
* X. We do not differentiate in this function (there
* really isn't a good way without access to the list of
* imports and identifiers, so that has to be done higher up
* the stack).
*/
func findCalls(n ast.Node, f *finder) bool {
switch x := n.(type) {
case *ast.File:
locfields := strings.Split(fset.Position(n.Pos()).String(), ":")
f.currentFile = locfields[0]
case *ast.SelectorExpr:
switch y := x.X.(type) {
case *ast.Ident:
locfields := strings.Split(fset.Position(y.NamePos).String(), ":")
ln, err := strconv.Atoi(locfields[1])
if err != nil {
ln = -1
}
f.dset.AddPackageCall(Call{
Qual: y.Name,
Sel: x.Sel.Name,
// Location: y.NamePos,
Line: ln,
}, f.currentFile, true)
default:
return true
} // END switch y :=
default:
return true
} // END switch x :=
return true
}
/*
* finder is a struct which implements the ast.Visitor interface.
*/
type finder struct {
find func(ast.Node, *finder) bool
dset *DepSet
currentFile string
}
// func (f *finder) Calls() []Call {
// return f.calls
// }
func (f *finder) DepSet() *DepSet {
return f.dset
}
func (f finder) Visit(node ast.Node) ast.Visitor {
if f.find(node, &f) {
return f
}
return nil
}