Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / loader / loader.go
1 package loader
2
3 import (
4         "errors"
5         "fmt"
6         "go/ast"
7         "go/parser"
8         "go/scanner"
9         "go/token"
10         "go/types"
11         "log"
12         "os"
13
14         "golang.org/x/tools/go/gcexportdata"
15         "golang.org/x/tools/go/packages"
16 )
17
18 // Graph resolves patterns and returns packages with all the
19 // information required to later load type information, and optionally
20 // syntax trees.
21 //
22 // The provided config can set any setting with the exception of Mode.
23 func Graph(cfg packages.Config, patterns ...string) ([]*packages.Package, error) {
24         cfg.Mode = packages.NeedName | packages.NeedImports | packages.NeedDeps | packages.NeedExportsFile | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedTypesSizes
25         pkgs, err := packages.Load(&cfg, patterns...)
26         if err != nil {
27                 return nil, err
28         }
29         fset := token.NewFileSet()
30         packages.Visit(pkgs, nil, func(pkg *packages.Package) {
31                 pkg.Fset = fset
32         })
33
34         n := 0
35         for _, pkg := range pkgs {
36                 if len(pkg.CompiledGoFiles) == 0 && len(pkg.Errors) == 0 && pkg.PkgPath != "unsafe" {
37                         // If a package consists only of test files, then
38                         // go/packages incorrectly(?) returns an empty package for
39                         // the non-test variant. Get rid of those packages. See
40                         // #646.
41                         //
42                         // Do not, however, skip packages that have errors. Those,
43                         // too, may have no files, but we want to print the
44                         // errors.
45                         continue
46                 }
47                 pkgs[n] = pkg
48                 n++
49         }
50         return pkgs[:n], nil
51 }
52
53 // LoadFromExport loads a package from export data. All of its
54 // dependencies must have been loaded already.
55 func LoadFromExport(pkg *packages.Package) error {
56         pkg.IllTyped = true
57         for path, pkg := range pkg.Imports {
58                 if pkg.Types == nil {
59                         return fmt.Errorf("dependency %q hasn't been loaded yet", path)
60                 }
61         }
62         if pkg.ExportFile == "" {
63                 return fmt.Errorf("no export data for %q", pkg.ID)
64         }
65         f, err := os.Open(pkg.ExportFile)
66         if err != nil {
67                 return err
68         }
69         defer f.Close()
70
71         r, err := gcexportdata.NewReader(f)
72         if err != nil {
73                 return err
74         }
75
76         view := make(map[string]*types.Package)  // view seen by gcexportdata
77         seen := make(map[*packages.Package]bool) // all visited packages
78         var visit func(pkgs map[string]*packages.Package)
79         visit = func(pkgs map[string]*packages.Package) {
80                 for _, pkg := range pkgs {
81                         if !seen[pkg] {
82                                 seen[pkg] = true
83                                 view[pkg.PkgPath] = pkg.Types
84                                 visit(pkg.Imports)
85                         }
86                 }
87         }
88         visit(pkg.Imports)
89         tpkg, err := gcexportdata.Read(r, pkg.Fset, view, pkg.PkgPath)
90         if err != nil {
91                 return err
92         }
93         pkg.Types = tpkg
94         pkg.IllTyped = false
95         return nil
96 }
97
98 // LoadFromSource loads a package from source. All of its dependencies
99 // must have been loaded already.
100 func LoadFromSource(pkg *packages.Package) error {
101         pkg.IllTyped = true
102         pkg.Types = types.NewPackage(pkg.PkgPath, pkg.Name)
103
104         // OPT(dh): many packages have few files, much fewer than there
105         // are CPU cores. Additionally, parsing each individual file is
106         // very fast. A naive parallel implementation of this loop won't
107         // be faster, and tends to be slower due to extra scheduling,
108         // bookkeeping and potentially false sharing of cache lines.
109         pkg.Syntax = make([]*ast.File, len(pkg.CompiledGoFiles))
110         for i, file := range pkg.CompiledGoFiles {
111                 f, err := parser.ParseFile(pkg.Fset, file, nil, parser.ParseComments)
112                 if err != nil {
113                         pkg.Errors = append(pkg.Errors, convertError(err)...)
114                         return err
115                 }
116                 pkg.Syntax[i] = f
117         }
118         pkg.TypesInfo = &types.Info{
119                 Types:      make(map[ast.Expr]types.TypeAndValue),
120                 Defs:       make(map[*ast.Ident]types.Object),
121                 Uses:       make(map[*ast.Ident]types.Object),
122                 Implicits:  make(map[ast.Node]types.Object),
123                 Scopes:     make(map[ast.Node]*types.Scope),
124                 Selections: make(map[*ast.SelectorExpr]*types.Selection),
125         }
126
127         importer := func(path string) (*types.Package, error) {
128                 if path == "unsafe" {
129                         return types.Unsafe, nil
130                 }
131                 if path == "C" {
132                         // go/packages doesn't tell us that cgo preprocessing
133                         // failed. When we subsequently try to parse the package,
134                         // we'll encounter the raw C import.
135                         return nil, errors.New("cgo preprocessing failed")
136                 }
137                 imp := pkg.Imports[path]
138                 if imp == nil {
139                         return nil, nil
140                 }
141                 if len(imp.Errors) > 0 {
142                         return nil, imp.Errors[0]
143                 }
144                 return imp.Types, nil
145         }
146         tc := &types.Config{
147                 Importer: importerFunc(importer),
148                 Error: func(err error) {
149                         pkg.Errors = append(pkg.Errors, convertError(err)...)
150                 },
151         }
152         err := types.NewChecker(tc, pkg.Fset, pkg.Types, pkg.TypesInfo).Files(pkg.Syntax)
153         if err != nil {
154                 return err
155         }
156         pkg.IllTyped = false
157         return nil
158 }
159
160 func convertError(err error) []packages.Error {
161         var errs []packages.Error
162         // taken from go/packages
163         switch err := err.(type) {
164         case packages.Error:
165                 // from driver
166                 errs = append(errs, err)
167
168         case *os.PathError:
169                 // from parser
170                 errs = append(errs, packages.Error{
171                         Pos:  err.Path + ":1",
172                         Msg:  err.Err.Error(),
173                         Kind: packages.ParseError,
174                 })
175
176         case scanner.ErrorList:
177                 // from parser
178                 for _, err := range err {
179                         errs = append(errs, packages.Error{
180                                 Pos:  err.Pos.String(),
181                                 Msg:  err.Msg,
182                                 Kind: packages.ParseError,
183                         })
184                 }
185
186         case types.Error:
187                 // from type checker
188                 errs = append(errs, packages.Error{
189                         Pos:  err.Fset.Position(err.Pos).String(),
190                         Msg:  err.Msg,
191                         Kind: packages.TypeError,
192                 })
193
194         default:
195                 // unexpected impoverished error from parser?
196                 errs = append(errs, packages.Error{
197                         Pos:  "-",
198                         Msg:  err.Error(),
199                         Kind: packages.UnknownError,
200                 })
201
202                 // If you see this error message, please file a bug.
203                 log.Printf("internal error: error %q (%T) without position", err, err)
204         }
205         return errs
206 }
207
208 type importerFunc func(path string) (*types.Package, error)
209
210 func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) }