1 // Copyright 2018 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
17 "golang.org/x/mod/modfile"
18 "golang.org/x/mod/module"
19 "golang.org/x/tools/go/analysis"
20 "golang.org/x/tools/internal/gocommand"
21 "golang.org/x/tools/internal/imports"
22 "golang.org/x/tools/internal/lsp/protocol"
23 "golang.org/x/tools/internal/span"
24 errors "golang.org/x/xerrors"
27 // Snapshot represents the current state for the given view.
28 type Snapshot interface {
31 // View returns the View associated with this snapshot.
34 // BackgroundContext returns a context used for all background processing
35 // on behalf of this snapshot.
36 BackgroundContext() context.Context
38 // Fileset returns the Fileset used to parse all the Go files in this snapshot.
39 FileSet() *token.FileSet
41 // ValidBuildConfiguration returns true if there is some error in the
42 // user's workspace. In particular, if they are both outside of a module
44 ValidBuildConfiguration() bool
46 // WriteEnv writes the view-specific environment to the io.Writer.
47 WriteEnv(ctx context.Context, w io.Writer) error
49 // FindFile returns the FileHandle for the given URI, if it is already
50 // in the given snapshot.
51 FindFile(uri span.URI) VersionedFileHandle
53 // GetVersionedFile returns the VersionedFileHandle for a given URI,
54 // initializing it if it is not already part of the snapshot.
55 GetVersionedFile(ctx context.Context, uri span.URI) (VersionedFileHandle, error)
57 // GetFile returns the FileHandle for a given URI, initializing it if it is
58 // not already part of the snapshot.
59 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
61 // AwaitInitialized waits until the snapshot's view is initialized.
62 AwaitInitialized(ctx context.Context)
64 // IsOpen returns whether the editor currently has a file open.
65 IsOpen(uri span.URI) bool
67 // IgnoredFile reports if a file would be ignored by a `go list` of the whole
69 IgnoredFile(uri span.URI) bool
71 // ParseGo returns the parsed AST for the file.
72 // If the file is not available, returns nil and an error.
73 ParseGo(ctx context.Context, fh FileHandle, mode ParseMode) (*ParsedGoFile, error)
75 // PosToField is a cache of *ast.Fields by token.Pos. This allows us
76 // to quickly find corresponding *ast.Field node given a *types.Var.
77 // We must refer to the AST to render type aliases properly when
78 // formatting signatures and other types.
79 PosToField(ctx context.Context, pgf *ParsedGoFile) (map[token.Pos]*ast.Field, error)
81 // PosToDecl maps certain objects' positions to their surrounding
82 // ast.Decl. This mapping is used when building the documentation
83 // string for the objects.
84 PosToDecl(ctx context.Context, pgf *ParsedGoFile) (map[token.Pos]ast.Decl, error)
86 // Analyze runs the analyses for the given package at this snapshot.
87 Analyze(ctx context.Context, pkgID string, analyzers ...*analysis.Analyzer) ([]*Error, error)
89 // RunGoCommandPiped runs the given `go` command, writing its output
90 // to stdout and stderr. Verb, Args, and WorkingDir must be specified.
91 RunGoCommandPiped(ctx context.Context, mode InvocationFlags, inv *gocommand.Invocation, stdout, stderr io.Writer) error
93 // RunGoCommandDirect runs the given `go` command. Verb, Args, and
94 // WorkingDir must be specified.
95 RunGoCommandDirect(ctx context.Context, mode InvocationFlags, inv *gocommand.Invocation) (*bytes.Buffer, error)
97 // RunProcessEnvFunc runs fn with the process env for this snapshot's view.
98 // Note: the process env contains cached module and filesystem state.
99 RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error
101 // ModFiles are the go.mod files enclosed in the snapshot's view and known
103 ModFiles() []span.URI
105 // ParseMod is used to parse go.mod files.
106 ParseMod(ctx context.Context, fh FileHandle) (*ParsedModule, error)
108 // ModWhy returns the results of `go mod why` for the module specified by
109 // the given go.mod file.
110 ModWhy(ctx context.Context, fh FileHandle) (map[string]string, error)
112 // ModUpgrade returns the possible updates for the module specified by the
113 // given go.mod file.
114 ModUpgrade(ctx context.Context, fh FileHandle) (map[string]string, error)
116 // ModTidy returns the results of `go mod tidy` for the module specified by
117 // the given go.mod file.
118 ModTidy(ctx context.Context, pm *ParsedModule) (*TidiedModule, error)
120 // GoModForFile returns the URI of the go.mod file for the given URI.
121 GoModForFile(uri span.URI) span.URI
123 // BuiltinPackage returns information about the special builtin package.
124 BuiltinPackage(ctx context.Context) (*BuiltinPackage, error)
126 // PackagesForFile returns the packages that this file belongs to, checked
128 PackagesForFile(ctx context.Context, uri span.URI, mode TypecheckMode) ([]Package, error)
130 // PackageForFile returns a single package that this file belongs to,
131 // checked in mode and filtered by the package policy.
132 PackageForFile(ctx context.Context, uri span.URI, mode TypecheckMode, selectPackage PackageFilter) (Package, error)
134 // GetActiveReverseDeps returns the active files belonging to the reverse
135 // dependencies of this file's package, checked in TypecheckWorkspace mode.
136 GetReverseDependencies(ctx context.Context, id string) ([]Package, error)
138 // CachedImportPaths returns all the imported packages loaded in this
139 // snapshot, indexed by their import path and checked in TypecheckWorkspace
141 CachedImportPaths(ctx context.Context) (map[string]Package, error)
143 // KnownPackages returns all the packages loaded in this snapshot, checked
144 // in TypecheckWorkspace mode.
145 KnownPackages(ctx context.Context) ([]Package, error)
147 // WorkspacePackages returns the snapshot's top-level packages.
148 WorkspacePackages(ctx context.Context) ([]Package, error)
150 // GetCriticalError returns any critical errors in the workspace.
151 GetCriticalError(ctx context.Context) *CriticalError
154 // PackageFilter sets how a package is filtered out from a set of packages
155 // containing a given file.
156 type PackageFilter int
159 // NarrowestPackage picks the "narrowest" package for a given file.
160 // By "narrowest" package, we mean the package with the fewest number of
161 // files that includes the given file. This solves the problem of test
162 // variants, as the test will have more files than the non-test package.
163 NarrowestPackage PackageFilter = iota
165 // WidestPackage returns the Package containing the most files.
166 // This is useful for something like diagnostics, where we'd prefer to
167 // offer diagnostics for as many files as possible.
171 // InvocationFlags represents the settings of a particular go command invocation.
172 // It is a mode, plus a set of flag bits.
173 type InvocationFlags int
176 // Normal is appropriate for commands that might be run by a user and don't
177 // deliberately modify go.mod files, e.g. `go test`.
178 Normal InvocationFlags = iota
179 // UpdateUserModFile is for commands that intend to update the user's real
180 // go.mod file, e.g. `go mod tidy` in response to a user's request to tidy.
182 // WriteTemporaryModFile is for commands that need information from a
183 // modified version of the user's go.mod file, e.g. `go mod tidy` used to
184 // generate diagnostics.
185 WriteTemporaryModFile
186 // LoadWorkspace is for packages.Load, and other operations that should
187 // consider the whole workspace at once.
190 // AllowNetwork is a flag bit that indicates the invocation should be
191 // allowed to access the network.
192 AllowNetwork = 1 << 10
195 func (m InvocationFlags) Mode() InvocationFlags {
196 return m & (AllowNetwork - 1)
199 func (m InvocationFlags) AllowNetwork() bool {
200 return m&AllowNetwork != 0
203 // View represents a single workspace.
204 // This is the level at which we maintain configuration like working directory
206 type View interface {
207 // Name returns the name this view was constructed with.
210 // Folder returns the folder with which this view was created.
213 // Shutdown closes this view, and detaches it from its session.
214 Shutdown(ctx context.Context)
216 // Options returns a copy of the Options for this view.
219 // SetOptions sets the options of this view to new values.
220 // Calling this may cause the view to be invalidated and a replacement view
221 // added to the session. If so the new view will be returned, otherwise the
222 // original one will be.
223 SetOptions(context.Context, *Options) (View, error)
225 // Snapshot returns the current snapshot for the view.
226 Snapshot(ctx context.Context) (Snapshot, func())
228 // Rebuild rebuilds the current view, replacing the original view in its session.
229 Rebuild(ctx context.Context) (Snapshot, func(), error)
231 // IsGoPrivatePath reports whether target is a private import path, as identified
232 // by the GOPRIVATE environment variable.
233 IsGoPrivatePath(path string) bool
236 // A FileSource maps uris to FileHandles. This abstraction exists both for
237 // testability, and so that algorithms can be run equally on session and
239 type FileSource interface {
240 // GetFile returns the FileHandle for a given URI.
241 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
244 type BuiltinPackage struct {
246 ParsedFile *ParsedGoFile
249 // A ParsedGoFile contains the results of parsing a Go file.
250 type ParsedGoFile struct {
255 // Source code used to build the AST. It may be different from the
256 // actual content of the file if we have fixed the AST.
258 Mapper *protocol.ColumnMapper
262 // A ParsedModule contains the results of parsing a go.mod file.
263 type ParsedModule struct {
266 Mapper *protocol.ColumnMapper
270 // A TidiedModule contains the results of running `go mod tidy` on a module.
271 type TidiedModule struct {
272 // Diagnostics representing changes made by `go mod tidy`.
274 // The bytes of the go.mod file after it was tidied.
278 // Session represents a single connection from a client.
279 // This is the level at which things like open files are maintained on behalf
281 // A session may have many active views at any given time.
282 type Session interface {
283 // NewView creates a new View, returning it and its first snapshot.
284 NewView(ctx context.Context, name string, folder, tempWorkspaceDir span.URI, options *Options) (View, Snapshot, func(), error)
286 // Cache returns the cache that created this session, for debugging only.
289 // View returns a view with a matching name, if the session has one.
290 View(name string) View
292 // ViewOf returns a view corresponding to the given URI.
293 ViewOf(uri span.URI) (View, error)
295 // Views returns the set of active views built by this session.
298 // Shutdown the session and all views it has created.
299 Shutdown(ctx context.Context)
301 // GetFile returns a handle for the specified file.
302 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
304 // DidModifyFile reports a file modification to the session. It returns
305 // the new snapshots after the modifications have been applied, paired with
306 // the affected file URIs for those snapshots.
307 DidModifyFiles(ctx context.Context, changes []FileModification) (map[Snapshot][]span.URI, []func(), error)
309 // ExpandModificationsToDirectories returns the set of changes with the
310 // directory changes removed and expanded to include all of the files in
312 ExpandModificationsToDirectories(ctx context.Context, changes []FileModification) []FileModification
314 // Overlays returns a slice of file overlays for the session.
317 // Options returns a copy of the SessionOptions for this session.
320 // SetOptions sets the options of this session to new values.
323 // FileWatchingGlobPatterns returns glob patterns to watch every directory
324 // known by the view. For views within a module, this is the module root,
325 // any directory in the module root, and any replace targets.
326 FileWatchingGlobPatterns(ctx context.Context) map[string]struct{}
329 // Overlay is the type for a file held in memory on a session.
330 type Overlay interface {
334 // FileModification represents a modification to a file.
335 type FileModification struct {
339 // OnDisk is true if a watched file is changed on disk.
340 // If true, Version will be -1 and Text will be nil.
343 // Version will be -1 and Text will be nil when they are not supplied,
344 // specifically on textDocument/didClose and for on-disk changes.
348 // LanguageID is only sent from the language client on textDocument/didOpen.
355 UnknownFileAction = FileAction(iota)
365 func (a FileAction) String() string {
379 case InvalidateMetadata:
380 return "InvalidateMetadata"
386 var ErrTmpModfileUnsupported = errors.New("-modfile is unsupported for this Go version")
387 var ErrNoModOnDisk = errors.New("go.mod file is not on disk")
389 func IsNonFatalGoModError(err error) bool {
390 return err == ErrTmpModfileUnsupported || err == ErrNoModOnDisk
393 // ParseMode controls the content of the AST produced when parsing a source file.
397 // ParseHeader specifies that the main package declaration and imports are needed.
398 // This is the mode used when attempting to examine the package graph structure.
399 ParseHeader ParseMode = iota
401 // ParseExported specifies that the public symbols are needed, but things like
402 // private symbols and function bodies are not.
403 // This mode is used for things where a package is being consumed only as a
407 // ParseFull specifies the full AST is needed.
408 // This is used for files of direct interest where the entire contents must
413 // TypecheckMode controls what kind of parsing should be done (see ParseMode)
414 // while type checking a package.
415 type TypecheckMode int
418 // Invalid default value.
419 TypecheckUnknown TypecheckMode = iota
420 // TypecheckFull means to use ParseFull.
422 // TypecheckWorkspace means to use ParseFull for workspace packages, and
423 // ParseExported for others.
425 // TypecheckAll means ParseFull for workspace packages, and both Full and
426 // Exported for others. Only valid for some functions.
430 type VersionedFileHandle interface {
435 // LSPIdentity returns the version identity of a file.
436 VersionedFileIdentity() VersionedFileIdentity
439 type VersionedFileIdentity struct {
442 // SessionID is the ID of the LSP session.
445 // Version is the version of the file, as specified by the client. It should
446 // only be set in combination with SessionID.
450 // FileHandle represents a handle to a specific version of a single file.
451 type FileHandle interface {
455 // FileIdentity returns a FileIdentity for the file, even if there was an
457 FileIdentity() FileIdentity
458 // Read reads the contents of a file.
459 // If the file is not available, returns a nil slice and an error.
460 Read() ([]byte, error)
461 // Saved reports whether the file has the same content on disk.
465 // FileIdentity uniquely identifies a file at a version from a FileSystem.
466 type FileIdentity struct {
469 // Identifier represents a unique identifier for the file's content.
472 // Kind is the file's kind.
476 func (id FileIdentity) String() string {
477 return fmt.Sprintf("%s%s%s", id.URI, id.Hash, id.Kind)
480 // FileKind describes the kind of the file in question.
481 // It can be one of Go, mod, or sum.
485 // UnknownKind is a file type we don't know about.
486 UnknownKind = FileKind(iota)
488 // Go is a normal go source file.
490 // Mod is a go.mod file.
492 // Sum is a go.sum file.
496 // Analyzer represents a go/analysis analyzer with some boolean properties
497 // that let the user know how to use the analyzer.
498 type Analyzer struct {
499 Analyzer *analysis.Analyzer
501 // Enabled reports whether the analyzer is enabled. This value can be
502 // configured per-analysis in user settings. For staticcheck analyzers,
503 // the value of the Staticcheck setting overrides this field.
506 // Command is the name of the command used to invoke the suggested fixes
507 // for the analyzer. It is non-nil if we expect this analyzer to provide
508 // its fix separately from its diagnostics. That is, we should apply the
509 // analyzer's suggested fixes through a Command, not a TextEdit.
512 // If this is true, then we can apply the suggested fixes
513 // as part of a source.FixAll codeaction.
516 // FixesError is only set for type-error analyzers.
517 // It reports true if the message provided indicates an error that could be
518 // fixed by the analyzer.
519 FixesError func(msg string) bool
522 func (a Analyzer) IsEnabled(view View) bool {
523 // Staticcheck analyzers can only be enabled when staticcheck is on.
524 if _, ok := view.Options().StaticcheckAnalyzers[a.Analyzer.Name]; ok {
525 if !view.Options().Staticcheck {
529 if enabled, ok := view.Options().Analyses[a.Analyzer.Name]; ok {
535 // Package represents a Go package that has been type-checked. It maintains
536 // only the relevant fields of a *go/packages.Package.
537 type Package interface {
541 CompiledGoFiles() []*ParsedGoFile
542 File(uri span.URI) (*ParsedGoFile, error)
543 GetSyntax() []*ast.File
545 GetTypes() *types.Package
546 GetTypesInfo() *types.Info
547 GetTypesSizes() types.Sizes
550 GetImport(pkgPath string) (Package, error)
551 MissingDependencies() []string
553 Version() *module.Version
556 type CriticalError struct {
561 func (err *CriticalError) Error() string {
562 if err.MainError == nil {
565 return err.MainError.Error()
568 // An Error corresponds to an LSP Diagnostic.
569 // https://microsoft.github.io/language-server-protocol/specification#diagnostic
575 Category string // only used by analysis errors so far
577 Related []RelatedInformation
582 // SuggestedFixes is used to generate quick fixes for a CodeAction request.
583 // It isn't part of the Diagnostic type.
584 SuggestedFixes []SuggestedFix
587 // GoModTidy is the source for a diagnostic computed by running `go mod tidy`.
588 const GoModTidy = "go mod tidy"
593 UnknownError = ErrorKind(iota)
601 func (e *Error) Error() string {
605 return fmt.Sprintf("%s:%s: %s", e.URI, e.Range, e.Message)
609 PackagesLoadError = errors.New("packages.Load error")
612 // WorkspaceModuleVersion is the nonexistent pseudoversion suffix used in the
613 // construction of the workspace module. It is exported so that we can make
614 // sure not to show this version to end users in error messages, to avoid
616 // The major version is not included, as that depends on the module path.
617 const workspaceModuleVersion = ".0.0-goplsworkspace"
619 func IsWorkspaceModuleVersion(version string) bool {
620 return strings.HasSuffix(version, workspaceModuleVersion)
623 func WorkspaceModuleVersion(majorVersion string) string {
624 return majorVersion + workspaceModuleVersion