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