github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/loader/loader.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 loads, parses and type-checks packages of Go code 6 // plus their transitive closure, and retains both the ASTs and the 7 // derived facts. 8 // 9 // THIS INTERFACE IS EXPERIMENTAL AND IS LIKELY TO CHANGE. 10 // 11 // The package defines two primary types: Config, which specifies a 12 // set of initial packages to load and various other options; and 13 // Program, which is the result of successfully loading the packages 14 // specified by a configuration. 15 // 16 // The configuration can be set directly, but *Config provides various 17 // convenience methods to simplify the common cases, each of which can 18 // be called any number of times. Finally, these are followed by a 19 // call to Load() to actually load and type-check the program. 20 // 21 // var conf loader.Config 22 // 23 // // Use the command-line arguments to specify 24 // // a set of initial packages to load from source. 25 // // See FromArgsUsage for help. 26 // rest, err := conf.FromArgs(os.Args[1:], wantTests) 27 // 28 // // Parse the specified files and create an ad-hoc package with path "foo". 29 // // All files must have the same 'package' declaration. 30 // conf.CreateFromFilenames("foo", "foo.go", "bar.go") 31 // 32 // // Create an ad-hoc package with path "foo" from 33 // // the specified already-parsed files. 34 // // All ASTs must have the same 'package' declaration. 35 // conf.CreateFromFiles("foo", parsedFiles) 36 // 37 // // Add "runtime" to the set of packages to be loaded. 38 // conf.Import("runtime") 39 // 40 // // Adds "fmt" and "fmt_test" to the set of packages 41 // // to be loaded. "fmt" will include *_test.go files. 42 // conf.ImportWithTests("fmt") 43 // 44 // // Finally, load all the packages specified by the configuration. 45 // prog, err := conf.Load() 46 // 47 // 48 // CONCEPTS AND TERMINOLOGY 49 // 50 // An AD-HOC package is one specified as a set of source files on the 51 // command line. In the simplest case, it may consist of a single file 52 // such as $GOROOT/src/net/http/triv.go. 53 // 54 // EXTERNAL TEST packages are those comprised of a set of *_test.go 55 // files all with the same 'package foo_test' declaration, all in the 56 // same directory. (go/build.Package calls these files XTestFiles.) 57 // 58 // An IMPORTABLE package is one that can be referred to by some import 59 // spec. The Path() of each importable package is unique within a 60 // Program. 61 // 62 // Ad-hoc packages and external test packages are NON-IMPORTABLE. The 63 // Path() of an ad-hoc package is inferred from the package 64 // declarations of its files and is therefore not a unique package key. 65 // For example, Config.CreatePkgs may specify two initial ad-hoc 66 // packages both called "main". 67 // 68 // An AUGMENTED package is an importable package P plus all the 69 // *_test.go files with same 'package foo' declaration as P. 70 // (go/build.Package calls these files TestFiles.) 71 // 72 // The INITIAL packages are those specified in the configuration. A 73 // DEPENDENCY is a package loaded to satisfy an import in an initial 74 // package or another dependency. 75 // 76 package loader 77 78 // 'go test', in-package test files, and import cycles 79 // --------------------------------------------------- 80 // 81 // An external test package may depend upon members of the augmented 82 // package that are not in the unaugmented package, such as functions 83 // that expose internals. (See bufio/export_test.go for an example.) 84 // So, the loader must ensure that for each external test package 85 // it loads, it also augments the corresponding non-test package. 86 // 87 // The import graph over n unaugmented packages must be acyclic; the 88 // import graph over n-1 unaugmented packages plus one augmented 89 // package must also be acyclic. ('go test' relies on this.) But the 90 // import graph over n augmented packages may contain cycles. 91 // 92 // First, all the (unaugmented) non-test packages and their 93 // dependencies are imported in the usual way; the loader reports an 94 // error if it detects an import cycle. 95 // 96 // Then, each package P for which testing is desired is augmented by 97 // the list P' of its in-package test files, by calling 98 // (*types.Checker).Files. This arrangement ensures that P' may 99 // reference definitions within P, but P may not reference definitions 100 // within P'. Furthermore, P' may import any other package, including 101 // ones that depend upon P, without an import cycle error. 102 // 103 // Consider two packages A and B, both of which have lists of 104 // in-package test files we'll call A' and B', and which have the 105 // following import graph edges: 106 // B imports A 107 // B' imports A 108 // A' imports B 109 // This last edge would be expected to create an error were it not 110 // for the special type-checking discipline above. 111 // Cycles of size greater than two are possible. For example: 112 // compress/bzip2/bzip2_test.go (package bzip2) imports "io/ioutil" 113 // io/ioutil/tempfile_test.go (package ioutil) imports "regexp" 114 // regexp/exec_test.go (package regexp) imports "compress/bzip2" 115 // 116 // 117 // Concurrency 118 // ----------- 119 // 120 // Let us define the import dependency graph as follows. Each node is a 121 // list of files passed to (Checker).Files at once. Many of these lists 122 // are the production code of an importable Go package, so those nodes 123 // are labelled by the package's import path. The remaining nodes are 124 // ad-hoc packages and lists of in-package *_test.go files that augment 125 // an importable package; those nodes have no label. 126 // 127 // The edges of the graph represent import statements appearing within a 128 // file. An edge connects a node (a list of files) to the node it 129 // imports, which is importable and thus always labelled. 130 // 131 // Loading is controlled by this dependency graph. 132 // 133 // To reduce I/O latency, we start loading a package's dependencies 134 // asynchronously as soon as we've parsed its files and enumerated its 135 // imports (scanImports). This performs a preorder traversal of the 136 // import dependency graph. 137 // 138 // To exploit hardware parallelism, we type-check unrelated packages in 139 // parallel, where "unrelated" means not ordered by the partial order of 140 // the import dependency graph. 141 // 142 // We use a concurrency-safe blocking cache (importer.imported) to 143 // record the results of type-checking, whether success or failure. An 144 // entry is created in this cache by startLoad the first time the 145 // package is imported. The first goroutine to request an entry becomes 146 // responsible for completing the task and broadcasting completion to 147 // subsequent requestors, which block until then. 148 // 149 // Type checking occurs in (parallel) postorder: we cannot type-check a 150 // set of files until we have loaded and type-checked all of their 151 // immediate dependencies (and thus all of their transitive 152 // dependencies). If the input were guaranteed free of import cycles, 153 // this would be trivial: we could simply wait for completion of the 154 // dependencies and then invoke the typechecker. 155 // 156 // But as we saw in the 'go test' section above, some cycles in the 157 // import graph over packages are actually legal, so long as the 158 // cycle-forming edge originates in the in-package test files that 159 // augment the package. This explains why the nodes of the import 160 // dependency graph are not packages, but lists of files: the unlabelled 161 // nodes avoid the cycles. Consider packages A and B where B imports A 162 // and A's in-package tests AT import B. The naively constructed import 163 // graph over packages would contain a cycle (A+AT) --> B --> (A+AT) but 164 // the graph over lists of files is AT --> B --> A, where AT is an 165 // unlabelled node. 166 // 167 // Awaiting completion of the dependencies in a cyclic graph would 168 // deadlock, so we must materialize the import dependency graph (as 169 // importer.graph) and check whether each import edge forms a cycle. If 170 // x imports y, and the graph already contains a path from y to x, then 171 // there is an import cycle, in which case the processing of x must not 172 // wait for the completion of processing of y. 173 // 174 // When the type-checker makes a callback (doImport) to the loader for a 175 // given import edge, there are two possible cases. In the normal case, 176 // the dependency has already been completely type-checked; doImport 177 // does a cache lookup and returns it. In the cyclic case, the entry in 178 // the cache is still necessarily incomplete, indicating a cycle. We 179 // perform the cycle check again to obtain the error message, and return 180 // the error. 181 // 182 // The result of using concurrency is about a 2.5x speedup for stdlib_test. 183 184 // TODO(adonovan): 185 // - cache the calls to build.Import so we don't do it three times per 186 // test package. 187 // - Thorough overhaul of package documentation. 188 189 import ( 190 "errors" 191 "fmt" 192 "go/ast" 193 "go/build" 194 "go/parser" 195 "go/token" 196 "os" 197 "sort" 198 "strings" 199 "sync" 200 "time" 201 202 "llvm.org/llgo/third_party/gotools/go/ast/astutil" 203 "llvm.org/llgo/third_party/gotools/go/gcimporter" 204 "llvm.org/llgo/third_party/gotools/go/types" 205 ) 206 207 const trace = false // show timing info for type-checking 208 209 // Config specifies the configuration for a program to load. 210 // The zero value for Config is a ready-to-use default configuration. 211 type Config struct { 212 // Fset is the file set for the parser to use when loading the 213 // program. If nil, it may be lazily initialized by any 214 // method of Config. 215 Fset *token.FileSet 216 217 // ParserMode specifies the mode to be used by the parser when 218 // loading source packages. 219 ParserMode parser.Mode 220 221 // TypeChecker contains options relating to the type checker. 222 // 223 // The supplied IgnoreFuncBodies is not used; the effective 224 // value comes from the TypeCheckFuncBodies func below. 225 // 226 // TypeChecker.Packages is lazily initialized during Load. 227 TypeChecker types.Config 228 229 // TypeCheckFuncBodies is a predicate over package import 230 // paths. A package for which the predicate is false will 231 // have its package-level declarations type checked, but not 232 // its function bodies; this can be used to quickly load 233 // dependencies from source. If nil, all func bodies are type 234 // checked. 235 TypeCheckFuncBodies func(string) bool 236 237 // ImportFromBinary determines whether to satisfy dependencies by 238 // loading gc export data instead of Go source code. 239 // 240 // If false, the entire program---the initial packages and their 241 // transitive closure of dependencies---will be loaded from 242 // source, parsed, and type-checked. This is required for 243 // whole-program analyses such as pointer analysis. 244 // 245 // If true, the go/gcimporter mechanism is used instead to read 246 // the binary export-data files written by the gc toolchain. 247 // They supply only the types of package-level declarations and 248 // values of constants, but no code, this option will not yield 249 // a whole program. It is intended for analyses that perform 250 // modular analysis of a single package, e.g. traditional 251 // compilation. 252 // 253 // No check is made that the export data files are up-to-date. 254 // 255 // The initial packages (CreatePkgs and ImportPkgs) are always 256 // loaded from Go source, regardless of this flag's setting. 257 // 258 // NB: there is a bug when loading multiple initial packages with 259 // this flag enabled: https://github.com/golang/go/issues/9955. 260 ImportFromBinary bool 261 262 // If Build is non-nil, it is used to locate source packages. 263 // Otherwise &build.Default is used. 264 // 265 // By default, cgo is invoked to preprocess Go files that 266 // import the fake package "C". This behaviour can be 267 // disabled by setting CGO_ENABLED=0 in the environment prior 268 // to startup, or by setting Build.CgoEnabled=false. 269 Build *build.Context 270 271 // The current directory, used for resolving relative package 272 // references such as "./go/loader". If empty, os.Getwd will be 273 // used instead. 274 Cwd string 275 276 // If DisplayPath is non-nil, it is used to transform each 277 // file name obtained from Build.Import(). This can be used 278 // to prevent a virtualized build.Config's file names from 279 // leaking into the user interface. 280 DisplayPath func(path string) string 281 282 // If AllowErrors is true, Load will return a Program even 283 // if some of the its packages contained I/O, parser or type 284 // errors; such errors are accessible via PackageInfo.Errors. If 285 // false, Load will fail if any package had an error. 286 AllowErrors bool 287 288 // CreatePkgs specifies a list of non-importable initial 289 // packages to create. The resulting packages will appear in 290 // the corresponding elements of the Program.Created slice. 291 CreatePkgs []PkgSpec 292 293 // ImportPkgs specifies a set of initial packages to load from 294 // source. The map keys are package import paths, used to 295 // locate the package relative to $GOROOT. 296 // 297 // The map value indicates whether to load tests. If true, Load 298 // will add and type-check two lists of files to the package: 299 // non-test files followed by in-package *_test.go files. In 300 // addition, it will append the external test package (if any) 301 // to Program.Created. 302 ImportPkgs map[string]bool 303 304 // FindPackage is called during Load to create the build.Package 305 // for a given import path. If nil, a default implementation 306 // based on ctxt.Import is used. A client may use this hook to 307 // adapt to a proprietary build system that does not follow the 308 // "go build" layout conventions, for example. 309 // 310 // It must be safe to call concurrently from multiple goroutines. 311 FindPackage func(ctxt *build.Context, importPath string) (*build.Package, error) 312 313 // PackageCreated is a hook called when a types.Package 314 // is created but before it has been populated. 315 // 316 // The package's import Path() and Scope() are defined, 317 // but not its Name() since no package declaration has 318 // been seen yet. 319 // 320 // Clients may use this to insert synthetic items into 321 // the package scope, for example. 322 // 323 // It must be safe to call concurrently from multiple goroutines. 324 PackageCreated func(*types.Package) 325 } 326 327 // A PkgSpec specifies a non-importable package to be created by Load. 328 // Files are processed first, but typically only one of Files and 329 // Filenames is provided. The path needn't be globally unique. 330 // 331 type PkgSpec struct { 332 Path string // import path ("" => use package declaration) 333 Files []*ast.File // ASTs of already-parsed files 334 Filenames []string // names of files to be parsed 335 } 336 337 // A Program is a Go program loaded from source or binary 338 // as specified by a Config. 339 type Program struct { 340 Fset *token.FileSet // the file set for this program 341 342 // Created[i] contains the initial package whose ASTs or 343 // filenames were supplied by Config.CreatePkgs[i], followed by 344 // the external test package, if any, of each package in 345 // Config.ImportPkgs ordered by ImportPath. 346 Created []*PackageInfo 347 348 // Imported contains the initially imported packages, 349 // as specified by Config.ImportPkgs. 350 Imported map[string]*PackageInfo 351 352 // ImportMap is the canonical mapping of import paths to 353 // packages used by the type-checker (Config.TypeChecker.Packages). 354 // It contains all Imported initial packages, but not Created 355 // ones, and all imported dependencies. 356 ImportMap map[string]*types.Package 357 358 // AllPackages contains the PackageInfo of every package 359 // encountered by Load: all initial packages and all 360 // dependencies, including incomplete ones. 361 AllPackages map[*types.Package]*PackageInfo 362 } 363 364 // PackageInfo holds the ASTs and facts derived by the type-checker 365 // for a single package. 366 // 367 // Not mutated once exposed via the API. 368 // 369 type PackageInfo struct { 370 Pkg *types.Package 371 Importable bool // true if 'import "Pkg.Path()"' would resolve to this 372 TransitivelyErrorFree bool // true if Pkg and all its dependencies are free of errors 373 Files []*ast.File // syntax trees for the package's files 374 Errors []error // non-nil if the package had errors 375 types.Info // type-checker deductions. 376 377 checker *types.Checker // transient type-checker state 378 errorFunc func(error) 379 } 380 381 func (info *PackageInfo) String() string { return info.Pkg.Path() } 382 383 func (info *PackageInfo) appendError(err error) { 384 if info.errorFunc != nil { 385 info.errorFunc(err) 386 } else { 387 fmt.Fprintln(os.Stderr, err) 388 } 389 info.Errors = append(info.Errors, err) 390 } 391 392 func (conf *Config) fset() *token.FileSet { 393 if conf.Fset == nil { 394 conf.Fset = token.NewFileSet() 395 } 396 return conf.Fset 397 } 398 399 // ParseFile is a convenience function (intended for testing) that invokes 400 // the parser using the Config's FileSet, which is initialized if nil. 401 // 402 // src specifies the parser input as a string, []byte, or io.Reader, and 403 // filename is its apparent name. If src is nil, the contents of 404 // filename are read from the file system. 405 // 406 func (conf *Config) ParseFile(filename string, src interface{}) (*ast.File, error) { 407 // TODO(adonovan): use conf.build() etc like parseFiles does. 408 return parser.ParseFile(conf.fset(), filename, src, conf.ParserMode) 409 } 410 411 // FromArgsUsage is a partial usage message that applications calling 412 // FromArgs may wish to include in their -help output. 413 const FromArgsUsage = ` 414 <args> is a list of arguments denoting a set of initial packages. 415 It may take one of two forms: 416 417 1. A list of *.go source files. 418 419 All of the specified files are loaded, parsed and type-checked 420 as a single package. All the files must belong to the same directory. 421 422 2. A list of import paths, each denoting a package. 423 424 The package's directory is found relative to the $GOROOT and 425 $GOPATH using similar logic to 'go build', and the *.go files in 426 that directory are loaded, parsed and type-checked as a single 427 package. 428 429 In addition, all *_test.go files in the directory are then loaded 430 and parsed. Those files whose package declaration equals that of 431 the non-*_test.go files are included in the primary package. Test 432 files whose package declaration ends with "_test" are type-checked 433 as another package, the 'external' test package, so that a single 434 import path may denote two packages. (Whether this behaviour is 435 enabled is tool-specific, and may depend on additional flags.) 436 437 A '--' argument terminates the list of packages. 438 ` 439 440 // FromArgs interprets args as a set of initial packages to load from 441 // source and updates the configuration. It returns the list of 442 // unconsumed arguments. 443 // 444 // It is intended for use in command-line interfaces that require a 445 // set of initial packages to be specified; see FromArgsUsage message 446 // for details. 447 // 448 // Only superficial errors are reported at this stage; errors dependent 449 // on I/O are detected during Load. 450 // 451 func (conf *Config) FromArgs(args []string, xtest bool) ([]string, error) { 452 var rest []string 453 for i, arg := range args { 454 if arg == "--" { 455 rest = args[i+1:] 456 args = args[:i] 457 break // consume "--" and return the remaining args 458 } 459 } 460 461 if len(args) > 0 && strings.HasSuffix(args[0], ".go") { 462 // Assume args is a list of a *.go files 463 // denoting a single ad-hoc package. 464 for _, arg := range args { 465 if !strings.HasSuffix(arg, ".go") { 466 return nil, fmt.Errorf("named files must be .go files: %s", arg) 467 } 468 } 469 conf.CreateFromFilenames("", args...) 470 } else { 471 // Assume args are directories each denoting a 472 // package and (perhaps) an external test, iff xtest. 473 for _, arg := range args { 474 if xtest { 475 conf.ImportWithTests(arg) 476 } else { 477 conf.Import(arg) 478 } 479 } 480 } 481 482 return rest, nil 483 } 484 485 // CreateFromFilenames is a convenience function that adds 486 // a conf.CreatePkgs entry to create a package of the specified *.go 487 // files. 488 // 489 func (conf *Config) CreateFromFilenames(path string, filenames ...string) { 490 conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Filenames: filenames}) 491 } 492 493 // CreateFromFiles is a convenience function that adds a conf.CreatePkgs 494 // entry to create package of the specified path and parsed files. 495 // 496 func (conf *Config) CreateFromFiles(path string, files ...*ast.File) { 497 conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Files: files}) 498 } 499 500 // ImportWithTests is a convenience function that adds path to 501 // ImportPkgs, the set of initial source packages located relative to 502 // $GOPATH. The package will be augmented by any *_test.go files in 503 // its directory that contain a "package x" (not "package x_test") 504 // declaration. 505 // 506 // In addition, if any *_test.go files contain a "package x_test" 507 // declaration, an additional package comprising just those files will 508 // be added to CreatePkgs. 509 // 510 func (conf *Config) ImportWithTests(path string) { conf.addImport(path, true) } 511 512 // Import is a convenience function that adds path to ImportPkgs, the 513 // set of initial packages that will be imported from source. 514 // 515 func (conf *Config) Import(path string) { conf.addImport(path, false) } 516 517 func (conf *Config) addImport(path string, tests bool) { 518 if path == "unsafe" { 519 return // ignore; not a real package 520 } 521 if conf.ImportPkgs == nil { 522 conf.ImportPkgs = make(map[string]bool) 523 } 524 conf.ImportPkgs[path] = conf.ImportPkgs[path] || tests 525 } 526 527 // PathEnclosingInterval returns the PackageInfo and ast.Node that 528 // contain source interval [start, end), and all the node's ancestors 529 // up to the AST root. It searches all ast.Files of all packages in prog. 530 // exact is defined as for astutil.PathEnclosingInterval. 531 // 532 // The zero value is returned if not found. 533 // 534 func (prog *Program) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) { 535 for _, info := range prog.AllPackages { 536 for _, f := range info.Files { 537 if !tokenFileContainsPos(prog.Fset.File(f.Pos()), start) { 538 continue 539 } 540 if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil { 541 return info, path, exact 542 } 543 } 544 } 545 return nil, nil, false 546 } 547 548 // InitialPackages returns a new slice containing the set of initial 549 // packages (Created + Imported) in unspecified order. 550 // 551 func (prog *Program) InitialPackages() []*PackageInfo { 552 infos := make([]*PackageInfo, 0, len(prog.Created)+len(prog.Imported)) 553 infos = append(infos, prog.Created...) 554 for _, info := range prog.Imported { 555 infos = append(infos, info) 556 } 557 return infos 558 } 559 560 // ---------- Implementation ---------- 561 562 // importer holds the working state of the algorithm. 563 type importer struct { 564 conf *Config // the client configuration 565 prog *Program // resulting program 566 start time.Time // for logging 567 568 // This mutex serializes access to prog.ImportMap (aka 569 // TypeChecker.Packages); we also use it for AllPackages. 570 // 571 // The TypeChecker.Packages map is not really used by this 572 // package, but may be used by the client's Import function, 573 // and by clients of the returned Program. 574 typecheckerMu sync.Mutex 575 576 importedMu sync.Mutex 577 imported map[string]*importInfo // all imported packages (incl. failures) by import path 578 579 // import dependency graph: graph[x][y] => x imports y 580 // 581 // Since non-importable packages cannot be cyclic, we ignore 582 // their imports, thus we only need the subgraph over importable 583 // packages. Nodes are identified by their import paths. 584 graphMu sync.Mutex 585 graph map[string]map[string]bool 586 } 587 588 // importInfo tracks the success or failure of a single import. 589 // 590 // Upon completion, exactly one of info and err is non-nil: 591 // info on successful creation of a package, err otherwise. 592 // A successful package may still contain type errors. 593 // 594 type importInfo struct { 595 path string // import path 596 mu sync.Mutex // guards the following fields prior to completion 597 info *PackageInfo // results of typechecking (including errors) 598 err error // reason for failure to create a package 599 complete sync.Cond // complete condition is that one of info, err is non-nil. 600 } 601 602 // awaitCompletion blocks until ii is complete, 603 // i.e. the info and err fields are safe to inspect without a lock. 604 // It is concurrency-safe and idempotent. 605 func (ii *importInfo) awaitCompletion() { 606 ii.mu.Lock() 607 for ii.info == nil && ii.err == nil { 608 ii.complete.Wait() 609 } 610 ii.mu.Unlock() 611 } 612 613 // Complete marks ii as complete. 614 // Its info and err fields will not be subsequently updated. 615 func (ii *importInfo) Complete(info *PackageInfo, err error) { 616 ii.mu.Lock() 617 ii.info = info 618 ii.err = err 619 ii.complete.Broadcast() 620 ii.mu.Unlock() 621 } 622 623 // Load creates the initial packages specified by conf.{Create,Import}Pkgs, 624 // loading their dependencies packages as needed. 625 // 626 // On success, Load returns a Program containing a PackageInfo for 627 // each package. On failure, it returns an error. 628 // 629 // If AllowErrors is true, Load will return a Program even if some 630 // packages contained I/O, parser or type errors, or if dependencies 631 // were missing. (Such errors are accessible via PackageInfo.Errors. If 632 // false, Load will fail if any package had an error. 633 // 634 // It is an error if no packages were loaded. 635 // 636 func (conf *Config) Load() (*Program, error) { 637 // Initialize by setting the conf's copy, so all copies of 638 // TypeChecker agree on the identity of the map. 639 if conf.TypeChecker.Packages == nil { 640 conf.TypeChecker.Packages = make(map[string]*types.Package) 641 } 642 643 // Create a simple default error handler for parse/type errors. 644 if conf.TypeChecker.Error == nil { 645 conf.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) } 646 } 647 648 // Set default working directory for relative package references. 649 if conf.Cwd == "" { 650 var err error 651 conf.Cwd, err = os.Getwd() 652 if err != nil { 653 return nil, err 654 } 655 } 656 657 // Install default FindPackage hook using go/build logic. 658 if conf.FindPackage == nil { 659 conf.FindPackage = func(ctxt *build.Context, path string) (*build.Package, error) { 660 bp, err := ctxt.Import(path, conf.Cwd, 0) 661 if _, ok := err.(*build.NoGoError); ok { 662 return bp, nil // empty directory is not an error 663 } 664 return bp, err 665 } 666 } 667 668 prog := &Program{ 669 Fset: conf.fset(), 670 Imported: make(map[string]*PackageInfo), 671 ImportMap: conf.TypeChecker.Packages, 672 AllPackages: make(map[*types.Package]*PackageInfo), 673 } 674 675 imp := importer{ 676 conf: conf, 677 prog: prog, 678 imported: make(map[string]*importInfo), 679 start: time.Now(), 680 graph: make(map[string]map[string]bool), 681 } 682 683 // -- loading proper (concurrent phase) -------------------------------- 684 685 var errpkgs []string // packages that contained errors 686 687 // Load the initially imported packages and their dependencies, 688 // in parallel. 689 for _, ii := range imp.loadAll("", conf.ImportPkgs) { 690 if ii.err != nil { 691 conf.TypeChecker.Error(ii.err) // failed to create package 692 errpkgs = append(errpkgs, ii.path) 693 continue 694 } 695 prog.Imported[ii.info.Pkg.Path()] = ii.info 696 } 697 698 // Augment the designated initial packages by their tests. 699 // Dependencies are loaded in parallel. 700 var xtestPkgs []*build.Package 701 for path, augment := range conf.ImportPkgs { 702 if !augment { 703 continue 704 } 705 706 bp, err := conf.FindPackage(conf.build(), path) 707 if err != nil { 708 // Package not found, or can't even parse package declaration. 709 // Already reported by previous loop; ignore it. 710 continue 711 } 712 713 // Needs external test package? 714 if len(bp.XTestGoFiles) > 0 { 715 xtestPkgs = append(xtestPkgs, bp) 716 } 717 718 imp.importedMu.Lock() // (unnecessary, we're sequential here) 719 info := imp.imported[path].info // must be non-nil, see above 720 imp.importedMu.Unlock() 721 722 // Parse the in-package test files. 723 files, errs := imp.conf.parsePackageFiles(bp, 't') 724 for _, err := range errs { 725 info.appendError(err) 726 } 727 728 // The test files augmenting package P cannot be imported, 729 // but may import packages that import P, 730 // so we must disable the cycle check. 731 imp.addFiles(info, files, false) 732 } 733 734 createPkg := func(path string, files []*ast.File, errs []error) { 735 info := imp.newPackageInfo(path) 736 for _, err := range errs { 737 info.appendError(err) 738 } 739 740 // Ad-hoc packages are non-importable, 741 // so no cycle check is needed. 742 // addFiles loads dependencies in parallel. 743 imp.addFiles(info, files, false) 744 prog.Created = append(prog.Created, info) 745 } 746 747 // Create packages specified by conf.CreatePkgs. 748 for _, cp := range conf.CreatePkgs { 749 files, errs := parseFiles(conf.fset(), conf.build(), nil, ".", cp.Filenames, conf.ParserMode) 750 files = append(files, cp.Files...) 751 752 path := cp.Path 753 if path == "" { 754 if len(files) > 0 { 755 path = files[0].Name.Name 756 } else { 757 path = "(unnamed)" 758 } 759 } 760 createPkg(path, files, errs) 761 } 762 763 // Create external test packages. 764 sort.Sort(byImportPath(xtestPkgs)) 765 for _, bp := range xtestPkgs { 766 files, errs := imp.conf.parsePackageFiles(bp, 'x') 767 createPkg(bp.ImportPath+"_test", files, errs) 768 } 769 770 // -- finishing up (sequential) ---------------------------------------- 771 772 if len(prog.Imported)+len(prog.Created) == 0 { 773 return nil, errors.New("no initial packages were loaded") 774 } 775 776 // Create infos for indirectly imported packages. 777 // e.g. incomplete packages without syntax, loaded from export data. 778 for _, obj := range prog.ImportMap { 779 info := prog.AllPackages[obj] 780 if info == nil { 781 prog.AllPackages[obj] = &PackageInfo{Pkg: obj, Importable: true} 782 } else { 783 // finished 784 info.checker = nil 785 info.errorFunc = nil 786 } 787 } 788 789 if !conf.AllowErrors { 790 // Report errors in indirectly imported packages. 791 for _, info := range prog.AllPackages { 792 if len(info.Errors) > 0 { 793 errpkgs = append(errpkgs, info.Pkg.Path()) 794 } 795 } 796 if errpkgs != nil { 797 var more string 798 if len(errpkgs) > 3 { 799 more = fmt.Sprintf(" and %d more", len(errpkgs)-3) 800 errpkgs = errpkgs[:3] 801 } 802 return nil, fmt.Errorf("couldn't load packages due to errors: %s%s", 803 strings.Join(errpkgs, ", "), more) 804 } 805 } 806 807 markErrorFreePackages(prog.AllPackages) 808 809 return prog, nil 810 } 811 812 type byImportPath []*build.Package 813 814 func (b byImportPath) Len() int { return len(b) } 815 func (b byImportPath) Less(i, j int) bool { return b[i].ImportPath < b[j].ImportPath } 816 func (b byImportPath) Swap(i, j int) { b[i], b[j] = b[j], b[i] } 817 818 // markErrorFreePackages sets the TransitivelyErrorFree flag on all 819 // applicable packages. 820 func markErrorFreePackages(allPackages map[*types.Package]*PackageInfo) { 821 // Build the transpose of the import graph. 822 importedBy := make(map[*types.Package]map[*types.Package]bool) 823 for P := range allPackages { 824 for _, Q := range P.Imports() { 825 clients, ok := importedBy[Q] 826 if !ok { 827 clients = make(map[*types.Package]bool) 828 importedBy[Q] = clients 829 } 830 clients[P] = true 831 } 832 } 833 834 // Find all packages reachable from some error package. 835 reachable := make(map[*types.Package]bool) 836 var visit func(*types.Package) 837 visit = func(p *types.Package) { 838 if !reachable[p] { 839 reachable[p] = true 840 for q := range importedBy[p] { 841 visit(q) 842 } 843 } 844 } 845 for _, info := range allPackages { 846 if len(info.Errors) > 0 { 847 visit(info.Pkg) 848 } 849 } 850 851 // Mark the others as "transitively error-free". 852 for _, info := range allPackages { 853 if !reachable[info.Pkg] { 854 info.TransitivelyErrorFree = true 855 } 856 } 857 } 858 859 // build returns the effective build context. 860 func (conf *Config) build() *build.Context { 861 if conf.Build != nil { 862 return conf.Build 863 } 864 return &build.Default 865 } 866 867 // parsePackageFiles enumerates the files belonging to package path, 868 // then loads, parses and returns them, plus a list of I/O or parse 869 // errors that were encountered. 870 // 871 // 'which' indicates which files to include: 872 // 'g': include non-test *.go source files (GoFiles + processed CgoFiles) 873 // 't': include in-package *_test.go source files (TestGoFiles) 874 // 'x': include external *_test.go source files. (XTestGoFiles) 875 // 876 func (conf *Config) parsePackageFiles(bp *build.Package, which rune) ([]*ast.File, []error) { 877 var filenames []string 878 switch which { 879 case 'g': 880 filenames = bp.GoFiles 881 case 't': 882 filenames = bp.TestGoFiles 883 case 'x': 884 filenames = bp.XTestGoFiles 885 default: 886 panic(which) 887 } 888 889 files, errs := parseFiles(conf.fset(), conf.build(), conf.DisplayPath, bp.Dir, filenames, conf.ParserMode) 890 891 // Preprocess CgoFiles and parse the outputs (sequentially). 892 if which == 'g' && bp.CgoFiles != nil { 893 cgofiles, err := processCgoFiles(bp, conf.fset(), conf.DisplayPath, conf.ParserMode) 894 if err != nil { 895 errs = append(errs, err) 896 } else { 897 files = append(files, cgofiles...) 898 } 899 } 900 901 return files, errs 902 } 903 904 // doImport imports the package denoted by path. 905 // It implements the types.Importer signature. 906 // 907 // imports is the type-checker's package canonicalization map. 908 // 909 // It returns an error if a package could not be created 910 // (e.g. go/build or parse error), but type errors are reported via 911 // the types.Config.Error callback (the first of which is also saved 912 // in the package's PackageInfo). 913 // 914 // Idempotent. 915 // 916 func (imp *importer) doImport(from *PackageInfo, to string) (*types.Package, error) { 917 // Package unsafe is handled specially, and has no PackageInfo. 918 // TODO(adonovan): move this check into go/types? 919 if to == "unsafe" { 920 return types.Unsafe, nil 921 } 922 923 imp.importedMu.Lock() 924 ii := imp.imported[to] 925 imp.importedMu.Unlock() 926 if ii == nil { 927 panic("internal error: unexpected import: " + to) 928 } 929 if ii.err != nil { 930 return nil, ii.err 931 } 932 if ii.info != nil { 933 return ii.info.Pkg, nil 934 } 935 936 // Import of incomplete package: this indicates a cycle. 937 fromPath := from.Pkg.Path() 938 if cycle := imp.findPath(to, fromPath); cycle != nil { 939 cycle = append([]string{fromPath}, cycle...) 940 return nil, fmt.Errorf("import cycle: %s", strings.Join(cycle, " -> ")) 941 } 942 943 panic("internal error: import of incomplete (yet acyclic) package: " + fromPath) 944 } 945 946 // loadAll loads, parses, and type-checks the specified packages in 947 // parallel and returns their completed importInfos in unspecified order. 948 // 949 // fromPath is the import path of the importing package, if it is 950 // importable, "" otherwise. It is used for cycle detection. 951 // 952 func (imp *importer) loadAll(fromPath string, paths map[string]bool) []*importInfo { 953 result := make([]*importInfo, 0, len(paths)) 954 for path := range paths { 955 result = append(result, imp.startLoad(path)) 956 } 957 958 if fromPath != "" { 959 // We're loading a set of imports. 960 // 961 // We must record graph edges from the importing package 962 // to its dependencies, and check for cycles. 963 imp.graphMu.Lock() 964 deps, ok := imp.graph[fromPath] 965 if !ok { 966 deps = make(map[string]bool) 967 imp.graph[fromPath] = deps 968 } 969 for path := range paths { 970 deps[path] = true 971 } 972 imp.graphMu.Unlock() 973 } 974 975 for _, ii := range result { 976 if fromPath != "" { 977 if cycle := imp.findPath(ii.path, fromPath); cycle != nil { 978 // Cycle-forming import: we must not await its 979 // completion since it would deadlock. 980 // 981 // We don't record the error in ii since 982 // the error is really associated with the 983 // cycle-forming edge, not the package itself. 984 // (Also it would complicate the 985 // invariants of importPath completion.) 986 if trace { 987 fmt.Fprintln(os.Stderr, "import cycle: %q", cycle) 988 } 989 continue 990 } 991 } 992 ii.awaitCompletion() 993 994 } 995 return result 996 } 997 998 // findPath returns an arbitrary path from 'from' to 'to' in the import 999 // graph, or nil if there was none. 1000 func (imp *importer) findPath(from, to string) []string { 1001 imp.graphMu.Lock() 1002 defer imp.graphMu.Unlock() 1003 1004 seen := make(map[string]bool) 1005 var search func(stack []string, importPath string) []string 1006 search = func(stack []string, importPath string) []string { 1007 if !seen[importPath] { 1008 seen[importPath] = true 1009 stack = append(stack, importPath) 1010 if importPath == to { 1011 return stack 1012 } 1013 for x := range imp.graph[importPath] { 1014 if p := search(stack, x); p != nil { 1015 return p 1016 } 1017 } 1018 } 1019 return nil 1020 } 1021 return search(make([]string, 0, 20), from) 1022 } 1023 1024 // startLoad initiates the loading, parsing and type-checking of the 1025 // specified package and its dependencies, if it has not already begun. 1026 // 1027 // It returns an importInfo, not necessarily in a completed state. The 1028 // caller must call awaitCompletion() before accessing its info and err 1029 // fields. 1030 // 1031 // startLoad is concurrency-safe and idempotent. 1032 // 1033 // Precondition: path != "unsafe". 1034 // 1035 func (imp *importer) startLoad(path string) *importInfo { 1036 imp.importedMu.Lock() 1037 ii, ok := imp.imported[path] 1038 if !ok { 1039 ii = &importInfo{path: path} 1040 ii.complete.L = &ii.mu 1041 imp.imported[path] = ii 1042 1043 go imp.load(path, ii) 1044 } 1045 imp.importedMu.Unlock() 1046 1047 return ii 1048 } 1049 1050 func (imp *importer) load(path string, ii *importInfo) { 1051 var info *PackageInfo 1052 var err error 1053 // Find and create the actual package. 1054 if _, ok := imp.conf.ImportPkgs[path]; ok || !imp.conf.ImportFromBinary { 1055 info, err = imp.loadFromSource(path) 1056 } else { 1057 info, err = imp.importFromBinary(path) 1058 } 1059 ii.Complete(info, err) 1060 } 1061 1062 // importFromBinary implements package loading from the client-supplied 1063 // external source, e.g. object files from the gc compiler. 1064 // 1065 func (imp *importer) importFromBinary(path string) (*PackageInfo, error) { 1066 // Determine the caller's effective Import function. 1067 importfn := imp.conf.TypeChecker.Import 1068 if importfn == nil { 1069 importfn = gcimporter.Import 1070 } 1071 imp.typecheckerMu.Lock() 1072 pkg, err := importfn(imp.conf.TypeChecker.Packages, path) 1073 if pkg != nil { 1074 imp.conf.TypeChecker.Packages[path] = pkg 1075 } 1076 imp.typecheckerMu.Unlock() 1077 if err != nil { 1078 return nil, err 1079 } 1080 info := &PackageInfo{Pkg: pkg} 1081 info.Importable = true 1082 imp.typecheckerMu.Lock() 1083 imp.prog.AllPackages[pkg] = info 1084 imp.typecheckerMu.Unlock() 1085 return info, nil 1086 } 1087 1088 // loadFromSource implements package loading by parsing Go source files 1089 // located by go/build. 1090 // The returned PackageInfo's typeCheck function must be called. 1091 // 1092 func (imp *importer) loadFromSource(path string) (*PackageInfo, error) { 1093 bp, err := imp.conf.FindPackage(imp.conf.build(), path) 1094 if err != nil { 1095 return nil, err // package not found 1096 } 1097 info := imp.newPackageInfo(bp.ImportPath) 1098 info.Importable = true 1099 files, errs := imp.conf.parsePackageFiles(bp, 'g') 1100 for _, err := range errs { 1101 info.appendError(err) 1102 } 1103 1104 imp.addFiles(info, files, true) 1105 1106 imp.typecheckerMu.Lock() 1107 imp.conf.TypeChecker.Packages[path] = info.Pkg 1108 imp.typecheckerMu.Unlock() 1109 1110 return info, nil 1111 } 1112 1113 // addFiles adds and type-checks the specified files to info, loading 1114 // their dependencies if needed. The order of files determines the 1115 // package initialization order. It may be called multiple times on the 1116 // same package. Errors are appended to the info.Errors field. 1117 // 1118 // cycleCheck determines whether the imports within files create 1119 // dependency edges that should be checked for potential cycles. 1120 // 1121 func (imp *importer) addFiles(info *PackageInfo, files []*ast.File, cycleCheck bool) { 1122 info.Files = append(info.Files, files...) 1123 1124 // Ensure the dependencies are loaded, in parallel. 1125 var fromPath string 1126 if cycleCheck { 1127 fromPath = info.Pkg.Path() 1128 } 1129 imp.loadAll(fromPath, scanImports(files)) 1130 1131 if trace { 1132 fmt.Fprintf(os.Stderr, "%s: start %q (%d)\n", 1133 time.Since(imp.start), info.Pkg.Path(), len(files)) 1134 } 1135 1136 // Ignore the returned (first) error since we 1137 // already collect them all in the PackageInfo. 1138 info.checker.Files(files) 1139 1140 if trace { 1141 fmt.Fprintf(os.Stderr, "%s: stop %q\n", 1142 time.Since(imp.start), info.Pkg.Path()) 1143 } 1144 } 1145 1146 func (imp *importer) newPackageInfo(path string) *PackageInfo { 1147 pkg := types.NewPackage(path, "") 1148 if imp.conf.PackageCreated != nil { 1149 imp.conf.PackageCreated(pkg) 1150 } 1151 info := &PackageInfo{ 1152 Pkg: pkg, 1153 Info: types.Info{ 1154 Types: make(map[ast.Expr]types.TypeAndValue), 1155 Defs: make(map[*ast.Ident]types.Object), 1156 Uses: make(map[*ast.Ident]types.Object), 1157 Implicits: make(map[ast.Node]types.Object), 1158 Scopes: make(map[ast.Node]*types.Scope), 1159 Selections: make(map[*ast.SelectorExpr]*types.Selection), 1160 }, 1161 errorFunc: imp.conf.TypeChecker.Error, 1162 } 1163 1164 // Copy the types.Config so we can vary it across PackageInfos. 1165 tc := imp.conf.TypeChecker 1166 tc.IgnoreFuncBodies = false 1167 if f := imp.conf.TypeCheckFuncBodies; f != nil { 1168 tc.IgnoreFuncBodies = !f(path) 1169 } 1170 tc.Import = func(_ map[string]*types.Package, to string) (*types.Package, error) { 1171 return imp.doImport(info, to) 1172 } 1173 tc.Error = info.appendError // appendError wraps the user's Error function 1174 1175 info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info) 1176 imp.typecheckerMu.Lock() 1177 imp.prog.AllPackages[pkg] = info 1178 imp.typecheckerMu.Unlock() 1179 return info 1180 }