...
1
2
3
4
5 package loader
6
7 import (
8 "go/ast"
9 "go/build"
10 "go/parser"
11 "go/token"
12 "io"
13 "os"
14 "strconv"
15 "sync"
16
17 "golang.org/x/tools/go/buildutil"
18 )
19
20
21
22 var ioLimit = make(chan bool, 10)
23
24
25
26
27
28
29
30 func parseFiles(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, files []string, mode parser.Mode) ([]*ast.File, []error) {
31 if displayPath == nil {
32 displayPath = func(path string) string { return path }
33 }
34 var wg sync.WaitGroup
35 n := len(files)
36 parsed := make([]*ast.File, n)
37 errors := make([]error, n)
38 for i, file := range files {
39 if !buildutil.IsAbsPath(ctxt, file) {
40 file = buildutil.JoinPath(ctxt, dir, file)
41 }
42 wg.Add(1)
43 go func(i int, file string) {
44 ioLimit <- true
45 defer func() {
46 wg.Done()
47 <-ioLimit
48 }()
49 var rd io.ReadCloser
50 var err error
51 if ctxt.OpenFile != nil {
52 rd, err = ctxt.OpenFile(file)
53 } else {
54 rd, err = os.Open(file)
55 }
56 if err != nil {
57 errors[i] = err
58 return
59 }
60
61
62 parsed[i], errors[i] = parser.ParseFile(fset, displayPath(file), rd, mode)
63 rd.Close()
64 }(i, file)
65 }
66 wg.Wait()
67
68
69 var o int
70 for _, f := range parsed {
71 if f != nil {
72 parsed[o] = f
73 o++
74 }
75 }
76 parsed = parsed[:o]
77
78 o = 0
79 for _, err := range errors {
80 if err != nil {
81 errors[o] = err
82 o++
83 }
84 }
85 errors = errors[:o]
86
87 return parsed, errors
88 }
89
90
91
92 func scanImports(files []*ast.File) map[string]bool {
93 imports := make(map[string]bool)
94 for _, f := range files {
95 for _, decl := range f.Decls {
96 if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
97 for _, spec := range decl.Specs {
98 spec := spec.(*ast.ImportSpec)
99
100
101 path, err := strconv.Unquote(spec.Path.Value)
102 if err != nil {
103 continue
104 }
105 if path == "C" {
106 continue
107 }
108 imports[path] = true
109 }
110 }
111 }
112 }
113 return imports
114 }
115
116
117
118
119 func tokenFileContainsPos(f *token.File, pos token.Pos) bool {
120 p := int(pos)
121 base := f.Base()
122 return base <= p && p < base+f.Size()
123 }
124
View as plain text