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.
16 "golang.org/x/mod/modfile"
17 "golang.org/x/mod/module"
18 "golang.org/x/tools/go/analysis"
19 "golang.org/x/tools/internal/imports"
20 "golang.org/x/tools/internal/lsp/protocol"
21 "golang.org/x/tools/internal/span"
22 errors "golang.org/x/xerrors"
25 // Snapshot represents the current state for the given view.
26 type Snapshot interface {
29 // View returns the View associated with this snapshot.
32 // Fileset returns the Fileset used to parse all the Go files in this snapshot.
33 FileSet() *token.FileSet
35 // ValidBuildConfiguration returns true if there is some error in the
36 // user's workspace. In particular, if they are both outside of a module
38 ValidBuildConfiguration() bool
40 // WriteEnv writes the view-specific environment to the io.Writer.
41 WriteEnv(ctx context.Context, w io.Writer) error
43 // FindFile returns the FileHandle for the given URI, if it is already
44 // in the given snapshot.
45 FindFile(uri span.URI) VersionedFileHandle
47 // GetVersionedFile returns the VersionedFileHandle for a given URI,
48 // initializing it if it is not already part of the snapshot.
49 GetVersionedFile(ctx context.Context, uri span.URI) (VersionedFileHandle, error)
51 // GetFile returns the FileHandle for a given URI, initializing it if it is
52 // not already part of the snapshot.
53 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
55 // AwaitInitialized waits until the snapshot's view is initialized.
56 AwaitInitialized(ctx context.Context)
58 // IsOpen returns whether the editor currently has a file open.
59 IsOpen(uri span.URI) bool
61 // IgnoredFile reports if a file would be ignored by a `go list` of the whole
63 IgnoredFile(uri span.URI) bool
65 // ParseGo returns the parsed AST for the file.
66 // If the file is not available, returns nil and an error.
67 ParseGo(ctx context.Context, fh FileHandle, mode ParseMode) (*ParsedGoFile, error)
69 // PosToField is a cache of *ast.Fields by token.Pos. This allows us
70 // to quickly find corresponding *ast.Field node given a *types.Var.
71 // We must refer to the AST to render type aliases properly when
72 // formatting signatures and other types.
73 PosToField(ctx context.Context, pgf *ParsedGoFile) (map[token.Pos]*ast.Field, error)
75 // PosToDecl maps certain objects' positions to their surrounding
76 // ast.Decl. This mapping is used when building the documentation
77 // string for the objects.
78 PosToDecl(ctx context.Context, pgf *ParsedGoFile) (map[token.Pos]ast.Decl, error)
80 // Analyze runs the analyses for the given package at this snapshot.
81 Analyze(ctx context.Context, pkgID string, analyzers ...*analysis.Analyzer) ([]*Error, error)
83 // RunGoCommandPiped runs the given `go` command in the view, using the
84 // provided stdout and stderr. It will use the -modfile flag, if possible.
85 // If the provided working directory is empty, the snapshot's root folder
86 // will be used as the working directory.
87 RunGoCommandPiped(ctx context.Context, wd, verb string, args []string, stdout, stderr io.Writer) error
89 // RunGoCommandDirect runs the given `go` command, never using the
90 // -modfile flag. If the provided working directory is empty, the
91 // snapshot's root folder will be used as the working directory.
92 RunGoCommandDirect(ctx context.Context, wd, verb string, args []string) error
94 // RunProcessEnvFunc runs fn with the process env for this snapshot's view.
95 // Note: the process env contains cached module and filesystem state.
96 RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options) error) error
98 // ModFiles are the go.mod files enclosed in the snapshot's view and known
100 ModFiles() []span.URI
102 // ParseMod is used to parse go.mod files.
103 ParseMod(ctx context.Context, fh FileHandle) (*ParsedModule, error)
105 // ModWhy returns the results of `go mod why` for the module specified by
106 // the given go.mod file.
107 ModWhy(ctx context.Context, fh FileHandle) (map[string]string, error)
109 // ModUpgrade returns the possible updates for the module specified by the
110 // given go.mod file.
111 ModUpgrade(ctx context.Context, fh FileHandle) (map[string]string, error)
113 // ModTidy returns the results of `go mod tidy` for the module specified by
114 // the given go.mod file.
115 ModTidy(ctx context.Context, fh FileHandle) (*TidiedModule, error)
117 // GoModForFile returns the URI of the go.mod file for the given URI.
118 GoModForFile(ctx context.Context, uri span.URI) span.URI
120 // BuildWorkspaceModFile builds the contents of mod file to be used for
121 // multi-module workspace.
122 BuildWorkspaceModFile(ctx context.Context) (*modfile.File, error)
124 // BuiltinPackage returns information about the special builtin package.
125 BuiltinPackage(ctx context.Context) (*BuiltinPackage, error)
127 // PackagesForFile returns the packages that this file belongs to, checked
129 PackagesForFile(ctx context.Context, uri span.URI, mode TypecheckMode) ([]Package, error)
131 // PackageForFile returns a single package that this file belongs to,
132 // checked in mode and filtered by the package policy.
133 PackageForFile(ctx context.Context, uri span.URI, mode TypecheckMode, selectPackage PackageFilter) (Package, error)
135 // GetActiveReverseDeps returns the active files belonging to the reverse
136 // dependencies of this file's package, checked in TypecheckWorkspace mode.
137 GetReverseDependencies(ctx context.Context, id string) ([]Package, error)
139 // CachedImportPaths returns all the imported packages loaded in this
140 // snapshot, indexed by their import path and checked in TypecheckWorkspace
142 CachedImportPaths(ctx context.Context) (map[string]Package, error)
144 // KnownPackages returns all the packages loaded in this snapshot, checked
145 // in TypecheckWorkspace mode.
146 KnownPackages(ctx context.Context) ([]Package, error)
148 // WorkspacePackages returns the snapshot's top-level packages.
149 WorkspacePackages(ctx context.Context) ([]Package, error)
151 // WorkspaceDirectories returns any directory known by the view. For views
152 // within a module, this is the module root and any replace targets.
153 WorkspaceDirectories(ctx context.Context) []span.URI
156 // PackageFilter sets how a package is filtered out from a set of packages
157 // containing a given file.
158 type PackageFilter int
161 // NarrowestPackage picks the "narrowest" package for a given file.
162 // By "narrowest" package, we mean the package with the fewest number of
163 // files that includes the given file. This solves the problem of test
164 // variants, as the test will have more files than the non-test package.
165 NarrowestPackage PackageFilter = iota
167 // WidestPackage returns the Package containing the most files.
168 // This is useful for something like diagnostics, where we'd prefer to
169 // offer diagnostics for as many files as possible.
173 // View represents a single workspace.
174 // This is the level at which we maintain configuration like working directory
176 type View interface {
177 // Name returns the name this view was constructed with.
180 // Folder returns the folder with which this view was created.
183 // BackgroundContext returns a context used for all background processing
184 // on behalf of this view.
185 BackgroundContext() context.Context
187 // Shutdown closes this view, and detaches it from its session.
188 Shutdown(ctx context.Context)
190 // Options returns a copy of the Options for this view.
193 // SetOptions sets the options of this view to new values.
194 // Calling this may cause the view to be invalidated and a replacement view
195 // added to the session. If so the new view will be returned, otherwise the
196 // original one will be.
197 SetOptions(context.Context, *Options) (View, error)
199 // Snapshot returns the current snapshot for the view.
200 Snapshot(ctx context.Context) (Snapshot, func())
202 // Rebuild rebuilds the current view, replacing the original view in its session.
203 Rebuild(ctx context.Context) (Snapshot, func(), error)
205 // IsGoPrivatePath reports whether target is a private import path, as identified
206 // by the GOPRIVATE environment variable.
207 IsGoPrivatePath(path string) bool
210 // A FileSource maps uris to FileHandles. This abstraction exists both for
211 // testability, and so that algorithms can be run equally on session and
213 type FileSource interface {
214 // GetFile returns the FileHandle for a given URI.
215 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
218 type BuiltinPackage struct {
220 ParsedFile *ParsedGoFile
223 // A ParsedGoFile contains the results of parsing a Go file.
224 type ParsedGoFile struct {
229 // Source code used to build the AST. It may be different from the
230 // actual content of the file if we have fixed the AST.
232 Mapper *protocol.ColumnMapper
236 // A ParsedModule contains the results of parsing a go.mod file.
237 type ParsedModule struct {
239 Mapper *protocol.ColumnMapper
243 // A TidiedModule contains the results of running `go mod tidy` on a module.
244 type TidiedModule struct {
245 // The parsed module, which is guaranteed to have parsed successfully.
247 // Diagnostics representing changes made by `go mod tidy`.
249 // The bytes of the go.mod file after it was tidied.
253 // Session represents a single connection from a client.
254 // This is the level at which things like open files are maintained on behalf
256 // A session may have many active views at any given time.
257 type Session interface {
258 // NewView creates a new View, returning it and its first snapshot.
259 NewView(ctx context.Context, name string, folder span.URI, options *Options) (View, Snapshot, func(), error)
261 // Cache returns the cache that created this session, for debugging only.
264 // View returns a view with a matching name, if the session has one.
265 View(name string) View
267 // ViewOf returns a view corresponding to the given URI.
268 ViewOf(uri span.URI) (View, error)
270 // Views returns the set of active views built by this session.
273 // Shutdown the session and all views it has created.
274 Shutdown(ctx context.Context)
276 // GetFile returns a handle for the specified file.
277 GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
279 // DidModifyFile reports a file modification to the session. It returns the
280 // resulting snapshots, a guaranteed one per view.
281 DidModifyFiles(ctx context.Context, changes []FileModification) (map[span.URI]View, map[View]Snapshot, []func(), []span.URI, error)
283 // Overlays returns a slice of file overlays for the session.
286 // Options returns a copy of the SessionOptions for this session.
289 // SetOptions sets the options of this session to new values.
293 // Overlay is the type for a file held in memory on a session.
294 type Overlay interface {
297 // Saved returns whether this overlay has been saved to disk.
301 // FileModification represents a modification to a file.
302 type FileModification struct {
306 // OnDisk is true if a watched file is changed on disk.
307 // If true, Version will be -1 and Text will be nil.
310 // Version will be -1 and Text will be nil when they are not supplied,
311 // specifically on textDocument/didClose and for on-disk changes.
315 // LanguageID is only sent from the language client on textDocument/didOpen.
322 UnknownFileAction = FileAction(iota)
332 func (a FileAction) String() string {
346 case InvalidateMetadata:
347 return "InvalidateMetadata"
353 var ErrTmpModfileUnsupported = errors.New("-modfile is unsupported for this Go version")
354 var ErrNoModOnDisk = errors.New("go.mod file is not on disk")
356 func IsNonFatalGoModError(err error) bool {
357 return err == ErrTmpModfileUnsupported || err == ErrNoModOnDisk
360 // ParseMode controls the content of the AST produced when parsing a source file.
364 // ParseHeader specifies that the main package declaration and imports are needed.
365 // This is the mode used when attempting to examine the package graph structure.
366 ParseHeader ParseMode = iota
368 // ParseExported specifies that the public symbols are needed, but things like
369 // private symbols and function bodies are not.
370 // This mode is used for things where a package is being consumed only as a
374 // ParseFull specifies the full AST is needed.
375 // This is used for files of direct interest where the entire contents must
380 // TypecheckMode controls what kind of parsing should be done (see ParseMode)
381 // while type checking a package.
382 type TypecheckMode int
385 // Invalid default value.
386 TypecheckUnknown TypecheckMode = iota
387 // TypecheckFull means to use ParseFull.
389 // TypecheckWorkspace means to use ParseFull for workspace packages, and
390 // ParseExported for others.
392 // TypecheckAll means ParseFull for workspace packages, and both Full and
393 // Exported for others. Only valid for some functions.
397 type VersionedFileHandle interface {
402 // LSPIdentity returns the version identity of a file.
403 VersionedFileIdentity() VersionedFileIdentity
406 type VersionedFileIdentity struct {
409 // SessionID is the ID of the LSP session.
412 // Version is the version of the file, as specified by the client. It should
413 // only be set in combination with SessionID.
417 // FileHandle represents a handle to a specific version of a single file.
418 type FileHandle interface {
422 // FileIdentity returns a FileIdentity for the file, even if there was an
424 FileIdentity() FileIdentity
425 // Read reads the contents of a file.
426 // If the file is not available, returns a nil slice and an error.
427 Read() ([]byte, error)
430 // FileIdentity uniquely identifies a file at a version from a FileSystem.
431 type FileIdentity struct {
434 // Identifier represents a unique identifier for the file's content.
437 // Kind is the file's kind.
441 func (id FileIdentity) String() string {
442 return fmt.Sprintf("%s%s%s", id.URI, id.Hash, id.Kind)
445 // FileKind describes the kind of the file in question.
446 // It can be one of Go, mod, or sum.
450 // UnknownKind is a file type we don't know about.
451 UnknownKind = FileKind(iota)
453 // Go is a normal go source file.
455 // Mod is a go.mod file.
457 // Sum is a go.sum file.
461 // Analyzer represents a go/analysis analyzer with some boolean properties
462 // that let the user know how to use the analyzer.
463 type Analyzer struct {
464 Analyzer *analysis.Analyzer
466 // Enabled reports whether the analyzer is enabled. This value can be
467 // configured per-analysis in user settings. For staticcheck analyzers,
468 // the value of the Staticcheck setting overrides this field.
471 // Command is the name of the command used to invoke the suggested fixes
472 // for the analyzer. It is non-nil if we expect this analyzer to provide
473 // its fix separately from its diagnostics. That is, we should apply the
474 // analyzer's suggested fixes through a Command, not a TextEdit.
477 // If this is true, then we can apply the suggested fixes
478 // as part of a source.FixAll codeaction.
481 // FixesError is only set for type-error analyzers.
482 // It reports true if the message provided indicates an error that could be
483 // fixed by the analyzer.
484 FixesError func(msg string) bool
487 func (a Analyzer) IsEnabled(view View) bool {
488 // Staticcheck analyzers can only be enabled when staticcheck is on.
489 if _, ok := view.Options().StaticcheckAnalyzers[a.Analyzer.Name]; ok {
490 if !view.Options().Staticcheck {
494 if enabled, ok := view.Options().Analyses[a.Analyzer.Name]; ok {
500 // Package represents a Go package that has been type-checked. It maintains
501 // only the relevant fields of a *go/packages.Package.
502 type Package interface {
506 CompiledGoFiles() []*ParsedGoFile
507 File(uri span.URI) (*ParsedGoFile, error)
508 GetSyntax() []*ast.File
510 GetTypes() *types.Package
511 GetTypesInfo() *types.Info
512 GetTypesSizes() types.Sizes
515 GetImport(pkgPath string) (Package, error)
516 MissingDependencies() []string
518 Version() *module.Version
521 type ErrorList []*Error
523 func (err *ErrorList) Error() string {
524 var b strings.Builder
525 b.WriteString("source error list:")
526 for _, e := range *err {
527 b.WriteString(fmt.Sprintf("\n\t%s", e))
537 Category string // only used by analysis errors so far
538 SuggestedFixes []SuggestedFix
539 Related []RelatedInformation
542 // GoModTidy is the source for a diagnostic computed by running `go mod tidy`.
543 const GoModTidy = "go mod tidy"
548 UnknownError = ErrorKind(iota)
556 func (e *Error) Error() string {
557 return fmt.Sprintf("%s:%s: %s", e.URI, e.Range, e.Message)
561 InconsistentVendoring = errors.New("inconsistent vendoring")
562 PackagesLoadError = errors.New("packages.Load error")
565 // WorkspaceModuleVersion is the nonexistent pseudoversion suffix used in the
566 // construction of the workspace module. It is exported so that we can make
567 // sure not to show this version to end users in error messages, to avoid
569 // The major version is not included, as that depends on the module path.
570 const workspaceModuleVersion = ".0.0-goplsworkspace"
572 func IsWorkspaceModuleVersion(version string) bool {
573 return strings.HasSuffix(version, workspaceModuleVersion)
576 func WorkspaceModuleVersion(majorVersion string) string {
577 return majorVersion + workspaceModuleVersion