github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/loader/util.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 "llvm.org/llgo/third_party/gotools/go/buildutil" 18 ) 19 20 // parseFiles parses the Go source files within directory dir and 21 // returns the ASTs of the ones that could be at least partially parsed, 22 // along with a list of I/O and parse errors encountered. 23 // 24 // I/O is done via ctxt, which may specify a virtual file system. 25 // displayPath is used to transform the filenames attached to the ASTs. 26 // 27 func parseFiles(fset *token.FileSet, ctxt *build.Context, displayPath func(string) string, dir string, files []string, mode parser.Mode) ([]*ast.File, []error) { 28 if displayPath == nil { 29 displayPath = func(path string) string { return path } 30 } 31 var wg sync.WaitGroup 32 n := len(files) 33 parsed := make([]*ast.File, n) 34 errors := make([]error, n) 35 for i, file := range files { 36 if !buildutil.IsAbsPath(ctxt, file) { 37 file = buildutil.JoinPath(ctxt, dir, file) 38 } 39 wg.Add(1) 40 go func(i int, file string) { 41 defer wg.Done() 42 var rd io.ReadCloser 43 var err error 44 if ctxt.OpenFile != nil { 45 rd, err = ctxt.OpenFile(file) 46 } else { 47 rd, err = os.Open(file) 48 } 49 if err != nil { 50 errors[i] = err // open failed 51 return 52 } 53 54 // ParseFile may return both an AST and an error. 55 parsed[i], errors[i] = parser.ParseFile(fset, displayPath(file), rd, mode) 56 rd.Close() 57 }(i, file) 58 } 59 wg.Wait() 60 61 // Eliminate nils, preserving order. 62 var o int 63 for _, f := range parsed { 64 if f != nil { 65 parsed[o] = f 66 o++ 67 } 68 } 69 parsed = parsed[:o] 70 71 o = 0 72 for _, err := range errors { 73 if err != nil { 74 errors[o] = err 75 o++ 76 } 77 } 78 errors = errors[:o] 79 80 return parsed, errors 81 } 82 83 // scanImports returns the set of all package import paths from all 84 // import specs in the specified files. 85 func scanImports(files []*ast.File) map[string]bool { 86 imports := make(map[string]bool) 87 for _, f := range files { 88 for _, decl := range f.Decls { 89 if decl, ok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT { 90 for _, spec := range decl.Specs { 91 spec := spec.(*ast.ImportSpec) 92 93 // NB: do not assume the program is well-formed! 94 path, err := strconv.Unquote(spec.Path.Value) 95 if err != nil { 96 continue // quietly ignore the error 97 } 98 if path == "C" || path == "unsafe" { 99 continue // skip pseudo packages 100 } 101 imports[path] = true 102 } 103 } 104 } 105 } 106 return imports 107 } 108 109 // ---------- Internal helpers ---------- 110 111 // TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos) 112 func tokenFileContainsPos(f *token.File, pos token.Pos) bool { 113 p := int(pos) 114 base := f.Base() 115 return base <= p && p < base+f.Size() 116 }