GoPLS Viewer

Home|gopls/go/loader/util.go
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
5package loader
6
7import (
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// We use a counting semaphore to limit
21// the number of parallel I/O calls per process.
22var ioLimit = make(chan bool10)
23
24// parseFiles parses the Go source files within directory dir and
25// returns the ASTs of the ones that could be at least partially parsed,
26// along with a list of I/O and parse errors encountered.
27//
28// I/O is done via ctxt, which may specify a virtual file system.
29// displayPath is used to transform the filenames attached to the ASTs.
30func parseFiles(fset *token.FileSetctxt *build.ContextdisplayPath func(stringstringdir stringfiles []stringmode parser.Mode) ([]*ast.File, []error) {
31    if displayPath == nil {
32        displayPath = func(path stringstring { return path }
33    }
34    var wg sync.WaitGroup
35    n := len(files)
36    parsed := make([]*ast.Filen)
37    errors := make([]errorn)
38    for ifile := range files {
39        if !buildutil.IsAbsPath(ctxtfile) {
40            file = buildutil.JoinPath(ctxtdirfile)
41        }
42        wg.Add(1)
43        go func(i intfile string) {
44            ioLimit <- true // wait
45            defer func() {
46                wg.Done()
47                <-ioLimit // signal
48            }()
49            var rd io.ReadCloser
50            var err error
51            if ctxt.OpenFile != nil {
52                rderr = ctxt.OpenFile(file)
53            } else {
54                rderr = os.Open(file)
55            }
56            if err != nil {
57                errors[i] = err // open failed
58                return
59            }
60
61            // ParseFile may return both an AST and an error.
62            parsed[i], errors[i] = parser.ParseFile(fsetdisplayPath(file), rdmode)
63            rd.Close()
64        }(ifile)
65    }
66    wg.Wait()
67
68    // Eliminate nils, preserving order.
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 parsederrors
88}
89
90// scanImports returns the set of all import paths from all
91// import specs in the specified files.
92func 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 declok := decl.(*ast.GenDecl); ok && decl.Tok == token.IMPORT {
97                for _spec := range decl.Specs {
98                    spec := spec.(*ast.ImportSpec)
99
100                    // NB: do not assume the program is well-formed!
101                    patherr := strconv.Unquote(spec.Path.Value)
102                    if err != nil {
103                        continue // quietly ignore the error
104                    }
105                    if path == "C" {
106                        continue // skip pseudopackage
107                    }
108                    imports[path] = true
109                }
110            }
111        }
112    }
113    return imports
114}
115
116// ---------- Internal helpers ----------
117
118// TODO(adonovan): make this a method: func (*token.File) Contains(token.Pos)
119func tokenFileContainsPos(f *token.Filepos token.Posbool {
120    p := int(pos)
121    base := f.Base()
122    return base <= p && p < base+f.Size()
123}
124
MembersX
parseFiles
parseFiles.n
parseFiles.parsed
scanImports
parseFiles.displayPath
parseFiles.RangeStmt_1113.i
parseFiles.RangeStmt_1809.f
tokenFileContainsPos
tokenFileContainsPos.f
parseFiles.dir
parseFiles.files
parseFiles.RangeStmt_1913.err
parseFiles.fset
parseFiles.ctxt
parseFiles.errors
parseFiles.RangeStmt_1113.file
scanImports.RangeStmt_2230.f
scanImports.RangeStmt_2230.BlockStmt.RangeStmt_2258.BlockStmt.BlockStmt.RangeStmt_2365.BlockStmt.err
tokenFileContainsPos.base
io
strconv
parseFiles.mode
scanImports.files
scanImports.imports
scanImports.RangeStmt_2230.BlockStmt.RangeStmt_2258.BlockStmt.BlockStmt.RangeStmt_2365.spec
parseFiles.RangeStmt_1113.BlockStmt.BlockStmt.rd
parseFiles.RangeStmt_1113.BlockStmt.BlockStmt.err
scanImports.RangeStmt_2230.BlockStmt.RangeStmt_2258.BlockStmt.BlockStmt.RangeStmt_2365.BlockStmt.path
tokenFileContainsPos.pos
parseFiles.o
scanImports.RangeStmt_2230.BlockStmt.RangeStmt_2258.decl
tokenFileContainsPos.p
parseFiles.wg
Members
X