222 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2018 The Go Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| /*
 | |
| Package packages loads Go packages for inspection and analysis.
 | |
| 
 | |
| The Load function takes as input a list of patterns and return a list of Package
 | |
| structs describing individual packages matched by those patterns.
 | |
| The LoadMode controls the amount of detail in the loaded packages.
 | |
| 
 | |
| Load passes most patterns directly to the underlying build tool,
 | |
| but all patterns with the prefix "query=", where query is a
 | |
| non-empty string of letters from [a-z], are reserved and may be
 | |
| interpreted as query operators.
 | |
| 
 | |
| Two query operators are currently supported: "file" and "pattern".
 | |
| 
 | |
| The query "file=path/to/file.go" matches the package or packages enclosing
 | |
| the Go source file path/to/file.go.  For example "file=~/go/src/fmt/print.go"
 | |
| might return the packages "fmt" and "fmt [fmt.test]".
 | |
| 
 | |
| The query "pattern=string" causes "string" to be passed directly to
 | |
| the underlying build tool. In most cases this is unnecessary,
 | |
| but an application can use Load("pattern=" + x) as an escaping mechanism
 | |
| to ensure that x is not interpreted as a query operator if it contains '='.
 | |
| 
 | |
| All other query operators are reserved for future use and currently
 | |
| cause Load to report an error.
 | |
| 
 | |
| The Package struct provides basic information about the package, including
 | |
| 
 | |
|   - ID, a unique identifier for the package in the returned set;
 | |
|   - GoFiles, the names of the package's Go source files;
 | |
|   - Imports, a map from source import strings to the Packages they name;
 | |
|   - Types, the type information for the package's exported symbols;
 | |
|   - Syntax, the parsed syntax trees for the package's source code; and
 | |
|   - TypeInfo, the result of a complete type-check of the package syntax trees.
 | |
| 
 | |
| (See the documentation for type Package for the complete list of fields
 | |
| and more detailed descriptions.)
 | |
| 
 | |
| For example,
 | |
| 
 | |
| 	Load(nil, "bytes", "unicode...")
 | |
| 
 | |
| returns four Package structs describing the standard library packages
 | |
| bytes, unicode, unicode/utf16, and unicode/utf8. Note that one pattern
 | |
| can match multiple packages and that a package might be matched by
 | |
| multiple patterns: in general it is not possible to determine which
 | |
| packages correspond to which patterns.
 | |
| 
 | |
| Note that the list returned by Load contains only the packages matched
 | |
| by the patterns. Their dependencies can be found by walking the import
 | |
| graph using the Imports fields.
 | |
| 
 | |
| The Load function can be configured by passing a pointer to a Config as
 | |
| the first argument. A nil Config is equivalent to the zero Config, which
 | |
| causes Load to run in LoadFiles mode, collecting minimal information.
 | |
| See the documentation for type Config for details.
 | |
| 
 | |
| As noted earlier, the Config.Mode controls the amount of detail
 | |
| reported about the loaded packages. See the documentation for type LoadMode
 | |
| for details.
 | |
| 
 | |
| Most tools should pass their command-line arguments (after any flags)
 | |
| uninterpreted to the loader, so that the loader can interpret them
 | |
| according to the conventions of the underlying build system.
 | |
| See the Example function for typical usage.
 | |
| 
 | |
| */
 | |
| package packages // import "golang.org/x/tools/go/packages"
 | |
| 
 | |
| /*
 | |
| 
 | |
| Motivation and design considerations
 | |
| 
 | |
| The new package's design solves problems addressed by two existing
 | |
| packages: go/build, which locates and describes packages, and
 | |
| golang.org/x/tools/go/loader, which loads, parses and type-checks them.
 | |
| The go/build.Package structure encodes too much of the 'go build' way
 | |
| of organizing projects, leaving us in need of a data type that describes a
 | |
| package of Go source code independent of the underlying build system.
 | |
| We wanted something that works equally well with go build and vgo, and
 | |
| also other build systems such as Bazel and Blaze, making it possible to
 | |
| construct analysis tools that work in all these environments.
 | |
| Tools such as errcheck and staticcheck were essentially unavailable to
 | |
| the Go community at Google, and some of Google's internal tools for Go
 | |
| are unavailable externally.
 | |
| This new package provides a uniform way to obtain package metadata by
 | |
| querying each of these build systems, optionally supporting their
 | |
| preferred command-line notations for packages, so that tools integrate
 | |
| neatly with users' build environments. The Metadata query function
 | |
| executes an external query tool appropriate to the current workspace.
 | |
| 
 | |
| Loading packages always returns the complete import graph "all the way down",
 | |
| even if all you want is information about a single package, because the query
 | |
| mechanisms of all the build systems we currently support ({go,vgo} list, and
 | |
| blaze/bazel aspect-based query) cannot provide detailed information
 | |
| about one package without visiting all its dependencies too, so there is
 | |
| no additional asymptotic cost to providing transitive information.
 | |
| (This property might not be true of a hypothetical 5th build system.)
 | |
| 
 | |
| In calls to TypeCheck, all initial packages, and any package that
 | |
| transitively depends on one of them, must be loaded from source.
 | |
| Consider A->B->C->D->E: if A,C are initial, A,B,C must be loaded from
 | |
| source; D may be loaded from export data, and E may not be loaded at all
 | |
| (though it's possible that D's export data mentions it, so a
 | |
| types.Package may be created for it and exposed.)
 | |
| 
 | |
| The old loader had a feature to suppress type-checking of function
 | |
| bodies on a per-package basis, primarily intended to reduce the work of
 | |
| obtaining type information for imported packages. Now that imports are
 | |
| satisfied by export data, the optimization no longer seems necessary.
 | |
| 
 | |
| Despite some early attempts, the old loader did not exploit export data,
 | |
| instead always using the equivalent of WholeProgram mode. This was due
 | |
| to the complexity of mixing source and export data packages (now
 | |
| resolved by the upward traversal mentioned above), and because export data
 | |
| files were nearly always missing or stale. Now that 'go build' supports
 | |
| caching, all the underlying build systems can guarantee to produce
 | |
| export data in a reasonable (amortized) time.
 | |
| 
 | |
| Test "main" packages synthesized by the build system are now reported as
 | |
| first-class packages, avoiding the need for clients (such as go/ssa) to
 | |
| reinvent this generation logic.
 | |
| 
 | |
| One way in which go/packages is simpler than the old loader is in its
 | |
| treatment of in-package tests. In-package tests are packages that
 | |
| consist of all the files of the library under test, plus the test files.
 | |
| The old loader constructed in-package tests by a two-phase process of
 | |
| mutation called "augmentation": first it would construct and type check
 | |
| all the ordinary library packages and type-check the packages that
 | |
| depend on them; then it would add more (test) files to the package and
 | |
| type-check again. This two-phase approach had four major problems:
 | |
| 1) in processing the tests, the loader modified the library package,
 | |
|    leaving no way for a client application to see both the test
 | |
|    package and the library package; one would mutate into the other.
 | |
| 2) because test files can declare additional methods on types defined in
 | |
|    the library portion of the package, the dispatch of method calls in
 | |
|    the library portion was affected by the presence of the test files.
 | |
|    This should have been a clue that the packages were logically
 | |
|    different.
 | |
| 3) this model of "augmentation" assumed at most one in-package test
 | |
|    per library package, which is true of projects using 'go build',
 | |
|    but not other build systems.
 | |
| 4) because of the two-phase nature of test processing, all packages that
 | |
|    import the library package had to be processed before augmentation,
 | |
|    forcing a "one-shot" API and preventing the client from calling Load
 | |
|    in several times in sequence as is now possible in WholeProgram mode.
 | |
|    (TypeCheck mode has a similar one-shot restriction for a different reason.)
 | |
| 
 | |
| Early drafts of this package supported "multi-shot" operation.
 | |
| Although it allowed clients to make a sequence of calls (or concurrent
 | |
| calls) to Load, building up the graph of Packages incrementally,
 | |
| it was of marginal value: it complicated the API
 | |
| (since it allowed some options to vary across calls but not others),
 | |
| it complicated the implementation,
 | |
| it cannot be made to work in Types mode, as explained above,
 | |
| and it was less efficient than making one combined call (when this is possible).
 | |
| Among the clients we have inspected, none made multiple calls to load
 | |
| but could not be easily and satisfactorily modified to make only a single call.
 | |
| However, applications changes may be required.
 | |
| For example, the ssadump command loads the user-specified packages
 | |
| and in addition the runtime package.  It is tempting to simply append
 | |
| "runtime" to the user-provided list, but that does not work if the user
 | |
| specified an ad-hoc package such as [a.go b.go].
 | |
| Instead, ssadump no longer requests the runtime package,
 | |
| but seeks it among the dependencies of the user-specified packages,
 | |
| and emits an error if it is not found.
 | |
| 
 | |
| Overlays: The Overlay field in the Config allows providing alternate contents
 | |
| for Go source files, by providing a mapping from file path to contents.
 | |
| go/packages will pull in new imports added in overlay files when go/packages
 | |
| is run in LoadImports mode or greater.
 | |
| Overlay support for the go list driver isn't complete yet: if the file doesn't
 | |
| exist on disk, it will only be recognized in an overlay if it is a non-test file
 | |
| and the package would be reported even without the overlay.
 | |
| 
 | |
| Questions & Tasks
 | |
| 
 | |
| - Add GOARCH/GOOS?
 | |
|   They are not portable concepts, but could be made portable.
 | |
|   Our goal has been to allow users to express themselves using the conventions
 | |
|   of the underlying build system: if the build system honors GOARCH
 | |
|   during a build and during a metadata query, then so should
 | |
|   applications built atop that query mechanism.
 | |
|   Conversely, if the target architecture of the build is determined by
 | |
|   command-line flags, the application can pass the relevant
 | |
|   flags through to the build system using a command such as:
 | |
|     myapp -query_flag="--cpu=amd64" -query_flag="--os=darwin"
 | |
|   However, this approach is low-level, unwieldy, and non-portable.
 | |
|   GOOS and GOARCH seem important enough to warrant a dedicated option.
 | |
| 
 | |
| - How should we handle partial failures such as a mixture of good and
 | |
|   malformed patterns, existing and non-existent packages, successful and
 | |
|   failed builds, import failures, import cycles, and so on, in a call to
 | |
|   Load?
 | |
| 
 | |
| - Support bazel, blaze, and go1.10 list, not just go1.11 list.
 | |
| 
 | |
| - Handle (and test) various partial success cases, e.g.
 | |
|   a mixture of good packages and:
 | |
|   invalid patterns
 | |
|   nonexistent packages
 | |
|   empty packages
 | |
|   packages with malformed package or import declarations
 | |
|   unreadable files
 | |
|   import cycles
 | |
|   other parse errors
 | |
|   type errors
 | |
|   Make sure we record errors at the correct place in the graph.
 | |
| 
 | |
| - Missing packages among initial arguments are not reported.
 | |
|   Return bogus packages for them, like golist does.
 | |
| 
 | |
| - "undeclared name" errors (for example) are reported out of source file
 | |
|   order. I suspect this is due to the breadth-first resolution now used
 | |
|   by go/types. Is that a bug? Discuss with gri.
 | |
| 
 | |
| */
 |