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 // Fileset returns the Fileset used to parse all the Go files in this snapshot.
35 FileSet() *token.FileSet
37 // ValidBuildConfiguration returns true if there is some error in the
38 // user's workspace. In particular, if they are both outside of a module
40 ValidBuildConfiguration() bool
42 // WriteEnv writes the view-specific environment to the io.Writer.
43 WriteEnv(ctx context.Context, w io.Writer) error
45 // FindFile returns the FileHandle for the given URI, if it is already
46 // in the given snapshot.
47 FindFile(uri span.URI) VersionedFileHandle
49 // GetVersionedFile returns the VersionedFileHandle for a given URI,
50 // initializing it if it is not already part of the snapshot.
51 GetVersionedFile(ctx context.Context, uri span.URI) (VersionedFileHandle, error)
53 // GetFile returns the FileHandle for a given URI, initializing it if it is
54 // not already part of the snapshot.
55 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
57 // AwaitInitialized waits until the snapshot's view is initialized.
58 AwaitInitialized(ctx context.Context)
60 // IsOpen returns whether the editor currently has a file open.
61 IsOpen(uri span.URI) bool
63 // IgnoredFile reports if a file would be ignored by a `go list` of the whole
65 IgnoredFile(uri span.URI) bool
67 // ParseGo returns the parsed AST for the file.
68 // If the file is not available, returns nil and an error.
69 ParseGo(ctx context.Context, fh FileHandle, mode ParseMode) (*ParsedGoFile, error)
71 // PosToField is a cache of *ast.Fields by token.Pos. This allows us
72 // to quickly find corresponding *ast.Field node given a *types.Var.
73 // We must refer to the AST to render type aliases properly when
74 // formatting signatures and other types.
75 PosToField(ctx context.Context, pgf *ParsedGoFile) (map[token.Pos]*ast.Field, error)
77 // PosToDecl maps certain objects' positions to their surrounding
78 // ast.Decl. This mapping is used when building the documentation
79 // string for the objects.
80 PosToDecl(ctx context.Context, pgf *ParsedGoFile) (map[token.Pos]ast.Decl, error)
82 // Analyze runs the analyses for the given package at this snapshot.
83 Analyze(ctx context.Context, pkgID string, analyzers ...*analysis.Analyzer) ([]*Error, error)
85 // RunGoCommandPiped runs the given `go` command, writing its output
86 // to stdout and stderr. Verb, Args, and WorkingDir must be specified.
87 RunGoCommandPiped(ctx context.Context, mode InvocationMode, inv *gocommand.Invocation, stdout, stderr io.Writer) error
89 // RunGoCommandDirect runs the given `go` command. Verb, Args, and
90 // WorkingDir must be specified.
91 RunGoCommandDirect(ctx context.Context, mode InvocationMode, inv *gocommand.Invocation) (*bytes.Buffer, error)
93 // RunProcessEnvFunc runs fn with the process env for this snapshot's view.
94 // Note: the process env contains cached module and filesystem state.
95 RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error
97 // ModFiles are the go.mod files enclosed in the snapshot's view and known
101 // ParseMod is used to parse go.mod files.
102 ParseMod(ctx context.Context, fh FileHandle) (*ParsedModule, error)
104 // ModWhy returns the results of `go mod why` for the module specified by
105 // the given go.mod file.
106 ModWhy(ctx context.Context, fh FileHandle) (map[string]string, error)
108 // ModUpgrade returns the possible updates for the module specified by the
109 // given go.mod file.
110 ModUpgrade(ctx context.Context, fh FileHandle) (map[string]string, error)
112 // ModTidy returns the results of `go mod tidy` for the module specified by
113 // the given go.mod file.
114 ModTidy(ctx context.Context, fh FileHandle) (*TidiedModule, error)
116 // GoModForFile returns the URI of the go.mod file for the given URI.
117 GoModForFile(ctx context.Context, uri span.URI) span.URI
119 // BuiltinPackage returns information about the special builtin package.
120 BuiltinPackage(ctx context.Context) (*BuiltinPackage, error)
122 // PackagesForFile returns the packages that this file belongs to, checked
124 PackagesForFile(ctx context.Context, uri span.URI, mode TypecheckMode) ([]Package, error)
126 // PackageForFile returns a single package that this file belongs to,
127 // checked in mode and filtered by the package policy.
128 PackageForFile(ctx context.Context, uri span.URI, mode TypecheckMode, selectPackage PackageFilter) (Package, error)
130 // GetActiveReverseDeps returns the active files belonging to the reverse
131 // dependencies of this file's package, checked in TypecheckWorkspace mode.
132 GetReverseDependencies(ctx context.Context, id string) ([]Package, error)
134 // CachedImportPaths returns all the imported packages loaded in this
135 // snapshot, indexed by their import path and checked in TypecheckWorkspace
137 CachedImportPaths(ctx context.Context) (map[string]Package, error)
139 // KnownPackages returns all the packages loaded in this snapshot, checked
140 // in TypecheckWorkspace mode.
141 KnownPackages(ctx context.Context) ([]Package, error)
143 // WorkspacePackages returns the snapshot's top-level packages.
144 WorkspacePackages(ctx context.Context) ([]Package, error)
146 // WorkspaceDirectories returns any directory known by the view. For views
147 // within a module, this is the module root and any replace targets.
148 WorkspaceDirectories(ctx context.Context) []span.URI
151 // PackageFilter sets how a package is filtered out from a set of packages
152 // containing a given file.
153 type PackageFilter int
156 // NarrowestPackage picks the "narrowest" package for a given file.
157 // By "narrowest" package, we mean the package with the fewest number of
158 // files that includes the given file. This solves the problem of test
159 // variants, as the test will have more files than the non-test package.
160 NarrowestPackage PackageFilter = iota
162 // WidestPackage returns the Package containing the most files.
163 // This is useful for something like diagnostics, where we'd prefer to
164 // offer diagnostics for as many files as possible.
168 // InvocationMode represents the goal of a particular go command invocation.
169 type InvocationMode int
172 // Normal is appropriate for commands that might be run by a user and don't
173 // deliberately modify go.mod files, e.g. `go test`.
175 // UpdateUserModFile is for commands that intend to update the user's real
176 // go.mod file, e.g. `go mod tidy` in response to a user's request to tidy.
178 // WriteTemporaryModFile is for commands that need information from a
179 // modified version of the user's go.mod file, e.g. `go mod tidy` used to
180 // generate diagnostics.
181 WriteTemporaryModFile
182 // ForTypeChecking is for packages.Load.
186 // View represents a single workspace.
187 // This is the level at which we maintain configuration like working directory
189 type View interface {
190 // Name returns the name this view was constructed with.
193 // Folder returns the folder with which this view was created.
196 // BackgroundContext returns a context used for all background processing
197 // on behalf of this view.
198 BackgroundContext() context.Context
200 // Shutdown closes this view, and detaches it from its session.
201 Shutdown(ctx context.Context)
203 // Options returns a copy of the Options for this view.
206 // SetOptions sets the options of this view to new values.
207 // Calling this may cause the view to be invalidated and a replacement view
208 // added to the session. If so the new view will be returned, otherwise the
209 // original one will be.
210 SetOptions(context.Context, *Options) (View, error)
212 // Snapshot returns the current snapshot for the view.
213 Snapshot(ctx context.Context) (Snapshot, func())
215 // Rebuild rebuilds the current view, replacing the original view in its session.
216 Rebuild(ctx context.Context) (Snapshot, func(), error)
218 // IsGoPrivatePath reports whether target is a private import path, as identified
219 // by the GOPRIVATE environment variable.
220 IsGoPrivatePath(path string) bool
223 // A FileSource maps uris to FileHandles. This abstraction exists both for
224 // testability, and so that algorithms can be run equally on session and
226 type FileSource interface {
227 // GetFile returns the FileHandle for a given URI.
228 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
231 type BuiltinPackage struct {
233 ParsedFile *ParsedGoFile
236 // A ParsedGoFile contains the results of parsing a Go file.
237 type ParsedGoFile struct {
242 // Source code used to build the AST. It may be different from the
243 // actual content of the file if we have fixed the AST.
245 Mapper *protocol.ColumnMapper
249 // A ParsedModule contains the results of parsing a go.mod file.
250 type ParsedModule struct {
252 Mapper *protocol.ColumnMapper
256 // A TidiedModule contains the results of running `go mod tidy` on a module.
257 type TidiedModule struct {
258 // The parsed module, which is guaranteed to have parsed successfully.
260 // Diagnostics representing changes made by `go mod tidy`.
262 // The bytes of the go.mod file after it was tidied.
266 // Session represents a single connection from a client.
267 // This is the level at which things like open files are maintained on behalf
269 // A session may have many active views at any given time.
270 type Session interface {
271 // NewView creates a new View, returning it and its first snapshot.
272 NewView(ctx context.Context, name string, folder, tempWorkspaceDir span.URI, options *Options) (View, Snapshot, func(), error)
274 // Cache returns the cache that created this session, for debugging only.
277 // View returns a view with a matching name, if the session has one.
278 View(name string) View
280 // ViewOf returns a view corresponding to the given URI.
281 ViewOf(uri span.URI) (View, error)
283 // Views returns the set of active views built by this session.
286 // Shutdown the session and all views it has created.
287 Shutdown(ctx context.Context)
289 // GetFile returns a handle for the specified file.
290 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
292 // DidModifyFile reports a file modification to the session. It returns the
293 // resulting snapshots, a guaranteed one per view.
294 DidModifyFiles(ctx context.Context, changes []FileModification) (map[span.URI]View, map[View]Snapshot, []func(), []span.URI, error)
296 // Overlays returns a slice of file overlays for the session.
299 // Options returns a copy of the SessionOptions for this session.
302 // SetOptions sets the options of this session to new values.
306 // Overlay is the type for a file held in memory on a session.
307 type Overlay interface {
310 // Saved returns whether this overlay has been saved to disk.
314 // FileModification represents a modification to a file.
315 type FileModification struct {
319 // OnDisk is true if a watched file is changed on disk.
320 // If true, Version will be -1 and Text will be nil.
323 // Version will be -1 and Text will be nil when they are not supplied,
324 // specifically on textDocument/didClose and for on-disk changes.
328 // LanguageID is only sent from the language client on textDocument/didOpen.
335 UnknownFileAction = FileAction(iota)
345 func (a FileAction) String() string {
359 case InvalidateMetadata:
360 return "InvalidateMetadata"
366 var ErrTmpModfileUnsupported = errors.New("-modfile is unsupported for this Go version")
367 var ErrNoModOnDisk = errors.New("go.mod file is not on disk")
369 func IsNonFatalGoModError(err error) bool {
370 return err == ErrTmpModfileUnsupported || err == ErrNoModOnDisk
373 // ParseMode controls the content of the AST produced when parsing a source file.
377 // ParseHeader specifies that the main package declaration and imports are needed.
378 // This is the mode used when attempting to examine the package graph structure.
379 ParseHeader ParseMode = iota
381 // ParseExported specifies that the public symbols are needed, but things like
382 // private symbols and function bodies are not.
383 // This mode is used for things where a package is being consumed only as a
387 // ParseFull specifies the full AST is needed.
388 // This is used for files of direct interest where the entire contents must
393 // TypecheckMode controls what kind of parsing should be done (see ParseMode)
394 // while type checking a package.
395 type TypecheckMode int
398 // Invalid default value.
399 TypecheckUnknown TypecheckMode = iota
400 // TypecheckFull means to use ParseFull.
402 // TypecheckWorkspace means to use ParseFull for workspace packages, and
403 // ParseExported for others.
405 // TypecheckAll means ParseFull for workspace packages, and both Full and
406 // Exported for others. Only valid for some functions.
410 type VersionedFileHandle interface {
415 // LSPIdentity returns the version identity of a file.
416 VersionedFileIdentity() VersionedFileIdentity
419 type VersionedFileIdentity struct {
422 // SessionID is the ID of the LSP session.
425 // Version is the version of the file, as specified by the client. It should
426 // only be set in combination with SessionID.
430 // FileHandle represents a handle to a specific version of a single file.
431 type FileHandle interface {
435 // FileIdentity returns a FileIdentity for the file, even if there was an
437 FileIdentity() FileIdentity
438 // Read reads the contents of a file.
439 // If the file is not available, returns a nil slice and an error.
440 Read() ([]byte, error)
443 // FileIdentity uniquely identifies a file at a version from a FileSystem.
444 type FileIdentity struct {
447 // Identifier represents a unique identifier for the file's content.
450 // Kind is the file's kind.
454 func (id FileIdentity) String() string {
455 return fmt.Sprintf("%s%s%s", id.URI, id.Hash, id.Kind)
458 // FileKind describes the kind of the file in question.
459 // It can be one of Go, mod, or sum.
463 // UnknownKind is a file type we don't know about.
464 UnknownKind = FileKind(iota)
466 // Go is a normal go source file.
468 // Mod is a go.mod file.
470 // Sum is a go.sum file.
474 // Analyzer represents a go/analysis analyzer with some boolean properties
475 // that let the user know how to use the analyzer.
476 type Analyzer struct {
477 Analyzer *analysis.Analyzer
479 // Enabled reports whether the analyzer is enabled. This value can be
480 // configured per-analysis in user settings. For staticcheck analyzers,
481 // the value of the Staticcheck setting overrides this field.
484 // Command is the name of the command used to invoke the suggested fixes
485 // for the analyzer. It is non-nil if we expect this analyzer to provide
486 // its fix separately from its diagnostics. That is, we should apply the
487 // analyzer's suggested fixes through a Command, not a TextEdit.
490 // If this is true, then we can apply the suggested fixes
491 // as part of a source.FixAll codeaction.
494 // FixesError is only set for type-error analyzers.
495 // It reports true if the message provided indicates an error that could be
496 // fixed by the analyzer.
497 FixesError func(msg string) bool
500 func (a Analyzer) IsEnabled(view View) bool {
501 // Staticcheck analyzers can only be enabled when staticcheck is on.
502 if _, ok := view.Options().StaticcheckAnalyzers[a.Analyzer.Name]; ok {
503 if !view.Options().Staticcheck {
507 if enabled, ok := view.Options().Analyses[a.Analyzer.Name]; ok {
513 // Package represents a Go package that has been type-checked. It maintains
514 // only the relevant fields of a *go/packages.Package.
515 type Package interface {
519 CompiledGoFiles() []*ParsedGoFile
520 File(uri span.URI) (*ParsedGoFile, error)
521 GetSyntax() []*ast.File
523 GetTypes() *types.Package
524 GetTypesInfo() *types.Info
525 GetTypesSizes() types.Sizes
528 GetImport(pkgPath string) (Package, error)
529 MissingDependencies() []string
531 Version() *module.Version
534 type ErrorList []*Error
536 func (err *ErrorList) Error() string {
537 var b strings.Builder
538 b.WriteString("source error list:")
539 for _, e := range *err {
540 b.WriteString(fmt.Sprintf("\n\t%s", e))
545 // An Error corresponds to an LSP Diagnostic.
546 // https://microsoft.github.io/language-server-protocol/specification#diagnostic
552 Category string // only used by analysis errors so far
553 Related []RelatedInformation
555 // SuggestedFixes is used to generate quick fixes for a CodeAction request.
556 // It isn't part of the Diagnostic type.
557 SuggestedFixes []SuggestedFix
560 // GoModTidy is the source for a diagnostic computed by running `go mod tidy`.
561 const GoModTidy = "go mod tidy"
566 UnknownError = ErrorKind(iota)
574 func (e *Error) Error() string {
575 return fmt.Sprintf("%s:%s: %s", e.URI, e.Range, e.Message)
579 PackagesLoadError = errors.New("packages.Load error")
582 // WorkspaceModuleVersion is the nonexistent pseudoversion suffix used in the
583 // construction of the workspace module. It is exported so that we can make
584 // sure not to show this version to end users in error messages, to avoid
586 // The major version is not included, as that depends on the module path.
587 const workspaceModuleVersion = ".0.0-goplsworkspace"
589 func IsWorkspaceModuleVersion(version string) bool {
590 return strings.HasSuffix(version, workspaceModuleVersion)
593 func WorkspaceModuleVersion(majorVersion string) string {
594 return majorVersion + workspaceModuleVersion