| 1 | // Copyright 2018 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 packages |
| 6 | |
| 7 | // See doc.go for package documentation and implementation notes. |
| 8 | |
| 9 | import ( |
| 10 | "context" |
| 11 | "encoding/json" |
| 12 | "fmt" |
| 13 | "go/ast" |
| 14 | "go/parser" |
| 15 | "go/scanner" |
| 16 | "go/token" |
| 17 | "go/types" |
| 18 | "io" |
| 19 | "io/ioutil" |
| 20 | "log" |
| 21 | "os" |
| 22 | "path/filepath" |
| 23 | "runtime" |
| 24 | "strings" |
| 25 | "sync" |
| 26 | "time" |
| 27 | |
| 28 | "golang.org/x/tools/go/gcexportdata" |
| 29 | "golang.org/x/tools/internal/gocommand" |
| 30 | "golang.org/x/tools/internal/packagesinternal" |
| 31 | "golang.org/x/tools/internal/typeparams" |
| 32 | "golang.org/x/tools/internal/typesinternal" |
| 33 | ) |
| 34 | |
| 35 | // A LoadMode controls the amount of detail to return when loading. |
| 36 | // The bits below can be combined to specify which fields should be |
| 37 | // filled in the result packages. |
| 38 | // The zero value is a special case, equivalent to combining |
| 39 | // the NeedName, NeedFiles, and NeedCompiledGoFiles bits. |
| 40 | // ID and Errors (if present) will always be filled. |
| 41 | // Load may return more information than requested. |
| 42 | type LoadMode int |
| 43 | |
| 44 | const ( |
| 45 | // NeedName adds Name and PkgPath. |
| 46 | NeedName LoadMode = 1 << iota |
| 47 | |
| 48 | // NeedFiles adds GoFiles and OtherFiles. |
| 49 | NeedFiles |
| 50 | |
| 51 | // NeedCompiledGoFiles adds CompiledGoFiles. |
| 52 | NeedCompiledGoFiles |
| 53 | |
| 54 | // NeedImports adds Imports. If NeedDeps is not set, the Imports field will contain |
| 55 | // "placeholder" Packages with only the ID set. |
| 56 | NeedImports |
| 57 | |
| 58 | // NeedDeps adds the fields requested by the LoadMode in the packages in Imports. |
| 59 | NeedDeps |
| 60 | |
| 61 | // NeedExportFile adds ExportFile. |
| 62 | NeedExportFile |
| 63 | |
| 64 | // NeedTypes adds Types, Fset, and IllTyped. |
| 65 | NeedTypes |
| 66 | |
| 67 | // NeedSyntax adds Syntax. |
| 68 | NeedSyntax |
| 69 | |
| 70 | // NeedTypesInfo adds TypesInfo. |
| 71 | NeedTypesInfo |
| 72 | |
| 73 | // NeedTypesSizes adds TypesSizes. |
| 74 | NeedTypesSizes |
| 75 | |
| 76 | // needInternalDepsErrors adds the internal deps errors field for use by gopls. |
| 77 | needInternalDepsErrors |
| 78 | |
| 79 | // needInternalForTest adds the internal forTest field. |
| 80 | // Tests must also be set on the context for this field to be populated. |
| 81 | needInternalForTest |
| 82 | |
| 83 | // typecheckCgo enables full support for type checking cgo. Requires Go 1.15+. |
| 84 | // Modifies CompiledGoFiles and Types, and has no effect on its own. |
| 85 | typecheckCgo |
| 86 | |
| 87 | // NeedModule adds Module. |
| 88 | NeedModule |
| 89 | |
| 90 | // NeedEmbedFiles adds EmbedFiles. |
| 91 | NeedEmbedFiles |
| 92 | |
| 93 | // NeedEmbedPatterns adds EmbedPatterns. |
| 94 | NeedEmbedPatterns |
| 95 | ) |
| 96 | |
| 97 | const ( |
| 98 | // Deprecated: LoadFiles exists for historical compatibility |
| 99 | // and should not be used. Please directly specify the needed fields using the Need values. |
| 100 | LoadFiles = NeedName | NeedFiles | NeedCompiledGoFiles |
| 101 | |
| 102 | // Deprecated: LoadImports exists for historical compatibility |
| 103 | // and should not be used. Please directly specify the needed fields using the Need values. |
| 104 | LoadImports = LoadFiles | NeedImports |
| 105 | |
| 106 | // Deprecated: LoadTypes exists for historical compatibility |
| 107 | // and should not be used. Please directly specify the needed fields using the Need values. |
| 108 | LoadTypes = LoadImports | NeedTypes | NeedTypesSizes |
| 109 | |
| 110 | // Deprecated: LoadSyntax exists for historical compatibility |
| 111 | // and should not be used. Please directly specify the needed fields using the Need values. |
| 112 | LoadSyntax = LoadTypes | NeedSyntax | NeedTypesInfo |
| 113 | |
| 114 | // Deprecated: LoadAllSyntax exists for historical compatibility |
| 115 | // and should not be used. Please directly specify the needed fields using the Need values. |
| 116 | LoadAllSyntax = LoadSyntax | NeedDeps |
| 117 | |
| 118 | // Deprecated: NeedExportsFile is a historical misspelling of NeedExportFile. |
| 119 | NeedExportsFile = NeedExportFile |
| 120 | ) |
| 121 | |
| 122 | // A Config specifies details about how packages should be loaded. |
| 123 | // The zero value is a valid configuration. |
| 124 | // Calls to Load do not modify this struct. |
| 125 | type Config struct { |
| 126 | // Mode controls the level of information returned for each package. |
| 127 | Mode LoadMode |
| 128 | |
| 129 | // Context specifies the context for the load operation. |
| 130 | // If the context is cancelled, the loader may stop early |
| 131 | // and return an ErrCancelled error. |
| 132 | // If Context is nil, the load cannot be cancelled. |
| 133 | Context context.Context |
| 134 | |
| 135 | // Logf is the logger for the config. |
| 136 | // If the user provides a logger, debug logging is enabled. |
| 137 | // If the GOPACKAGESDEBUG environment variable is set to true, |
| 138 | // but the logger is nil, default to log.Printf. |
| 139 | Logf func(format string, args ...interface{}) |
| 140 | |
| 141 | // Dir is the directory in which to run the build system's query tool |
| 142 | // that provides information about the packages. |
| 143 | // If Dir is empty, the tool is run in the current directory. |
| 144 | Dir string |
| 145 | |
| 146 | // Env is the environment to use when invoking the build system's query tool. |
| 147 | // If Env is nil, the current environment is used. |
| 148 | // As in os/exec's Cmd, only the last value in the slice for |
| 149 | // each environment key is used. To specify the setting of only |
| 150 | // a few variables, append to the current environment, as in: |
| 151 | // |
| 152 | // opt.Env = append(os.Environ(), "GOOS=plan9", "GOARCH=386") |
| 153 | // |
| 154 | Env []string |
| 155 | |
| 156 | // gocmdRunner guards go command calls from concurrency errors. |
| 157 | gocmdRunner *gocommand.Runner |
| 158 | |
| 159 | // BuildFlags is a list of command-line flags to be passed through to |
| 160 | // the build system's query tool. |
| 161 | BuildFlags []string |
| 162 | |
| 163 | // modFile will be used for -modfile in go command invocations. |
| 164 | modFile string |
| 165 | |
| 166 | // modFlag will be used for -modfile in go command invocations. |
| 167 | modFlag string |
| 168 | |
| 169 | // Fset provides source position information for syntax trees and types. |
| 170 | // If Fset is nil, Load will use a new fileset, but preserve Fset's value. |
| 171 | Fset *token.FileSet |
| 172 | |
| 173 | // ParseFile is called to read and parse each file |
| 174 | // when preparing a package's type-checked syntax tree. |
| 175 | // It must be safe to call ParseFile simultaneously from multiple goroutines. |
| 176 | // If ParseFile is nil, the loader will uses parser.ParseFile. |
| 177 | // |
| 178 | // ParseFile should parse the source from src and use filename only for |
| 179 | // recording position information. |
| 180 | // |
| 181 | // An application may supply a custom implementation of ParseFile |
| 182 | // to change the effective file contents or the behavior of the parser, |
| 183 | // or to modify the syntax tree. For example, selectively eliminating |
| 184 | // unwanted function bodies can significantly accelerate type checking. |
| 185 | ParseFile func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) |
| 186 | |
| 187 | // If Tests is set, the loader includes not just the packages |
| 188 | // matching a particular pattern but also any related test packages, |
| 189 | // including test-only variants of the package and the test executable. |
| 190 | // |
| 191 | // For example, when using the go command, loading "fmt" with Tests=true |
| 192 | // returns four packages, with IDs "fmt" (the standard package), |
| 193 | // "fmt [fmt.test]" (the package as compiled for the test), |
| 194 | // "fmt_test" (the test functions from source files in package fmt_test), |
| 195 | // and "fmt.test" (the test binary). |
| 196 | // |
| 197 | // In build systems with explicit names for tests, |
| 198 | // setting Tests may have no effect. |
| 199 | Tests bool |
| 200 | |
| 201 | // Overlay provides a mapping of absolute file paths to file contents. |
| 202 | // If the file with the given path already exists, the parser will use the |
| 203 | // alternative file contents provided by the map. |
| 204 | // |
| 205 | // Overlays provide incomplete support for when a given file doesn't |
| 206 | // already exist on disk. See the package doc above for more details. |
| 207 | Overlay map[string][]byte |
| 208 | } |
| 209 | |
| 210 | // driver is the type for functions that query the build system for the |
| 211 | // packages named by the patterns. |
| 212 | type driver func(cfg *Config, patterns ...string) (*driverResponse, error) |
| 213 | |
| 214 | // driverResponse contains the results for a driver query. |
| 215 | type driverResponse struct { |
| 216 | // NotHandled is returned if the request can't be handled by the current |
| 217 | // driver. If an external driver returns a response with NotHandled, the |
| 218 | // rest of the driverResponse is ignored, and go/packages will fallback |
| 219 | // to the next driver. If go/packages is extended in the future to support |
| 220 | // lists of multiple drivers, go/packages will fall back to the next driver. |
| 221 | NotHandled bool |
| 222 | |
| 223 | // Sizes, if not nil, is the types.Sizes to use when type checking. |
| 224 | Sizes *types.StdSizes |
| 225 | |
| 226 | // Roots is the set of package IDs that make up the root packages. |
| 227 | // We have to encode this separately because when we encode a single package |
| 228 | // we cannot know if it is one of the roots as that requires knowledge of the |
| 229 | // graph it is part of. |
| 230 | Roots []string `json:",omitempty"` |
| 231 | |
| 232 | // Packages is the full set of packages in the graph. |
| 233 | // The packages are not connected into a graph. |
| 234 | // The Imports if populated will be stubs that only have their ID set. |
| 235 | // Imports will be connected and then type and syntax information added in a |
| 236 | // later pass (see refine). |
| 237 | Packages []*Package |
| 238 | |
| 239 | // GoVersion is the minor version number used by the driver |
| 240 | // (e.g. the go command on the PATH) when selecting .go files. |
| 241 | // Zero means unknown. |
| 242 | GoVersion int |
| 243 | } |
| 244 | |
| 245 | // Load loads and returns the Go packages named by the given patterns. |
| 246 | // |
| 247 | // Config specifies loading options; |
| 248 | // nil behaves the same as an empty Config. |
| 249 | // |
| 250 | // Load returns an error if any of the patterns was invalid |
| 251 | // as defined by the underlying build system. |
| 252 | // It may return an empty list of packages without an error, |
| 253 | // for instance for an empty expansion of a valid wildcard. |
| 254 | // Errors associated with a particular package are recorded in the |
| 255 | // corresponding Package's Errors list, and do not cause Load to |
| 256 | // return an error. Clients may need to handle such errors before |
| 257 | // proceeding with further analysis. The PrintErrors function is |
| 258 | // provided for convenient display of all errors. |
| 259 | func Load(cfg *Config, patterns ...string) ([]*Package, error) { |
| 260 | l := newLoader(cfg) |
| 261 | response, err := defaultDriver(&l.Config, patterns...) |
| 262 | if err != nil { |
| 263 | return nil, err |
| 264 | } |
| 265 | l.sizes = response.Sizes |
| 266 | return l.refine(response) |
| 267 | } |
| 268 | |
| 269 | // defaultDriver is a driver that implements go/packages' fallback behavior. |
| 270 | // It will try to request to an external driver, if one exists. If there's |
| 271 | // no external driver, or the driver returns a response with NotHandled set, |
| 272 | // defaultDriver will fall back to the go list driver. |
| 273 | func defaultDriver(cfg *Config, patterns ...string) (*driverResponse, error) { |
| 274 | driver := findExternalDriver(cfg) |
| 275 | if driver == nil { |
| 276 | driver = goListDriver |
| 277 | } |
| 278 | response, err := driver(cfg, patterns...) |
| 279 | if err != nil { |
| 280 | return response, err |
| 281 | } else if response.NotHandled { |
| 282 | return goListDriver(cfg, patterns...) |
| 283 | } |
| 284 | return response, nil |
| 285 | } |
| 286 | |
| 287 | // A Package describes a loaded Go package. |
| 288 | type Package struct { |
| 289 | // ID is a unique identifier for a package, |
| 290 | // in a syntax provided by the underlying build system. |
| 291 | // |
| 292 | // Because the syntax varies based on the build system, |
| 293 | // clients should treat IDs as opaque and not attempt to |
| 294 | // interpret them. |
| 295 | ID string |
| 296 | |
| 297 | // Name is the package name as it appears in the package source code. |
| 298 | Name string |
| 299 | |
| 300 | // PkgPath is the package path as used by the go/types package. |
| 301 | PkgPath string |
| 302 | |
| 303 | // Errors contains any errors encountered querying the metadata |
| 304 | // of the package, or while parsing or type-checking its files. |
| 305 | Errors []Error |
| 306 | |
| 307 | // TypeErrors contains the subset of errors produced during type checking. |
| 308 | TypeErrors []types.Error |
| 309 | |
| 310 | // GoFiles lists the absolute file paths of the package's Go source files. |
| 311 | GoFiles []string |
| 312 | |
| 313 | // CompiledGoFiles lists the absolute file paths of the package's source |
| 314 | // files that are suitable for type checking. |
| 315 | // This may differ from GoFiles if files are processed before compilation. |
| 316 | CompiledGoFiles []string |
| 317 | |
| 318 | // OtherFiles lists the absolute file paths of the package's non-Go source files, |
| 319 | // including assembly, C, C++, Fortran, Objective-C, SWIG, and so on. |
| 320 | OtherFiles []string |
| 321 | |
| 322 | // EmbedFiles lists the absolute file paths of the package's files |
| 323 | // embedded with go:embed. |
| 324 | EmbedFiles []string |
| 325 | |
| 326 | // EmbedPatterns lists the absolute file patterns of the package's |
| 327 | // files embedded with go:embed. |
| 328 | EmbedPatterns []string |
| 329 | |
| 330 | // IgnoredFiles lists source files that are not part of the package |
| 331 | // using the current build configuration but that might be part of |
| 332 | // the package using other build configurations. |
| 333 | IgnoredFiles []string |
| 334 | |
| 335 | // ExportFile is the absolute path to a file containing type |
| 336 | // information for the package as provided by the build system. |
| 337 | ExportFile string |
| 338 | |
| 339 | // Imports maps import paths appearing in the package's Go source files |
| 340 | // to corresponding loaded Packages. |
| 341 | Imports map[string]*Package |
| 342 | |
| 343 | // Types provides type information for the package. |
| 344 | // The NeedTypes LoadMode bit sets this field for packages matching the |
| 345 | // patterns; type information for dependencies may be missing or incomplete, |
| 346 | // unless NeedDeps and NeedImports are also set. |
| 347 | Types *types.Package |
| 348 | |
| 349 | // Fset provides position information for Types, TypesInfo, and Syntax. |
| 350 | // It is set only when Types is set. |
| 351 | Fset *token.FileSet |
| 352 | |
| 353 | // IllTyped indicates whether the package or any dependency contains errors. |
| 354 | // It is set only when Types is set. |
| 355 | IllTyped bool |
| 356 | |
| 357 | // Syntax is the package's syntax trees, for the files listed in CompiledGoFiles. |
| 358 | // |
| 359 | // The NeedSyntax LoadMode bit populates this field for packages matching the patterns. |
| 360 | // If NeedDeps and NeedImports are also set, this field will also be populated |
| 361 | // for dependencies. |
| 362 | // |
| 363 | // Syntax is kept in the same order as CompiledGoFiles, with the caveat that nils are |
| 364 | // removed. If parsing returned nil, Syntax may be shorter than CompiledGoFiles. |
| 365 | Syntax []*ast.File |
| 366 | |
| 367 | // TypesInfo provides type information about the package's syntax trees. |
| 368 | // It is set only when Syntax is set. |
| 369 | TypesInfo *types.Info |
| 370 | |
| 371 | // TypesSizes provides the effective size function for types in TypesInfo. |
| 372 | TypesSizes types.Sizes |
| 373 | |
| 374 | // forTest is the package under test, if any. |
| 375 | forTest string |
| 376 | |
| 377 | // depsErrors is the DepsErrors field from the go list response, if any. |
| 378 | depsErrors []*packagesinternal.PackageError |
| 379 | |
| 380 | // module is the module information for the package if it exists. |
| 381 | Module *Module |
| 382 | } |
| 383 | |
| 384 | // Module provides module information for a package. |
| 385 | type Module struct { |
| 386 | Path string // module path |
| 387 | Version string // module version |
| 388 | Replace *Module // replaced by this module |
| 389 | Time *time.Time // time version was created |
| 390 | Main bool // is this the main module? |
| 391 | Indirect bool // is this module only an indirect dependency of main module? |
| 392 | Dir string // directory holding files for this module, if any |
| 393 | GoMod string // path to go.mod file used when loading this module, if any |
| 394 | GoVersion string // go version used in module |
| 395 | Error *ModuleError // error loading module |
| 396 | } |
| 397 | |
| 398 | // ModuleError holds errors loading a module. |
| 399 | type ModuleError struct { |
| 400 | Err string // the error itself |
| 401 | } |
| 402 | |
| 403 | func init() { |
| 404 | packagesinternal.GetForTest = func(p interface{}) string { |
| 405 | return p.(*Package).forTest |
| 406 | } |
| 407 | packagesinternal.GetDepsErrors = func(p interface{}) []*packagesinternal.PackageError { |
| 408 | return p.(*Package).depsErrors |
| 409 | } |
| 410 | packagesinternal.GetGoCmdRunner = func(config interface{}) *gocommand.Runner { |
| 411 | return config.(*Config).gocmdRunner |
| 412 | } |
| 413 | packagesinternal.SetGoCmdRunner = func(config interface{}, runner *gocommand.Runner) { |
| 414 | config.(*Config).gocmdRunner = runner |
| 415 | } |
| 416 | packagesinternal.SetModFile = func(config interface{}, value string) { |
| 417 | config.(*Config).modFile = value |
| 418 | } |
| 419 | packagesinternal.SetModFlag = func(config interface{}, value string) { |
| 420 | config.(*Config).modFlag = value |
| 421 | } |
| 422 | packagesinternal.TypecheckCgo = int(typecheckCgo) |
| 423 | packagesinternal.DepsErrors = int(needInternalDepsErrors) |
| 424 | packagesinternal.ForTest = int(needInternalForTest) |
| 425 | } |
| 426 | |
| 427 | // An Error describes a problem with a package's metadata, syntax, or types. |
| 428 | type Error struct { |
| 429 | Pos string // "file:line:col" or "file:line" or "" or "-" |
| 430 | Msg string |
| 431 | Kind ErrorKind |
| 432 | } |
| 433 | |
| 434 | // ErrorKind describes the source of the error, allowing the user to |
| 435 | // differentiate between errors generated by the driver, the parser, or the |
| 436 | // type-checker. |
| 437 | type ErrorKind int |
| 438 | |
| 439 | const ( |
| 440 | UnknownError ErrorKind = iota |
| 441 | ListError |
| 442 | ParseError |
| 443 | TypeError |
| 444 | ) |
| 445 | |
| 446 | func (err Error) Error() string { |
| 447 | pos := err.Pos |
| 448 | if pos == "" { |
| 449 | pos = "-" // like token.Position{}.String() |
| 450 | } |
| 451 | return pos + ": " + err.Msg |
| 452 | } |
| 453 | |
| 454 | // flatPackage is the JSON form of Package |
| 455 | // It drops all the type and syntax fields, and transforms the Imports |
| 456 | // |
| 457 | // TODO(adonovan): identify this struct with Package, effectively |
| 458 | // publishing the JSON protocol. |
| 459 | type flatPackage struct { |
| 460 | ID string |
| 461 | Name string `json:",omitempty"` |
| 462 | PkgPath string `json:",omitempty"` |
| 463 | Errors []Error `json:",omitempty"` |
| 464 | GoFiles []string `json:",omitempty"` |
| 465 | CompiledGoFiles []string `json:",omitempty"` |
| 466 | OtherFiles []string `json:",omitempty"` |
| 467 | EmbedFiles []string `json:",omitempty"` |
| 468 | EmbedPatterns []string `json:",omitempty"` |
| 469 | IgnoredFiles []string `json:",omitempty"` |
| 470 | ExportFile string `json:",omitempty"` |
| 471 | Imports map[string]string `json:",omitempty"` |
| 472 | } |
| 473 | |
| 474 | // MarshalJSON returns the Package in its JSON form. |
| 475 | // For the most part, the structure fields are written out unmodified, and |
| 476 | // the type and syntax fields are skipped. |
| 477 | // The imports are written out as just a map of path to package id. |
| 478 | // The errors are written using a custom type that tries to preserve the |
| 479 | // structure of error types we know about. |
| 480 | // |
| 481 | // This method exists to enable support for additional build systems. It is |
| 482 | // not intended for use by clients of the API and we may change the format. |
| 483 | func (p *Package) MarshalJSON() ([]byte, error) { |
| 484 | flat := &flatPackage{ |
| 485 | ID: p.ID, |
| 486 | Name: p.Name, |
| 487 | PkgPath: p.PkgPath, |
| 488 | Errors: p.Errors, |
| 489 | GoFiles: p.GoFiles, |
| 490 | CompiledGoFiles: p.CompiledGoFiles, |
| 491 | OtherFiles: p.OtherFiles, |
| 492 | EmbedFiles: p.EmbedFiles, |
| 493 | EmbedPatterns: p.EmbedPatterns, |
| 494 | IgnoredFiles: p.IgnoredFiles, |
| 495 | ExportFile: p.ExportFile, |
| 496 | } |
| 497 | if len(p.Imports) > 0 { |
| 498 | flat.Imports = make(map[string]string, len(p.Imports)) |
| 499 | for path, ipkg := range p.Imports { |
| 500 | flat.Imports[path] = ipkg.ID |
| 501 | } |
| 502 | } |
| 503 | return json.Marshal(flat) |
| 504 | } |
| 505 | |
| 506 | // UnmarshalJSON reads in a Package from its JSON format. |
| 507 | // See MarshalJSON for details about the format accepted. |
| 508 | func (p *Package) UnmarshalJSON(b []byte) error { |
| 509 | flat := &flatPackage{} |
| 510 | if err := json.Unmarshal(b, &flat); err != nil { |
| 511 | return err |
| 512 | } |
| 513 | *p = Package{ |
| 514 | ID: flat.ID, |
| 515 | Name: flat.Name, |
| 516 | PkgPath: flat.PkgPath, |
| 517 | Errors: flat.Errors, |
| 518 | GoFiles: flat.GoFiles, |
| 519 | CompiledGoFiles: flat.CompiledGoFiles, |
| 520 | OtherFiles: flat.OtherFiles, |
| 521 | EmbedFiles: flat.EmbedFiles, |
| 522 | EmbedPatterns: flat.EmbedPatterns, |
| 523 | ExportFile: flat.ExportFile, |
| 524 | } |
| 525 | if len(flat.Imports) > 0 { |
| 526 | p.Imports = make(map[string]*Package, len(flat.Imports)) |
| 527 | for path, id := range flat.Imports { |
| 528 | p.Imports[path] = &Package{ID: id} |
| 529 | } |
| 530 | } |
| 531 | return nil |
| 532 | } |
| 533 | |
| 534 | func (p *Package) String() string { return p.ID } |
| 535 | |
| 536 | // loaderPackage augments Package with state used during the loading phase |
| 537 | type loaderPackage struct { |
| 538 | *Package |
| 539 | importErrors map[string]error // maps each bad import to its error |
| 540 | loadOnce sync.Once |
| 541 | color uint8 // for cycle detection |
| 542 | needsrc bool // load from source (Mode >= LoadTypes) |
| 543 | needtypes bool // type information is either requested or depended on |
| 544 | initial bool // package was matched by a pattern |
| 545 | goVersion int // minor version number of go command on PATH |
| 546 | } |
| 547 | |
| 548 | // loader holds the working state of a single call to load. |
| 549 | type loader struct { |
| 550 | pkgs map[string]*loaderPackage |
| 551 | Config |
| 552 | sizes types.Sizes |
| 553 | parseCache map[string]*parseValue |
| 554 | parseCacheMu sync.Mutex |
| 555 | exportMu sync.Mutex // enforces mutual exclusion of exportdata operations |
| 556 | |
| 557 | // Config.Mode contains the implied mode (see impliedLoadMode). |
| 558 | // Implied mode contains all the fields we need the data for. |
| 559 | // In requestedMode there are the actually requested fields. |
| 560 | // We'll zero them out before returning packages to the user. |
| 561 | // This makes it easier for us to get the conditions where |
| 562 | // we need certain modes right. |
| 563 | requestedMode LoadMode |
| 564 | } |
| 565 | |
| 566 | type parseValue struct { |
| 567 | f *ast.File |
| 568 | err error |
| 569 | ready chan struct{} |
| 570 | } |
| 571 | |
| 572 | func newLoader(cfg *Config) *loader { |
| 573 | ld := &loader{ |
| 574 | parseCache: map[string]*parseValue{}, |
| 575 | } |
| 576 | if cfg != nil { |
| 577 | ld.Config = *cfg |
| 578 | // If the user has provided a logger, use it. |
| 579 | ld.Config.Logf = cfg.Logf |
| 580 | } |
| 581 | if ld.Config.Logf == nil { |
| 582 | // If the GOPACKAGESDEBUG environment variable is set to true, |
| 583 | // but the user has not provided a logger, default to log.Printf. |
| 584 | if debug { |
| 585 | ld.Config.Logf = log.Printf |
| 586 | } else { |
| 587 | ld.Config.Logf = func(format string, args ...interface{}) {} |
| 588 | } |
| 589 | } |
| 590 | if ld.Config.Mode == 0 { |
| 591 | ld.Config.Mode = NeedName | NeedFiles | NeedCompiledGoFiles // Preserve zero behavior of Mode for backwards compatibility. |
| 592 | } |
| 593 | if ld.Config.Env == nil { |
| 594 | ld.Config.Env = os.Environ() |
| 595 | } |
| 596 | if ld.Config.gocmdRunner == nil { |
| 597 | ld.Config.gocmdRunner = &gocommand.Runner{} |
| 598 | } |
| 599 | if ld.Context == nil { |
| 600 | ld.Context = context.Background() |
| 601 | } |
| 602 | if ld.Dir == "" { |
| 603 | if dir, err := os.Getwd(); err == nil { |
| 604 | ld.Dir = dir |
| 605 | } |
| 606 | } |
| 607 | |
| 608 | // Save the actually requested fields. We'll zero them out before returning packages to the user. |
| 609 | ld.requestedMode = ld.Mode |
| 610 | ld.Mode = impliedLoadMode(ld.Mode) |
| 611 | |
| 612 | if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 { |
| 613 | if ld.Fset == nil { |
| 614 | ld.Fset = token.NewFileSet() |
| 615 | } |
| 616 | |
| 617 | // ParseFile is required even in LoadTypes mode |
| 618 | // because we load source if export data is missing. |
| 619 | if ld.ParseFile == nil { |
| 620 | ld.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) { |
| 621 | const mode = parser.AllErrors | parser.ParseComments |
| 622 | return parser.ParseFile(fset, filename, src, mode) |
| 623 | } |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | return ld |
| 628 | } |
| 629 | |
| 630 | // refine connects the supplied packages into a graph and then adds type and |
| 631 | // and syntax information as requested by the LoadMode. |
| 632 | func (ld *loader) refine(response *driverResponse) ([]*Package, error) { |
| 633 | roots := response.Roots |
| 634 | rootMap := make(map[string]int, len(roots)) |
| 635 | for i, root := range roots { |
| 636 | rootMap[root] = i |
| 637 | } |
| 638 | ld.pkgs = make(map[string]*loaderPackage) |
| 639 | // first pass, fixup and build the map and roots |
| 640 | var initial = make([]*loaderPackage, len(roots)) |
| 641 | for _, pkg := range response.Packages { |
| 642 | rootIndex := -1 |
| 643 | if i, found := rootMap[pkg.ID]; found { |
| 644 | rootIndex = i |
| 645 | } |
| 646 | |
| 647 | // Overlays can invalidate export data. |
| 648 | // TODO(matloob): make this check fine-grained based on dependencies on overlaid files |
| 649 | exportDataInvalid := len(ld.Overlay) > 0 || pkg.ExportFile == "" && pkg.PkgPath != "unsafe" |
| 650 | // This package needs type information if the caller requested types and the package is |
| 651 | // either a root, or it's a non-root and the user requested dependencies ... |
| 652 | needtypes := (ld.Mode&NeedTypes|NeedTypesInfo != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0)) |
| 653 | // This package needs source if the call requested source (or types info, which implies source) |
| 654 | // and the package is either a root, or itas a non- root and the user requested dependencies... |
| 655 | needsrc := ((ld.Mode&(NeedSyntax|NeedTypesInfo) != 0 && (rootIndex >= 0 || ld.Mode&NeedDeps != 0)) || |
| 656 | // ... or if we need types and the exportData is invalid. We fall back to (incompletely) |
| 657 | // typechecking packages from source if they fail to compile. |
| 658 | (ld.Mode&(NeedTypes|NeedTypesInfo) != 0 && exportDataInvalid)) && pkg.PkgPath != "unsafe" |
| 659 | lpkg := &loaderPackage{ |
| 660 | Package: pkg, |
| 661 | needtypes: needtypes, |
| 662 | needsrc: needsrc, |
| 663 | goVersion: response.GoVersion, |
| 664 | } |
| 665 | ld.pkgs[lpkg.ID] = lpkg |
| 666 | if rootIndex >= 0 { |
| 667 | initial[rootIndex] = lpkg |
| 668 | lpkg.initial = true |
| 669 | } |
| 670 | } |
| 671 | for i, root := range roots { |
| 672 | if initial[i] == nil { |
| 673 | return nil, fmt.Errorf("root package %v is missing", root) |
| 674 | } |
| 675 | } |
| 676 | |
| 677 | // Materialize the import graph. |
| 678 | |
| 679 | const ( |
| 680 | white = 0 // new |
| 681 | grey = 1 // in progress |
| 682 | black = 2 // complete |
| 683 | ) |
| 684 | |
| 685 | // visit traverses the import graph, depth-first, |
| 686 | // and materializes the graph as Packages.Imports. |
| 687 | // |
| 688 | // Valid imports are saved in the Packages.Import map. |
| 689 | // Invalid imports (cycles and missing nodes) are saved in the importErrors map. |
| 690 | // Thus, even in the presence of both kinds of errors, the Import graph remains a DAG. |
| 691 | // |
| 692 | // visit returns whether the package needs src or has a transitive |
| 693 | // dependency on a package that does. These are the only packages |
| 694 | // for which we load source code. |
| 695 | var stack []*loaderPackage |
| 696 | var visit func(lpkg *loaderPackage) bool |
| 697 | var srcPkgs []*loaderPackage |
| 698 | visit = func(lpkg *loaderPackage) bool { |
| 699 | switch lpkg.color { |
| 700 | case black: |
| 701 | return lpkg.needsrc |
| 702 | case grey: |
| 703 | panic("internal error: grey node") |
| 704 | } |
| 705 | lpkg.color = grey |
| 706 | stack = append(stack, lpkg) // push |
| 707 | stubs := lpkg.Imports // the structure form has only stubs with the ID in the Imports |
| 708 | // If NeedImports isn't set, the imports fields will all be zeroed out. |
| 709 | if ld.Mode&NeedImports != 0 { |
| 710 | lpkg.Imports = make(map[string]*Package, len(stubs)) |
| 711 | for importPath, ipkg := range stubs { |
| 712 | var importErr error |
| 713 | imp := ld.pkgs[ipkg.ID] |
| 714 | if imp == nil { |
| 715 | // (includes package "C" when DisableCgo) |
| 716 | importErr = fmt.Errorf("missing package: %q", ipkg.ID) |
| 717 | } else if imp.color == grey { |
| 718 | importErr = fmt.Errorf("import cycle: %s", stack) |
| 719 | } |
| 720 | if importErr != nil { |
| 721 | if lpkg.importErrors == nil { |
| 722 | lpkg.importErrors = make(map[string]error) |
| 723 | } |
| 724 | lpkg.importErrors[importPath] = importErr |
| 725 | continue |
| 726 | } |
| 727 | |
| 728 | if visit(imp) { |
| 729 | lpkg.needsrc = true |
| 730 | } |
| 731 | lpkg.Imports[importPath] = imp.Package |
| 732 | } |
| 733 | } |
| 734 | if lpkg.needsrc { |
| 735 | srcPkgs = append(srcPkgs, lpkg) |
| 736 | } |
| 737 | if ld.Mode&NeedTypesSizes != 0 { |
| 738 | lpkg.TypesSizes = ld.sizes |
| 739 | } |
| 740 | stack = stack[:len(stack)-1] // pop |
| 741 | lpkg.color = black |
| 742 | |
| 743 | return lpkg.needsrc |
| 744 | } |
| 745 | |
| 746 | if ld.Mode&NeedImports == 0 { |
| 747 | // We do this to drop the stub import packages that we are not even going to try to resolve. |
| 748 | for _, lpkg := range initial { |
| 749 | lpkg.Imports = nil |
| 750 | } |
| 751 | } else { |
| 752 | // For each initial package, create its import DAG. |
| 753 | for _, lpkg := range initial { |
| 754 | visit(lpkg) |
| 755 | } |
| 756 | } |
| 757 | if ld.Mode&NeedImports != 0 && ld.Mode&NeedTypes != 0 { |
| 758 | for _, lpkg := range srcPkgs { |
| 759 | // Complete type information is required for the |
| 760 | // immediate dependencies of each source package. |
| 761 | for _, ipkg := range lpkg.Imports { |
| 762 | imp := ld.pkgs[ipkg.ID] |
| 763 | imp.needtypes = true |
| 764 | } |
| 765 | } |
| 766 | } |
| 767 | // Load type data and syntax if needed, starting at |
| 768 | // the initial packages (roots of the import DAG). |
| 769 | if ld.Mode&NeedTypes != 0 || ld.Mode&NeedSyntax != 0 { |
| 770 | var wg sync.WaitGroup |
| 771 | for _, lpkg := range initial { |
| 772 | wg.Add(1) |
| 773 | go func(lpkg *loaderPackage) { |
| 774 | ld.loadRecursive(lpkg) |
| 775 | wg.Done() |
| 776 | }(lpkg) |
| 777 | } |
| 778 | wg.Wait() |
| 779 | } |
| 780 | |
| 781 | result := make([]*Package, len(initial)) |
| 782 | for i, lpkg := range initial { |
| 783 | result[i] = lpkg.Package |
| 784 | } |
| 785 | for i := range ld.pkgs { |
| 786 | // Clear all unrequested fields, |
| 787 | // to catch programs that use more than they request. |
| 788 | if ld.requestedMode&NeedName == 0 { |
| 789 | ld.pkgs[i].Name = "" |
| 790 | ld.pkgs[i].PkgPath = "" |
| 791 | } |
| 792 | if ld.requestedMode&NeedFiles == 0 { |
| 793 | ld.pkgs[i].GoFiles = nil |
| 794 | ld.pkgs[i].OtherFiles = nil |
| 795 | ld.pkgs[i].IgnoredFiles = nil |
| 796 | } |
| 797 | if ld.requestedMode&NeedEmbedFiles == 0 { |
| 798 | ld.pkgs[i].EmbedFiles = nil |
| 799 | } |
| 800 | if ld.requestedMode&NeedEmbedPatterns == 0 { |
| 801 | ld.pkgs[i].EmbedPatterns = nil |
| 802 | } |
| 803 | if ld.requestedMode&NeedCompiledGoFiles == 0 { |
| 804 | ld.pkgs[i].CompiledGoFiles = nil |
| 805 | } |
| 806 | if ld.requestedMode&NeedImports == 0 { |
| 807 | ld.pkgs[i].Imports = nil |
| 808 | } |
| 809 | if ld.requestedMode&NeedExportFile == 0 { |
| 810 | ld.pkgs[i].ExportFile = "" |
| 811 | } |
| 812 | if ld.requestedMode&NeedTypes == 0 { |
| 813 | ld.pkgs[i].Types = nil |
| 814 | ld.pkgs[i].Fset = nil |
| 815 | ld.pkgs[i].IllTyped = false |
| 816 | } |
| 817 | if ld.requestedMode&NeedSyntax == 0 { |
| 818 | ld.pkgs[i].Syntax = nil |
| 819 | } |
| 820 | if ld.requestedMode&NeedTypesInfo == 0 { |
| 821 | ld.pkgs[i].TypesInfo = nil |
| 822 | } |
| 823 | if ld.requestedMode&NeedTypesSizes == 0 { |
| 824 | ld.pkgs[i].TypesSizes = nil |
| 825 | } |
| 826 | if ld.requestedMode&NeedModule == 0 { |
| 827 | ld.pkgs[i].Module = nil |
| 828 | } |
| 829 | } |
| 830 | |
| 831 | return result, nil |
| 832 | } |
| 833 | |
| 834 | // loadRecursive loads the specified package and its dependencies, |
| 835 | // recursively, in parallel, in topological order. |
| 836 | // It is atomic and idempotent. |
| 837 | // Precondition: ld.Mode&NeedTypes. |
| 838 | func (ld *loader) loadRecursive(lpkg *loaderPackage) { |
| 839 | lpkg.loadOnce.Do(func() { |
| 840 | // Load the direct dependencies, in parallel. |
| 841 | var wg sync.WaitGroup |
| 842 | for _, ipkg := range lpkg.Imports { |
| 843 | imp := ld.pkgs[ipkg.ID] |
| 844 | wg.Add(1) |
| 845 | go func(imp *loaderPackage) { |
| 846 | ld.loadRecursive(imp) |
| 847 | wg.Done() |
| 848 | }(imp) |
| 849 | } |
| 850 | wg.Wait() |
| 851 | ld.loadPackage(lpkg) |
| 852 | }) |
| 853 | } |
| 854 | |
| 855 | // loadPackage loads the specified package. |
| 856 | // It must be called only once per Package, |
| 857 | // after immediate dependencies are loaded. |
| 858 | // Precondition: ld.Mode & NeedTypes. |
| 859 | func (ld *loader) loadPackage(lpkg *loaderPackage) { |
| 860 | if lpkg.PkgPath == "unsafe" { |
| 861 | // Fill in the blanks to avoid surprises. |
| 862 | lpkg.Types = types.Unsafe |
| 863 | lpkg.Fset = ld.Fset |
| 864 | lpkg.Syntax = []*ast.File{} |
| 865 | lpkg.TypesInfo = new(types.Info) |
| 866 | lpkg.TypesSizes = ld.sizes |
| 867 | return |
| 868 | } |
| 869 | |
| 870 | // Call NewPackage directly with explicit name. |
| 871 | // This avoids skew between golist and go/types when the files' |
| 872 | // package declarations are inconsistent. |
| 873 | lpkg.Types = types.NewPackage(lpkg.PkgPath, lpkg.Name) |
| 874 | lpkg.Fset = ld.Fset |
| 875 | |
| 876 | // Subtle: we populate all Types fields with an empty Package |
| 877 | // before loading export data so that export data processing |
| 878 | // never has to create a types.Package for an indirect dependency, |
| 879 | // which would then require that such created packages be explicitly |
| 880 | // inserted back into the Import graph as a final step after export data loading. |
| 881 | // The Diamond test exercises this case. |
| 882 | if !lpkg.needtypes && !lpkg.needsrc { |
| 883 | return |
| 884 | } |
| 885 | if !lpkg.needsrc { |
| 886 | ld.loadFromExportData(lpkg) |
| 887 | return // not a source package, don't get syntax trees |
| 888 | } |
| 889 | |
| 890 | appendError := func(err error) { |
| 891 | // Convert various error types into the one true Error. |
| 892 | var errs []Error |
| 893 | switch err := err.(type) { |
| 894 | case Error: |
| 895 | // from driver |
| 896 | errs = append(errs, err) |
| 897 | |
| 898 | case *os.PathError: |
| 899 | // from parser |
| 900 | errs = append(errs, Error{ |
| 901 | Pos: err.Path + ":1", |
| 902 | Msg: err.Err.Error(), |
| 903 | Kind: ParseError, |
| 904 | }) |
| 905 | |
| 906 | case scanner.ErrorList: |
| 907 | // from parser |
| 908 | for _, err := range err { |
| 909 | errs = append(errs, Error{ |
| 910 | Pos: err.Pos.String(), |
| 911 | Msg: err.Msg, |
| 912 | Kind: ParseError, |
| 913 | }) |
| 914 | } |
| 915 | |
| 916 | case types.Error: |
| 917 | // from type checker |
| 918 | lpkg.TypeErrors = append(lpkg.TypeErrors, err) |
| 919 | errs = append(errs, Error{ |
| 920 | Pos: err.Fset.Position(err.Pos).String(), |
| 921 | Msg: err.Msg, |
| 922 | Kind: TypeError, |
| 923 | }) |
| 924 | |
| 925 | default: |
| 926 | // unexpected impoverished error from parser? |
| 927 | errs = append(errs, Error{ |
| 928 | Pos: "-", |
| 929 | Msg: err.Error(), |
| 930 | Kind: UnknownError, |
| 931 | }) |
| 932 | |
| 933 | // If you see this error message, please file a bug. |
| 934 | log.Printf("internal error: error %q (%T) without position", err, err) |
| 935 | } |
| 936 | |
| 937 | lpkg.Errors = append(lpkg.Errors, errs...) |
| 938 | } |
| 939 | |
| 940 | // If the go command on the PATH is newer than the runtime, |
| 941 | // then the go/{scanner,ast,parser,types} packages from the |
| 942 | // standard library may be unable to process the files |
| 943 | // selected by go list. |
| 944 | // |
| 945 | // There is currently no way to downgrade the effective |
| 946 | // version of the go command (see issue 52078), so we proceed |
| 947 | // with the newer go command but, in case of parse or type |
| 948 | // errors, we emit an additional diagnostic. |
| 949 | // |
| 950 | // See: |
| 951 | // - golang.org/issue/52078 (flag to set release tags) |
| 952 | // - golang.org/issue/50825 (gopls legacy version support) |
| 953 | // - golang.org/issue/55883 (go/packages confusing error) |
| 954 | // |
| 955 | // Should we assert a hard minimum of (currently) go1.16 here? |
| 956 | var runtimeVersion int |
| 957 | if _, err := fmt.Sscanf(runtime.Version(), "go1.%d", &runtimeVersion); err == nil && runtimeVersion < lpkg.goVersion { |
| 958 | defer func() { |
| 959 | if len(lpkg.Errors) > 0 { |
| 960 | appendError(Error{ |
| 961 | Pos: "-", |
| 962 | Msg: fmt.Sprintf("This application uses version go1.%d of the source-processing packages but runs version go1.%d of 'go list'. It may fail to process source files that rely on newer language features. If so, rebuild the application using a newer version of Go.", runtimeVersion, lpkg.goVersion), |
| 963 | Kind: UnknownError, |
| 964 | }) |
| 965 | } |
| 966 | }() |
| 967 | } |
| 968 | |
| 969 | if ld.Config.Mode&NeedTypes != 0 && len(lpkg.CompiledGoFiles) == 0 && lpkg.ExportFile != "" { |
| 970 | // The config requested loading sources and types, but sources are missing. |
| 971 | // Add an error to the package and fall back to loading from export data. |
| 972 | appendError(Error{"-", fmt.Sprintf("sources missing for package %s", lpkg.ID), ParseError}) |
| 973 | ld.loadFromExportData(lpkg) |
| 974 | return // can't get syntax trees for this package |
| 975 | } |
| 976 | |
| 977 | files, errs := ld.parseFiles(lpkg.CompiledGoFiles) |
| 978 | for _, err := range errs { |
| 979 | appendError(err) |
| 980 | } |
| 981 | |
| 982 | lpkg.Syntax = files |
| 983 | if ld.Config.Mode&NeedTypes == 0 { |
| 984 | return |
| 985 | } |
| 986 | |
| 987 | lpkg.TypesInfo = &types.Info{ |
| 988 | Types: make(map[ast.Expr]types.TypeAndValue), |
| 989 | Defs: make(map[*ast.Ident]types.Object), |
| 990 | Uses: make(map[*ast.Ident]types.Object), |
| 991 | Implicits: make(map[ast.Node]types.Object), |
| 992 | Scopes: make(map[ast.Node]*types.Scope), |
| 993 | Selections: make(map[*ast.SelectorExpr]*types.Selection), |
| 994 | } |
| 995 | typeparams.InitInstanceInfo(lpkg.TypesInfo) |
| 996 | lpkg.TypesSizes = ld.sizes |
| 997 | |
| 998 | importer := importerFunc(func(path string) (*types.Package, error) { |
| 999 | if path == "unsafe" { |
| 1000 | return types.Unsafe, nil |
| 1001 | } |
| 1002 | |
| 1003 | // The imports map is keyed by import path. |
| 1004 | ipkg := lpkg.Imports[path] |
| 1005 | if ipkg == nil { |
| 1006 | if err := lpkg.importErrors[path]; err != nil { |
| 1007 | return nil, err |
| 1008 | } |
| 1009 | // There was skew between the metadata and the |
| 1010 | // import declarations, likely due to an edit |
| 1011 | // race, or because the ParseFile feature was |
| 1012 | // used to supply alternative file contents. |
| 1013 | return nil, fmt.Errorf("no metadata for %s", path) |
| 1014 | } |
| 1015 | |
| 1016 | if ipkg.Types != nil && ipkg.Types.Complete() { |
| 1017 | return ipkg.Types, nil |
| 1018 | } |
| 1019 | log.Fatalf("internal error: package %q without types was imported from %q", path, lpkg) |
| 1020 | panic("unreachable") |
| 1021 | }) |
| 1022 | |
| 1023 | // type-check |
| 1024 | tc := &types.Config{ |
| 1025 | Importer: importer, |
| 1026 | |
| 1027 | // Type-check bodies of functions only in initial packages. |
| 1028 | // Example: for import graph A->B->C and initial packages {A,C}, |
| 1029 | // we can ignore function bodies in B. |
| 1030 | IgnoreFuncBodies: ld.Mode&NeedDeps == 0 && !lpkg.initial, |
| 1031 | |
| 1032 | Error: appendError, |
| 1033 | Sizes: ld.sizes, |
| 1034 | } |
| 1035 | if (ld.Mode & typecheckCgo) != 0 { |
| 1036 | if !typesinternal.SetUsesCgo(tc) { |
| 1037 | appendError(Error{ |
| 1038 | Msg: "typecheckCgo requires Go 1.15+", |
| 1039 | Kind: ListError, |
| 1040 | }) |
| 1041 | return |
| 1042 | } |
| 1043 | } |
| 1044 | types.NewChecker(tc, ld.Fset, lpkg.Types, lpkg.TypesInfo).Files(lpkg.Syntax) |
| 1045 | |
| 1046 | lpkg.importErrors = nil // no longer needed |
| 1047 | |
| 1048 | // If !Cgo, the type-checker uses FakeImportC mode, so |
| 1049 | // it doesn't invoke the importer for import "C", |
| 1050 | // nor report an error for the import, |
| 1051 | // or for any undefined C.f reference. |
| 1052 | // We must detect this explicitly and correctly |
| 1053 | // mark the package as IllTyped (by reporting an error). |
| 1054 | // TODO(adonovan): if these errors are annoying, |
| 1055 | // we could just set IllTyped quietly. |
| 1056 | if tc.FakeImportC { |
| 1057 | outer: |
| 1058 | for _, f := range lpkg.Syntax { |
| 1059 | for _, imp := range f.Imports { |
| 1060 | if imp.Path.Value == `"C"` { |
| 1061 | err := types.Error{Fset: ld.Fset, Pos: imp.Pos(), Msg: `import "C" ignored`} |
| 1062 | appendError(err) |
| 1063 | break outer |
| 1064 | } |
| 1065 | } |
| 1066 | } |
| 1067 | } |
| 1068 | |
| 1069 | // Record accumulated errors. |
| 1070 | illTyped := len(lpkg.Errors) > 0 |
| 1071 | if !illTyped { |
| 1072 | for _, imp := range lpkg.Imports { |
| 1073 | if imp.IllTyped { |
| 1074 | illTyped = true |
| 1075 | break |
| 1076 | } |
| 1077 | } |
| 1078 | } |
| 1079 | lpkg.IllTyped = illTyped |
| 1080 | } |
| 1081 | |
| 1082 | // An importFunc is an implementation of the single-method |
| 1083 | // types.Importer interface based on a function value. |
| 1084 | type importerFunc func(path string) (*types.Package, error) |
| 1085 | |
| 1086 | func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) } |
| 1087 | |
| 1088 | // We use a counting semaphore to limit |
| 1089 | // the number of parallel I/O calls per process. |
| 1090 | var ioLimit = make(chan bool, 20) |
| 1091 | |
| 1092 | func (ld *loader) parseFile(filename string) (*ast.File, error) { |
| 1093 | ld.parseCacheMu.Lock() |
| 1094 | v, ok := ld.parseCache[filename] |
| 1095 | if ok { |
| 1096 | // cache hit |
| 1097 | ld.parseCacheMu.Unlock() |
| 1098 | <-v.ready |
| 1099 | } else { |
| 1100 | // cache miss |
| 1101 | v = &parseValue{ready: make(chan struct{})} |
| 1102 | ld.parseCache[filename] = v |
| 1103 | ld.parseCacheMu.Unlock() |
| 1104 | |
| 1105 | var src []byte |
| 1106 | for f, contents := range ld.Config.Overlay { |
| 1107 | if sameFile(f, filename) { |
| 1108 | src = contents |
| 1109 | } |
| 1110 | } |
| 1111 | var err error |
| 1112 | if src == nil { |
| 1113 | ioLimit <- true // wait |
| 1114 | src, err = ioutil.ReadFile(filename) |
| 1115 | <-ioLimit // signal |
| 1116 | } |
| 1117 | if err != nil { |
| 1118 | v.err = err |
| 1119 | } else { |
| 1120 | v.f, v.err = ld.ParseFile(ld.Fset, filename, src) |
| 1121 | } |
| 1122 | |
| 1123 | close(v.ready) |
| 1124 | } |
| 1125 | return v.f, v.err |
| 1126 | } |
| 1127 | |
| 1128 | // parseFiles reads and parses the Go source files and returns the ASTs |
| 1129 | // of the ones that could be at least partially parsed, along with a |
| 1130 | // list of I/O and parse errors encountered. |
| 1131 | // |
| 1132 | // Because files are scanned in parallel, the token.Pos |
| 1133 | // positions of the resulting ast.Files are not ordered. |
| 1134 | func (ld *loader) parseFiles(filenames []string) ([]*ast.File, []error) { |
| 1135 | var wg sync.WaitGroup |
| 1136 | n := len(filenames) |
| 1137 | parsed := make([]*ast.File, n) |
| 1138 | errors := make([]error, n) |
| 1139 | for i, file := range filenames { |
| 1140 | if ld.Config.Context.Err() != nil { |
| 1141 | parsed[i] = nil |
| 1142 | errors[i] = ld.Config.Context.Err() |
| 1143 | continue |
| 1144 | } |
| 1145 | wg.Add(1) |
| 1146 | go func(i int, filename string) { |
| 1147 | parsed[i], errors[i] = ld.parseFile(filename) |
| 1148 | wg.Done() |
| 1149 | }(i, file) |
| 1150 | } |
| 1151 | wg.Wait() |
| 1152 | |
| 1153 | // Eliminate nils, preserving order. |
| 1154 | var o int |
| 1155 | for _, f := range parsed { |
| 1156 | if f != nil { |
| 1157 | parsed[o] = f |
| 1158 | o++ |
| 1159 | } |
| 1160 | } |
| 1161 | parsed = parsed[:o] |
| 1162 | |
| 1163 | o = 0 |
| 1164 | for _, err := range errors { |
| 1165 | if err != nil { |
| 1166 | errors[o] = err |
| 1167 | o++ |
| 1168 | } |
| 1169 | } |
| 1170 | errors = errors[:o] |
| 1171 | |
| 1172 | return parsed, errors |
| 1173 | } |
| 1174 | |
| 1175 | // sameFile returns true if x and y have the same basename and denote |
| 1176 | // the same file. |
| 1177 | func sameFile(x, y string) bool { |
| 1178 | if x == y { |
| 1179 | // It could be the case that y doesn't exist. |
| 1180 | // For instance, it may be an overlay file that |
| 1181 | // hasn't been written to disk. To handle that case |
| 1182 | // let x == y through. (We added the exact absolute path |
| 1183 | // string to the CompiledGoFiles list, so the unwritten |
| 1184 | // overlay case implies x==y.) |
| 1185 | return true |
| 1186 | } |
| 1187 | if strings.EqualFold(filepath.Base(x), filepath.Base(y)) { // (optimisation) |
| 1188 | if xi, err := os.Stat(x); err == nil { |
| 1189 | if yi, err := os.Stat(y); err == nil { |
| 1190 | return os.SameFile(xi, yi) |
| 1191 | } |
| 1192 | } |
| 1193 | } |
| 1194 | return false |
| 1195 | } |
| 1196 | |
| 1197 | // loadFromExportData returns type information for the specified |
| 1198 | // package, loading it from an export data file on the first request. |
| 1199 | func (ld *loader) loadFromExportData(lpkg *loaderPackage) (*types.Package, error) { |
| 1200 | if lpkg.PkgPath == "" { |
| 1201 | log.Fatalf("internal error: Package %s has no PkgPath", lpkg) |
| 1202 | } |
| 1203 | |
| 1204 | // Because gcexportdata.Read has the potential to create or |
| 1205 | // modify the types.Package for each node in the transitive |
| 1206 | // closure of dependencies of lpkg, all exportdata operations |
| 1207 | // must be sequential. (Finer-grained locking would require |
| 1208 | // changes to the gcexportdata API.) |
| 1209 | // |
| 1210 | // The exportMu lock guards the Package.Pkg field and the |
| 1211 | // types.Package it points to, for each Package in the graph. |
| 1212 | // |
| 1213 | // Not all accesses to Package.Pkg need to be protected by exportMu: |
| 1214 | // graph ordering ensures that direct dependencies of source |
| 1215 | // packages are fully loaded before the importer reads their Pkg field. |
| 1216 | ld.exportMu.Lock() |
| 1217 | defer ld.exportMu.Unlock() |
| 1218 | |
| 1219 | if tpkg := lpkg.Types; tpkg != nil && tpkg.Complete() { |
| 1220 | return tpkg, nil // cache hit |
| 1221 | } |
| 1222 | |
| 1223 | lpkg.IllTyped = true // fail safe |
| 1224 | |
| 1225 | if lpkg.ExportFile == "" { |
| 1226 | // Errors while building export data will have been printed to stderr. |
| 1227 | return nil, fmt.Errorf("no export data file") |
| 1228 | } |
| 1229 | f, err := os.Open(lpkg.ExportFile) |
| 1230 | if err != nil { |
| 1231 | return nil, err |
| 1232 | } |
| 1233 | defer f.Close() |
| 1234 | |
| 1235 | // Read gc export data. |
| 1236 | // |
| 1237 | // We don't currently support gccgo export data because all |
| 1238 | // underlying workspaces use the gc toolchain. (Even build |
| 1239 | // systems that support gccgo don't use it for workspace |
| 1240 | // queries.) |
| 1241 | r, err := gcexportdata.NewReader(f) |
| 1242 | if err != nil { |
| 1243 | return nil, fmt.Errorf("reading %s: %v", lpkg.ExportFile, err) |
| 1244 | } |
| 1245 | |
| 1246 | // Build the view. |
| 1247 | // |
| 1248 | // The gcexportdata machinery has no concept of package ID. |
| 1249 | // It identifies packages by their PkgPath, which although not |
| 1250 | // globally unique is unique within the scope of one invocation |
| 1251 | // of the linker, type-checker, or gcexportdata. |
| 1252 | // |
| 1253 | // So, we must build a PkgPath-keyed view of the global |
| 1254 | // (conceptually ID-keyed) cache of packages and pass it to |
| 1255 | // gcexportdata. The view must contain every existing |
| 1256 | // package that might possibly be mentioned by the |
| 1257 | // current package---its transitive closure. |
| 1258 | // |
| 1259 | // In loadPackage, we unconditionally create a types.Package for |
| 1260 | // each dependency so that export data loading does not |
| 1261 | // create new ones. |
| 1262 | // |
| 1263 | // TODO(adonovan): it would be simpler and more efficient |
| 1264 | // if the export data machinery invoked a callback to |
| 1265 | // get-or-create a package instead of a map. |
| 1266 | // |
| 1267 | view := make(map[string]*types.Package) // view seen by gcexportdata |
| 1268 | seen := make(map[*loaderPackage]bool) // all visited packages |
| 1269 | var visit func(pkgs map[string]*Package) |
| 1270 | visit = func(pkgs map[string]*Package) { |
| 1271 | for _, p := range pkgs { |
| 1272 | lpkg := ld.pkgs[p.ID] |
| 1273 | if !seen[lpkg] { |
| 1274 | seen[lpkg] = true |
| 1275 | view[lpkg.PkgPath] = lpkg.Types |
| 1276 | visit(lpkg.Imports) |
| 1277 | } |
| 1278 | } |
| 1279 | } |
| 1280 | visit(lpkg.Imports) |
| 1281 | |
| 1282 | viewLen := len(view) + 1 // adding the self package |
| 1283 | // Parse the export data. |
| 1284 | // (May modify incomplete packages in view but not create new ones.) |
| 1285 | tpkg, err := gcexportdata.Read(r, ld.Fset, view, lpkg.PkgPath) |
| 1286 | if err != nil { |
| 1287 | return nil, fmt.Errorf("reading %s: %v", lpkg.ExportFile, err) |
| 1288 | } |
| 1289 | if _, ok := view["go.shape"]; ok { |
| 1290 | // Account for the pseudopackage "go.shape" that gets |
| 1291 | // created by generic code. |
| 1292 | viewLen++ |
| 1293 | } |
| 1294 | if viewLen != len(view) { |
| 1295 | log.Panicf("golang.org/x/tools/go/packages: unexpected new packages during load of %s", lpkg.PkgPath) |
| 1296 | } |
| 1297 | |
| 1298 | lpkg.Types = tpkg |
| 1299 | lpkg.IllTyped = false |
| 1300 | |
| 1301 | return tpkg, nil |
| 1302 | } |
| 1303 | |
| 1304 | // impliedLoadMode returns loadMode with its dependencies. |
| 1305 | func impliedLoadMode(loadMode LoadMode) LoadMode { |
| 1306 | if loadMode&(NeedDeps|NeedTypes|NeedTypesInfo) != 0 { |
| 1307 | // All these things require knowing the import graph. |
| 1308 | loadMode |= NeedImports |
| 1309 | } |
| 1310 | |
| 1311 | return loadMode |
| 1312 | } |
| 1313 | |
| 1314 | func usesExportData(cfg *Config) bool { |
| 1315 | return cfg.Mode&NeedExportFile != 0 || cfg.Mode&NeedTypes != 0 && cfg.Mode&NeedDeps == 0 |
| 1316 | } |
| 1317 | |
| 1318 | var _ interface{} = io.Discard // assert build toolchain is go1.16 or later |
| 1319 |
Members