本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1087 lines
33KB

  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. package loader
  5. // See doc.go for package documentation and implementation notes.
  6. import (
  7. "errors"
  8. "fmt"
  9. "go/ast"
  10. "go/build"
  11. "go/parser"
  12. "go/token"
  13. "go/types"
  14. "os"
  15. "path/filepath"
  16. "sort"
  17. "strings"
  18. "sync"
  19. "time"
  20. "golang.org/x/tools/go/ast/astutil"
  21. "golang.org/x/tools/go/internal/cgo"
  22. )
  23. var ignoreVendor build.ImportMode
  24. const trace = false // show timing info for type-checking
  25. // Config specifies the configuration for loading a whole program from
  26. // Go source code.
  27. // The zero value for Config is a ready-to-use default configuration.
  28. type Config struct {
  29. // Fset is the file set for the parser to use when loading the
  30. // program. If nil, it may be lazily initialized by any
  31. // method of Config.
  32. Fset *token.FileSet
  33. // ParserMode specifies the mode to be used by the parser when
  34. // loading source packages.
  35. ParserMode parser.Mode
  36. // TypeChecker contains options relating to the type checker.
  37. //
  38. // The supplied IgnoreFuncBodies is not used; the effective
  39. // value comes from the TypeCheckFuncBodies func below.
  40. // The supplied Import function is not used either.
  41. TypeChecker types.Config
  42. // TypeCheckFuncBodies is a predicate over package paths.
  43. // A package for which the predicate is false will
  44. // have its package-level declarations type checked, but not
  45. // its function bodies; this can be used to quickly load
  46. // dependencies from source. If nil, all func bodies are type
  47. // checked.
  48. TypeCheckFuncBodies func(path string) bool
  49. // If Build is non-nil, it is used to locate source packages.
  50. // Otherwise &build.Default is used.
  51. //
  52. // By default, cgo is invoked to preprocess Go files that
  53. // import the fake package "C". This behaviour can be
  54. // disabled by setting CGO_ENABLED=0 in the environment prior
  55. // to startup, or by setting Build.CgoEnabled=false.
  56. Build *build.Context
  57. // The current directory, used for resolving relative package
  58. // references such as "./go/loader". If empty, os.Getwd will be
  59. // used instead.
  60. Cwd string
  61. // If DisplayPath is non-nil, it is used to transform each
  62. // file name obtained from Build.Import(). This can be used
  63. // to prevent a virtualized build.Config's file names from
  64. // leaking into the user interface.
  65. DisplayPath func(path string) string
  66. // If AllowErrors is true, Load will return a Program even
  67. // if some of the its packages contained I/O, parser or type
  68. // errors; such errors are accessible via PackageInfo.Errors. If
  69. // false, Load will fail if any package had an error.
  70. AllowErrors bool
  71. // CreatePkgs specifies a list of non-importable initial
  72. // packages to create. The resulting packages will appear in
  73. // the corresponding elements of the Program.Created slice.
  74. CreatePkgs []PkgSpec
  75. // ImportPkgs specifies a set of initial packages to load.
  76. // The map keys are package paths.
  77. //
  78. // The map value indicates whether to load tests. If true, Load
  79. // will add and type-check two lists of files to the package:
  80. // non-test files followed by in-package *_test.go files. In
  81. // addition, it will append the external test package (if any)
  82. // to Program.Created.
  83. ImportPkgs map[string]bool
  84. // FindPackage is called during Load to create the build.Package
  85. // for a given import path from a given directory.
  86. // If FindPackage is nil, (*build.Context).Import is used.
  87. // A client may use this hook to adapt to a proprietary build
  88. // system that does not follow the "go build" layout
  89. // conventions, for example.
  90. //
  91. // It must be safe to call concurrently from multiple goroutines.
  92. FindPackage func(ctxt *build.Context, importPath, fromDir string, mode build.ImportMode) (*build.Package, error)
  93. // AfterTypeCheck is called immediately after a list of files
  94. // has been type-checked and appended to info.Files.
  95. //
  96. // This optional hook function is the earliest opportunity for
  97. // the client to observe the output of the type checker,
  98. // which may be useful to reduce analysis latency when loading
  99. // a large program.
  100. //
  101. // The function is permitted to modify info.Info, for instance
  102. // to clear data structures that are no longer needed, which can
  103. // dramatically reduce peak memory consumption.
  104. //
  105. // The function may be called twice for the same PackageInfo:
  106. // once for the files of the package and again for the
  107. // in-package test files.
  108. //
  109. // It must be safe to call concurrently from multiple goroutines.
  110. AfterTypeCheck func(info *PackageInfo, files []*ast.File)
  111. }
  112. // A PkgSpec specifies a non-importable package to be created by Load.
  113. // Files are processed first, but typically only one of Files and
  114. // Filenames is provided. The path needn't be globally unique.
  115. //
  116. // For vendoring purposes, the package's directory is the one that
  117. // contains the first file.
  118. type PkgSpec struct {
  119. Path string // package path ("" => use package declaration)
  120. Files []*ast.File // ASTs of already-parsed files
  121. Filenames []string // names of files to be parsed
  122. }
  123. // A Program is a Go program loaded from source as specified by a Config.
  124. type Program struct {
  125. Fset *token.FileSet // the file set for this program
  126. // Created[i] contains the initial package whose ASTs or
  127. // filenames were supplied by Config.CreatePkgs[i], followed by
  128. // the external test package, if any, of each package in
  129. // Config.ImportPkgs ordered by ImportPath.
  130. //
  131. // NOTE: these files must not import "C". Cgo preprocessing is
  132. // only performed on imported packages, not ad hoc packages.
  133. //
  134. // TODO(adonovan): we need to copy and adapt the logic of
  135. // goFilesPackage (from $GOROOT/src/cmd/go/build.go) and make
  136. // Config.Import and Config.Create methods return the same kind
  137. // of entity, essentially a build.Package.
  138. // Perhaps we can even reuse that type directly.
  139. Created []*PackageInfo
  140. // Imported contains the initially imported packages,
  141. // as specified by Config.ImportPkgs.
  142. Imported map[string]*PackageInfo
  143. // AllPackages contains the PackageInfo of every package
  144. // encountered by Load: all initial packages and all
  145. // dependencies, including incomplete ones.
  146. AllPackages map[*types.Package]*PackageInfo
  147. // importMap is the canonical mapping of package paths to
  148. // packages. It contains all Imported initial packages, but not
  149. // Created ones, and all imported dependencies.
  150. importMap map[string]*types.Package
  151. }
  152. // PackageInfo holds the ASTs and facts derived by the type-checker
  153. // for a single package.
  154. //
  155. // Not mutated once exposed via the API.
  156. //
  157. type PackageInfo struct {
  158. Pkg *types.Package
  159. Importable bool // true if 'import "Pkg.Path()"' would resolve to this
  160. TransitivelyErrorFree bool // true if Pkg and all its dependencies are free of errors
  161. Files []*ast.File // syntax trees for the package's files
  162. Errors []error // non-nil if the package had errors
  163. types.Info // type-checker deductions.
  164. dir string // package directory
  165. checker *types.Checker // transient type-checker state
  166. errorFunc func(error)
  167. }
  168. func (info *PackageInfo) String() string { return info.Pkg.Path() }
  169. func (info *PackageInfo) appendError(err error) {
  170. if info.errorFunc != nil {
  171. info.errorFunc(err)
  172. } else {
  173. fmt.Fprintln(os.Stderr, err)
  174. }
  175. info.Errors = append(info.Errors, err)
  176. }
  177. func (conf *Config) fset() *token.FileSet {
  178. if conf.Fset == nil {
  179. conf.Fset = token.NewFileSet()
  180. }
  181. return conf.Fset
  182. }
  183. // ParseFile is a convenience function (intended for testing) that invokes
  184. // the parser using the Config's FileSet, which is initialized if nil.
  185. //
  186. // src specifies the parser input as a string, []byte, or io.Reader, and
  187. // filename is its apparent name. If src is nil, the contents of
  188. // filename are read from the file system.
  189. //
  190. func (conf *Config) ParseFile(filename string, src interface{}) (*ast.File, error) {
  191. // TODO(adonovan): use conf.build() etc like parseFiles does.
  192. return parser.ParseFile(conf.fset(), filename, src, conf.ParserMode)
  193. }
  194. // FromArgsUsage is a partial usage message that applications calling
  195. // FromArgs may wish to include in their -help output.
  196. const FromArgsUsage = `
  197. <args> is a list of arguments denoting a set of initial packages.
  198. It may take one of two forms:
  199. 1. A list of *.go source files.
  200. All of the specified files are loaded, parsed and type-checked
  201. as a single package. All the files must belong to the same directory.
  202. 2. A list of import paths, each denoting a package.
  203. The package's directory is found relative to the $GOROOT and
  204. $GOPATH using similar logic to 'go build', and the *.go files in
  205. that directory are loaded, parsed and type-checked as a single
  206. package.
  207. In addition, all *_test.go files in the directory are then loaded
  208. and parsed. Those files whose package declaration equals that of
  209. the non-*_test.go files are included in the primary package. Test
  210. files whose package declaration ends with "_test" are type-checked
  211. as another package, the 'external' test package, so that a single
  212. import path may denote two packages. (Whether this behaviour is
  213. enabled is tool-specific, and may depend on additional flags.)
  214. A '--' argument terminates the list of packages.
  215. `
  216. // FromArgs interprets args as a set of initial packages to load from
  217. // source and updates the configuration. It returns the list of
  218. // unconsumed arguments.
  219. //
  220. // It is intended for use in command-line interfaces that require a
  221. // set of initial packages to be specified; see FromArgsUsage message
  222. // for details.
  223. //
  224. // Only superficial errors are reported at this stage; errors dependent
  225. // on I/O are detected during Load.
  226. //
  227. func (conf *Config) FromArgs(args []string, xtest bool) ([]string, error) {
  228. var rest []string
  229. for i, arg := range args {
  230. if arg == "--" {
  231. rest = args[i+1:]
  232. args = args[:i]
  233. break // consume "--" and return the remaining args
  234. }
  235. }
  236. if len(args) > 0 && strings.HasSuffix(args[0], ".go") {
  237. // Assume args is a list of a *.go files
  238. // denoting a single ad hoc package.
  239. for _, arg := range args {
  240. if !strings.HasSuffix(arg, ".go") {
  241. return nil, fmt.Errorf("named files must be .go files: %s", arg)
  242. }
  243. }
  244. conf.CreateFromFilenames("", args...)
  245. } else {
  246. // Assume args are directories each denoting a
  247. // package and (perhaps) an external test, iff xtest.
  248. for _, arg := range args {
  249. if xtest {
  250. conf.ImportWithTests(arg)
  251. } else {
  252. conf.Import(arg)
  253. }
  254. }
  255. }
  256. return rest, nil
  257. }
  258. // CreateFromFilenames is a convenience function that adds
  259. // a conf.CreatePkgs entry to create a package of the specified *.go
  260. // files.
  261. //
  262. func (conf *Config) CreateFromFilenames(path string, filenames ...string) {
  263. conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Filenames: filenames})
  264. }
  265. // CreateFromFiles is a convenience function that adds a conf.CreatePkgs
  266. // entry to create package of the specified path and parsed files.
  267. //
  268. func (conf *Config) CreateFromFiles(path string, files ...*ast.File) {
  269. conf.CreatePkgs = append(conf.CreatePkgs, PkgSpec{Path: path, Files: files})
  270. }
  271. // ImportWithTests is a convenience function that adds path to
  272. // ImportPkgs, the set of initial source packages located relative to
  273. // $GOPATH. The package will be augmented by any *_test.go files in
  274. // its directory that contain a "package x" (not "package x_test")
  275. // declaration.
  276. //
  277. // In addition, if any *_test.go files contain a "package x_test"
  278. // declaration, an additional package comprising just those files will
  279. // be added to CreatePkgs.
  280. //
  281. func (conf *Config) ImportWithTests(path string) { conf.addImport(path, true) }
  282. // Import is a convenience function that adds path to ImportPkgs, the
  283. // set of initial packages that will be imported from source.
  284. //
  285. func (conf *Config) Import(path string) { conf.addImport(path, false) }
  286. func (conf *Config) addImport(path string, tests bool) {
  287. if path == "C" {
  288. return // ignore; not a real package
  289. }
  290. if conf.ImportPkgs == nil {
  291. conf.ImportPkgs = make(map[string]bool)
  292. }
  293. conf.ImportPkgs[path] = conf.ImportPkgs[path] || tests
  294. }
  295. // PathEnclosingInterval returns the PackageInfo and ast.Node that
  296. // contain source interval [start, end), and all the node's ancestors
  297. // up to the AST root. It searches all ast.Files of all packages in prog.
  298. // exact is defined as for astutil.PathEnclosingInterval.
  299. //
  300. // The zero value is returned if not found.
  301. //
  302. func (prog *Program) PathEnclosingInterval(start, end token.Pos) (pkg *PackageInfo, path []ast.Node, exact bool) {
  303. for _, info := range prog.AllPackages {
  304. for _, f := range info.Files {
  305. if f.Pos() == token.NoPos {
  306. // This can happen if the parser saw
  307. // too many errors and bailed out.
  308. // (Use parser.AllErrors to prevent that.)
  309. continue
  310. }
  311. if !tokenFileContainsPos(prog.Fset.File(f.Pos()), start) {
  312. continue
  313. }
  314. if path, exact := astutil.PathEnclosingInterval(f, start, end); path != nil {
  315. return info, path, exact
  316. }
  317. }
  318. }
  319. return nil, nil, false
  320. }
  321. // InitialPackages returns a new slice containing the set of initial
  322. // packages (Created + Imported) in unspecified order.
  323. //
  324. func (prog *Program) InitialPackages() []*PackageInfo {
  325. infos := make([]*PackageInfo, 0, len(prog.Created)+len(prog.Imported))
  326. infos = append(infos, prog.Created...)
  327. for _, info := range prog.Imported {
  328. infos = append(infos, info)
  329. }
  330. return infos
  331. }
  332. // Package returns the ASTs and results of type checking for the
  333. // specified package.
  334. func (prog *Program) Package(path string) *PackageInfo {
  335. if info, ok := prog.AllPackages[prog.importMap[path]]; ok {
  336. return info
  337. }
  338. for _, info := range prog.Created {
  339. if path == info.Pkg.Path() {
  340. return info
  341. }
  342. }
  343. return nil
  344. }
  345. // ---------- Implementation ----------
  346. // importer holds the working state of the algorithm.
  347. type importer struct {
  348. conf *Config // the client configuration
  349. start time.Time // for logging
  350. progMu sync.Mutex // guards prog
  351. prog *Program // the resulting program
  352. // findpkg is a memoization of FindPackage.
  353. findpkgMu sync.Mutex // guards findpkg
  354. findpkg map[findpkgKey]*findpkgValue
  355. importedMu sync.Mutex // guards imported
  356. imported map[string]*importInfo // all imported packages (incl. failures) by import path
  357. // import dependency graph: graph[x][y] => x imports y
  358. //
  359. // Since non-importable packages cannot be cyclic, we ignore
  360. // their imports, thus we only need the subgraph over importable
  361. // packages. Nodes are identified by their import paths.
  362. graphMu sync.Mutex
  363. graph map[string]map[string]bool
  364. }
  365. type findpkgKey struct {
  366. importPath string
  367. fromDir string
  368. mode build.ImportMode
  369. }
  370. type findpkgValue struct {
  371. ready chan struct{} // closed to broadcast readiness
  372. bp *build.Package
  373. err error
  374. }
  375. // importInfo tracks the success or failure of a single import.
  376. //
  377. // Upon completion, exactly one of info and err is non-nil:
  378. // info on successful creation of a package, err otherwise.
  379. // A successful package may still contain type errors.
  380. //
  381. type importInfo struct {
  382. path string // import path
  383. info *PackageInfo // results of typechecking (including errors)
  384. complete chan struct{} // closed to broadcast that info is set.
  385. }
  386. // awaitCompletion blocks until ii is complete,
  387. // i.e. the info field is safe to inspect.
  388. func (ii *importInfo) awaitCompletion() {
  389. <-ii.complete // wait for close
  390. }
  391. // Complete marks ii as complete.
  392. // Its info and err fields will not be subsequently updated.
  393. func (ii *importInfo) Complete(info *PackageInfo) {
  394. if info == nil {
  395. panic("info == nil")
  396. }
  397. ii.info = info
  398. close(ii.complete)
  399. }
  400. type importError struct {
  401. path string // import path
  402. err error // reason for failure to create a package
  403. }
  404. // Load creates the initial packages specified by conf.{Create,Import}Pkgs,
  405. // loading their dependencies packages as needed.
  406. //
  407. // On success, Load returns a Program containing a PackageInfo for
  408. // each package. On failure, it returns an error.
  409. //
  410. // If AllowErrors is true, Load will return a Program even if some
  411. // packages contained I/O, parser or type errors, or if dependencies
  412. // were missing. (Such errors are accessible via PackageInfo.Errors. If
  413. // false, Load will fail if any package had an error.
  414. //
  415. // It is an error if no packages were loaded.
  416. //
  417. func (conf *Config) Load() (*Program, error) {
  418. // Create a simple default error handler for parse/type errors.
  419. if conf.TypeChecker.Error == nil {
  420. conf.TypeChecker.Error = func(e error) { fmt.Fprintln(os.Stderr, e) }
  421. }
  422. // Set default working directory for relative package references.
  423. if conf.Cwd == "" {
  424. var err error
  425. conf.Cwd, err = os.Getwd()
  426. if err != nil {
  427. return nil, err
  428. }
  429. }
  430. // Install default FindPackage hook using go/build logic.
  431. if conf.FindPackage == nil {
  432. conf.FindPackage = (*build.Context).Import
  433. }
  434. prog := &Program{
  435. Fset: conf.fset(),
  436. Imported: make(map[string]*PackageInfo),
  437. importMap: make(map[string]*types.Package),
  438. AllPackages: make(map[*types.Package]*PackageInfo),
  439. }
  440. imp := importer{
  441. conf: conf,
  442. prog: prog,
  443. findpkg: make(map[findpkgKey]*findpkgValue),
  444. imported: make(map[string]*importInfo),
  445. start: time.Now(),
  446. graph: make(map[string]map[string]bool),
  447. }
  448. // -- loading proper (concurrent phase) --------------------------------
  449. var errpkgs []string // packages that contained errors
  450. // Load the initially imported packages and their dependencies,
  451. // in parallel.
  452. // No vendor check on packages imported from the command line.
  453. infos, importErrors := imp.importAll("", conf.Cwd, conf.ImportPkgs, ignoreVendor)
  454. for _, ie := range importErrors {
  455. conf.TypeChecker.Error(ie.err) // failed to create package
  456. errpkgs = append(errpkgs, ie.path)
  457. }
  458. for _, info := range infos {
  459. prog.Imported[info.Pkg.Path()] = info
  460. }
  461. // Augment the designated initial packages by their tests.
  462. // Dependencies are loaded in parallel.
  463. var xtestPkgs []*build.Package
  464. for importPath, augment := range conf.ImportPkgs {
  465. if !augment {
  466. continue
  467. }
  468. // No vendor check on packages imported from command line.
  469. bp, err := imp.findPackage(importPath, conf.Cwd, ignoreVendor)
  470. if err != nil {
  471. // Package not found, or can't even parse package declaration.
  472. // Already reported by previous loop; ignore it.
  473. continue
  474. }
  475. // Needs external test package?
  476. if len(bp.XTestGoFiles) > 0 {
  477. xtestPkgs = append(xtestPkgs, bp)
  478. }
  479. // Consult the cache using the canonical package path.
  480. path := bp.ImportPath
  481. imp.importedMu.Lock() // (unnecessary, we're sequential here)
  482. ii, ok := imp.imported[path]
  483. // Paranoid checks added due to issue #11012.
  484. if !ok {
  485. // Unreachable.
  486. // The previous loop called importAll and thus
  487. // startLoad for each path in ImportPkgs, which
  488. // populates imp.imported[path] with a non-zero value.
  489. panic(fmt.Sprintf("imported[%q] not found", path))
  490. }
  491. if ii == nil {
  492. // Unreachable.
  493. // The ii values in this loop are the same as in
  494. // the previous loop, which enforced the invariant
  495. // that at least one of ii.err and ii.info is non-nil.
  496. panic(fmt.Sprintf("imported[%q] == nil", path))
  497. }
  498. if ii.info == nil {
  499. // Unreachable.
  500. // awaitCompletion has the postcondition
  501. // ii.info != nil.
  502. panic(fmt.Sprintf("imported[%q].info = nil", path))
  503. }
  504. info := ii.info
  505. imp.importedMu.Unlock()
  506. // Parse the in-package test files.
  507. files, errs := imp.conf.parsePackageFiles(bp, 't')
  508. for _, err := range errs {
  509. info.appendError(err)
  510. }
  511. // The test files augmenting package P cannot be imported,
  512. // but may import packages that import P,
  513. // so we must disable the cycle check.
  514. imp.addFiles(info, files, false)
  515. }
  516. createPkg := func(path, dir string, files []*ast.File, errs []error) {
  517. info := imp.newPackageInfo(path, dir)
  518. for _, err := range errs {
  519. info.appendError(err)
  520. }
  521. // Ad hoc packages are non-importable,
  522. // so no cycle check is needed.
  523. // addFiles loads dependencies in parallel.
  524. imp.addFiles(info, files, false)
  525. prog.Created = append(prog.Created, info)
  526. }
  527. // Create packages specified by conf.CreatePkgs.
  528. for _, cp := range conf.CreatePkgs {
  529. files, errs := parseFiles(conf.fset(), conf.build(), nil, conf.Cwd, cp.Filenames, conf.ParserMode)
  530. files = append(files, cp.Files...)
  531. path := cp.Path
  532. if path == "" {
  533. if len(files) > 0 {
  534. path = files[0].Name.Name
  535. } else {
  536. path = "(unnamed)"
  537. }
  538. }
  539. dir := conf.Cwd
  540. if len(files) > 0 && files[0].Pos().IsValid() {
  541. dir = filepath.Dir(conf.fset().File(files[0].Pos()).Name())
  542. }
  543. createPkg(path, dir, files, errs)
  544. }
  545. // Create external test packages.
  546. sort.Sort(byImportPath(xtestPkgs))
  547. for _, bp := range xtestPkgs {
  548. files, errs := imp.conf.parsePackageFiles(bp, 'x')
  549. createPkg(bp.ImportPath+"_test", bp.Dir, files, errs)
  550. }
  551. // -- finishing up (sequential) ----------------------------------------
  552. if len(prog.Imported)+len(prog.Created) == 0 {
  553. return nil, errors.New("no initial packages were loaded")
  554. }
  555. // Create infos for indirectly imported packages.
  556. // e.g. incomplete packages without syntax, loaded from export data.
  557. for _, obj := range prog.importMap {
  558. info := prog.AllPackages[obj]
  559. if info == nil {
  560. prog.AllPackages[obj] = &PackageInfo{Pkg: obj, Importable: true}
  561. } else {
  562. // finished
  563. info.checker = nil
  564. info.errorFunc = nil
  565. }
  566. }
  567. if !conf.AllowErrors {
  568. // Report errors in indirectly imported packages.
  569. for _, info := range prog.AllPackages {
  570. if len(info.Errors) > 0 {
  571. errpkgs = append(errpkgs, info.Pkg.Path())
  572. }
  573. }
  574. if errpkgs != nil {
  575. var more string
  576. if len(errpkgs) > 3 {
  577. more = fmt.Sprintf(" and %d more", len(errpkgs)-3)
  578. errpkgs = errpkgs[:3]
  579. }
  580. return nil, fmt.Errorf("couldn't load packages due to errors: %s%s",
  581. strings.Join(errpkgs, ", "), more)
  582. }
  583. }
  584. markErrorFreePackages(prog.AllPackages)
  585. return prog, nil
  586. }
  587. type byImportPath []*build.Package
  588. func (b byImportPath) Len() int { return len(b) }
  589. func (b byImportPath) Less(i, j int) bool { return b[i].ImportPath < b[j].ImportPath }
  590. func (b byImportPath) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
  591. // markErrorFreePackages sets the TransitivelyErrorFree flag on all
  592. // applicable packages.
  593. func markErrorFreePackages(allPackages map[*types.Package]*PackageInfo) {
  594. // Build the transpose of the import graph.
  595. importedBy := make(map[*types.Package]map[*types.Package]bool)
  596. for P := range allPackages {
  597. for _, Q := range P.Imports() {
  598. clients, ok := importedBy[Q]
  599. if !ok {
  600. clients = make(map[*types.Package]bool)
  601. importedBy[Q] = clients
  602. }
  603. clients[P] = true
  604. }
  605. }
  606. // Find all packages reachable from some error package.
  607. reachable := make(map[*types.Package]bool)
  608. var visit func(*types.Package)
  609. visit = func(p *types.Package) {
  610. if !reachable[p] {
  611. reachable[p] = true
  612. for q := range importedBy[p] {
  613. visit(q)
  614. }
  615. }
  616. }
  617. for _, info := range allPackages {
  618. if len(info.Errors) > 0 {
  619. visit(info.Pkg)
  620. }
  621. }
  622. // Mark the others as "transitively error-free".
  623. for _, info := range allPackages {
  624. if !reachable[info.Pkg] {
  625. info.TransitivelyErrorFree = true
  626. }
  627. }
  628. }
  629. // build returns the effective build context.
  630. func (conf *Config) build() *build.Context {
  631. if conf.Build != nil {
  632. return conf.Build
  633. }
  634. return &build.Default
  635. }
  636. // parsePackageFiles enumerates the files belonging to package path,
  637. // then loads, parses and returns them, plus a list of I/O or parse
  638. // errors that were encountered.
  639. //
  640. // 'which' indicates which files to include:
  641. // 'g': include non-test *.go source files (GoFiles + processed CgoFiles)
  642. // 't': include in-package *_test.go source files (TestGoFiles)
  643. // 'x': include external *_test.go source files. (XTestGoFiles)
  644. //
  645. func (conf *Config) parsePackageFiles(bp *build.Package, which rune) ([]*ast.File, []error) {
  646. if bp.ImportPath == "unsafe" {
  647. return nil, nil
  648. }
  649. var filenames []string
  650. switch which {
  651. case 'g':
  652. filenames = bp.GoFiles
  653. case 't':
  654. filenames = bp.TestGoFiles
  655. case 'x':
  656. filenames = bp.XTestGoFiles
  657. default:
  658. panic(which)
  659. }
  660. files, errs := parseFiles(conf.fset(), conf.build(), conf.DisplayPath, bp.Dir, filenames, conf.ParserMode)
  661. // Preprocess CgoFiles and parse the outputs (sequentially).
  662. if which == 'g' && bp.CgoFiles != nil {
  663. cgofiles, err := cgo.ProcessFiles(bp, conf.fset(), conf.DisplayPath, conf.ParserMode)
  664. if err != nil {
  665. errs = append(errs, err)
  666. } else {
  667. files = append(files, cgofiles...)
  668. }
  669. }
  670. return files, errs
  671. }
  672. // doImport imports the package denoted by path.
  673. // It implements the types.Importer signature.
  674. //
  675. // It returns an error if a package could not be created
  676. // (e.g. go/build or parse error), but type errors are reported via
  677. // the types.Config.Error callback (the first of which is also saved
  678. // in the package's PackageInfo).
  679. //
  680. // Idempotent.
  681. //
  682. func (imp *importer) doImport(from *PackageInfo, to string) (*types.Package, error) {
  683. if to == "C" {
  684. // This should be unreachable, but ad hoc packages are
  685. // not currently subject to cgo preprocessing.
  686. // See https://golang.org/issue/11627.
  687. return nil, fmt.Errorf(`the loader doesn't cgo-process ad hoc packages like %q; see Go issue 11627`,
  688. from.Pkg.Path())
  689. }
  690. bp, err := imp.findPackage(to, from.dir, 0)
  691. if err != nil {
  692. return nil, err
  693. }
  694. // The standard unsafe package is handled specially,
  695. // and has no PackageInfo.
  696. if bp.ImportPath == "unsafe" {
  697. return types.Unsafe, nil
  698. }
  699. // Look for the package in the cache using its canonical path.
  700. path := bp.ImportPath
  701. imp.importedMu.Lock()
  702. ii := imp.imported[path]
  703. imp.importedMu.Unlock()
  704. if ii == nil {
  705. panic("internal error: unexpected import: " + path)
  706. }
  707. if ii.info != nil {
  708. return ii.info.Pkg, nil
  709. }
  710. // Import of incomplete package: this indicates a cycle.
  711. fromPath := from.Pkg.Path()
  712. if cycle := imp.findPath(path, fromPath); cycle != nil {
  713. // Normalize cycle: start from alphabetically largest node.
  714. pos, start := -1, ""
  715. for i, s := range cycle {
  716. if pos < 0 || s > start {
  717. pos, start = i, s
  718. }
  719. }
  720. cycle = append(cycle, cycle[:pos]...)[pos:] // rotate cycle to start from largest
  721. cycle = append(cycle, cycle[0]) // add start node to end to show cycliness
  722. return nil, fmt.Errorf("import cycle: %s", strings.Join(cycle, " -> "))
  723. }
  724. panic("internal error: import of incomplete (yet acyclic) package: " + fromPath)
  725. }
  726. // findPackage locates the package denoted by the importPath in the
  727. // specified directory.
  728. func (imp *importer) findPackage(importPath, fromDir string, mode build.ImportMode) (*build.Package, error) {
  729. // We use a non-blocking duplicate-suppressing cache (gopl.io §9.7)
  730. // to avoid holding the lock around FindPackage.
  731. key := findpkgKey{importPath, fromDir, mode}
  732. imp.findpkgMu.Lock()
  733. v, ok := imp.findpkg[key]
  734. if ok {
  735. // cache hit
  736. imp.findpkgMu.Unlock()
  737. <-v.ready // wait for entry to become ready
  738. } else {
  739. // Cache miss: this goroutine becomes responsible for
  740. // populating the map entry and broadcasting its readiness.
  741. v = &findpkgValue{ready: make(chan struct{})}
  742. imp.findpkg[key] = v
  743. imp.findpkgMu.Unlock()
  744. ioLimit <- true
  745. v.bp, v.err = imp.conf.FindPackage(imp.conf.build(), importPath, fromDir, mode)
  746. <-ioLimit
  747. if _, ok := v.err.(*build.NoGoError); ok {
  748. v.err = nil // empty directory is not an error
  749. }
  750. close(v.ready) // broadcast ready condition
  751. }
  752. return v.bp, v.err
  753. }
  754. // importAll loads, parses, and type-checks the specified packages in
  755. // parallel and returns their completed importInfos in unspecified order.
  756. //
  757. // fromPath is the package path of the importing package, if it is
  758. // importable, "" otherwise. It is used for cycle detection.
  759. //
  760. // fromDir is the directory containing the import declaration that
  761. // caused these imports.
  762. //
  763. func (imp *importer) importAll(fromPath, fromDir string, imports map[string]bool, mode build.ImportMode) (infos []*PackageInfo, errors []importError) {
  764. // TODO(adonovan): opt: do the loop in parallel once
  765. // findPackage is non-blocking.
  766. var pending []*importInfo
  767. for importPath := range imports {
  768. bp, err := imp.findPackage(importPath, fromDir, mode)
  769. if err != nil {
  770. errors = append(errors, importError{
  771. path: importPath,
  772. err: err,
  773. })
  774. continue
  775. }
  776. pending = append(pending, imp.startLoad(bp))
  777. }
  778. if fromPath != "" {
  779. // We're loading a set of imports.
  780. //
  781. // We must record graph edges from the importing package
  782. // to its dependencies, and check for cycles.
  783. imp.graphMu.Lock()
  784. deps, ok := imp.graph[fromPath]
  785. if !ok {
  786. deps = make(map[string]bool)
  787. imp.graph[fromPath] = deps
  788. }
  789. for _, ii := range pending {
  790. deps[ii.path] = true
  791. }
  792. imp.graphMu.Unlock()
  793. }
  794. for _, ii := range pending {
  795. if fromPath != "" {
  796. if cycle := imp.findPath(ii.path, fromPath); cycle != nil {
  797. // Cycle-forming import: we must not await its
  798. // completion since it would deadlock.
  799. //
  800. // We don't record the error in ii since
  801. // the error is really associated with the
  802. // cycle-forming edge, not the package itself.
  803. // (Also it would complicate the
  804. // invariants of importPath completion.)
  805. if trace {
  806. fmt.Fprintf(os.Stderr, "import cycle: %q\n", cycle)
  807. }
  808. continue
  809. }
  810. }
  811. ii.awaitCompletion()
  812. infos = append(infos, ii.info)
  813. }
  814. return infos, errors
  815. }
  816. // findPath returns an arbitrary path from 'from' to 'to' in the import
  817. // graph, or nil if there was none.
  818. func (imp *importer) findPath(from, to string) []string {
  819. imp.graphMu.Lock()
  820. defer imp.graphMu.Unlock()
  821. seen := make(map[string]bool)
  822. var search func(stack []string, importPath string) []string
  823. search = func(stack []string, importPath string) []string {
  824. if !seen[importPath] {
  825. seen[importPath] = true
  826. stack = append(stack, importPath)
  827. if importPath == to {
  828. return stack
  829. }
  830. for x := range imp.graph[importPath] {
  831. if p := search(stack, x); p != nil {
  832. return p
  833. }
  834. }
  835. }
  836. return nil
  837. }
  838. return search(make([]string, 0, 20), from)
  839. }
  840. // startLoad initiates the loading, parsing and type-checking of the
  841. // specified package and its dependencies, if it has not already begun.
  842. //
  843. // It returns an importInfo, not necessarily in a completed state. The
  844. // caller must call awaitCompletion() before accessing its info field.
  845. //
  846. // startLoad is concurrency-safe and idempotent.
  847. //
  848. func (imp *importer) startLoad(bp *build.Package) *importInfo {
  849. path := bp.ImportPath
  850. imp.importedMu.Lock()
  851. ii, ok := imp.imported[path]
  852. if !ok {
  853. ii = &importInfo{path: path, complete: make(chan struct{})}
  854. imp.imported[path] = ii
  855. go func() {
  856. info := imp.load(bp)
  857. ii.Complete(info)
  858. }()
  859. }
  860. imp.importedMu.Unlock()
  861. return ii
  862. }
  863. // load implements package loading by parsing Go source files
  864. // located by go/build.
  865. func (imp *importer) load(bp *build.Package) *PackageInfo {
  866. info := imp.newPackageInfo(bp.ImportPath, bp.Dir)
  867. info.Importable = true
  868. files, errs := imp.conf.parsePackageFiles(bp, 'g')
  869. for _, err := range errs {
  870. info.appendError(err)
  871. }
  872. imp.addFiles(info, files, true)
  873. imp.progMu.Lock()
  874. imp.prog.importMap[bp.ImportPath] = info.Pkg
  875. imp.progMu.Unlock()
  876. return info
  877. }
  878. // addFiles adds and type-checks the specified files to info, loading
  879. // their dependencies if needed. The order of files determines the
  880. // package initialization order. It may be called multiple times on the
  881. // same package. Errors are appended to the info.Errors field.
  882. //
  883. // cycleCheck determines whether the imports within files create
  884. // dependency edges that should be checked for potential cycles.
  885. //
  886. func (imp *importer) addFiles(info *PackageInfo, files []*ast.File, cycleCheck bool) {
  887. // Ensure the dependencies are loaded, in parallel.
  888. var fromPath string
  889. if cycleCheck {
  890. fromPath = info.Pkg.Path()
  891. }
  892. // TODO(adonovan): opt: make the caller do scanImports.
  893. // Callers with a build.Package can skip it.
  894. imp.importAll(fromPath, info.dir, scanImports(files), 0)
  895. if trace {
  896. fmt.Fprintf(os.Stderr, "%s: start %q (%d)\n",
  897. time.Since(imp.start), info.Pkg.Path(), len(files))
  898. }
  899. // Don't call checker.Files on Unsafe, even with zero files,
  900. // because it would mutate the package, which is a global.
  901. if info.Pkg == types.Unsafe {
  902. if len(files) > 0 {
  903. panic(`"unsafe" package contains unexpected files`)
  904. }
  905. } else {
  906. // Ignore the returned (first) error since we
  907. // already collect them all in the PackageInfo.
  908. info.checker.Files(files)
  909. info.Files = append(info.Files, files...)
  910. }
  911. if imp.conf.AfterTypeCheck != nil {
  912. imp.conf.AfterTypeCheck(info, files)
  913. }
  914. if trace {
  915. fmt.Fprintf(os.Stderr, "%s: stop %q\n",
  916. time.Since(imp.start), info.Pkg.Path())
  917. }
  918. }
  919. func (imp *importer) newPackageInfo(path, dir string) *PackageInfo {
  920. var pkg *types.Package
  921. if path == "unsafe" {
  922. pkg = types.Unsafe
  923. } else {
  924. pkg = types.NewPackage(path, "")
  925. }
  926. info := &PackageInfo{
  927. Pkg: pkg,
  928. Info: types.Info{
  929. Types: make(map[ast.Expr]types.TypeAndValue),
  930. Defs: make(map[*ast.Ident]types.Object),
  931. Uses: make(map[*ast.Ident]types.Object),
  932. Implicits: make(map[ast.Node]types.Object),
  933. Scopes: make(map[ast.Node]*types.Scope),
  934. Selections: make(map[*ast.SelectorExpr]*types.Selection),
  935. },
  936. errorFunc: imp.conf.TypeChecker.Error,
  937. dir: dir,
  938. }
  939. // Copy the types.Config so we can vary it across PackageInfos.
  940. tc := imp.conf.TypeChecker
  941. tc.IgnoreFuncBodies = false
  942. if f := imp.conf.TypeCheckFuncBodies; f != nil {
  943. tc.IgnoreFuncBodies = !f(path)
  944. }
  945. tc.Importer = closure{imp, info}
  946. tc.Error = info.appendError // appendError wraps the user's Error function
  947. info.checker = types.NewChecker(&tc, imp.conf.fset(), pkg, &info.Info)
  948. imp.progMu.Lock()
  949. imp.prog.AllPackages[pkg] = info
  950. imp.progMu.Unlock()
  951. return info
  952. }
  953. type closure struct {
  954. imp *importer
  955. info *PackageInfo
  956. }
  957. func (c closure) Import(to string) (*types.Package, error) { return c.imp.doImport(c.info, to) }
上海开阖软件有限公司 沪ICP备12045867号-1