mirror of
https://github.com/golang/go
synced 2024-11-19 00:34:40 -07:00
4796d4bd3d
This change associates an ast.Node for some object declarations. In this case, we only handle type declarations, but future changes will support other objects as well. This is the first step in adding documentation on hover. Updates golang/go#29151 Change-Id: I39ddccf4130ee3b106725286375cd74bc51bcd38 Reviewed-on: https://go-review.googlesource.com/c/tools/+/172661 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
138 lines
2.9 KiB
Go
138 lines
2.9 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 cache
|
|
|
|
import (
|
|
"context"
|
|
"go/ast"
|
|
"go/token"
|
|
"io/ioutil"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"golang.org/x/tools/internal/lsp/source"
|
|
"golang.org/x/tools/internal/span"
|
|
)
|
|
|
|
// File holds all the information we know about a file.
|
|
type File struct {
|
|
uris []span.URI
|
|
filename string
|
|
basename string
|
|
|
|
view *View
|
|
active bool
|
|
content []byte
|
|
ast *ast.File
|
|
token *token.File
|
|
pkg *Package
|
|
meta *metadata
|
|
imports []*ast.ImportSpec
|
|
}
|
|
|
|
func basename(filename string) string {
|
|
return strings.ToLower(filepath.Base(filename))
|
|
}
|
|
|
|
func (f *File) URI() span.URI {
|
|
return f.uris[0]
|
|
}
|
|
|
|
// View returns the view associated with the file.
|
|
func (f *File) View() source.View {
|
|
return f.view
|
|
}
|
|
|
|
// GetContent returns the contents of the file, reading it from file system if needed.
|
|
func (f *File) GetContent(ctx context.Context) []byte {
|
|
f.view.mu.Lock()
|
|
defer f.view.mu.Unlock()
|
|
|
|
if ctx.Err() == nil {
|
|
f.read(ctx)
|
|
}
|
|
|
|
return f.content
|
|
}
|
|
|
|
func (f *File) GetFileSet(ctx context.Context) *token.FileSet {
|
|
return f.view.Config.Fset
|
|
}
|
|
|
|
func (f *File) GetToken(ctx context.Context) *token.File {
|
|
f.view.mu.Lock()
|
|
defer f.view.mu.Unlock()
|
|
|
|
if f.token == nil || len(f.view.contentChanges) > 0 {
|
|
if _, err := f.view.parse(ctx, f); err != nil {
|
|
return nil
|
|
}
|
|
}
|
|
return f.token
|
|
}
|
|
|
|
func (f *File) GetAST(ctx context.Context) *ast.File {
|
|
f.view.mu.Lock()
|
|
defer f.view.mu.Unlock()
|
|
|
|
if f.ast == nil || len(f.view.contentChanges) > 0 {
|
|
if _, err := f.view.parse(ctx, f); err != nil {
|
|
return nil
|
|
}
|
|
}
|
|
return f.ast
|
|
}
|
|
|
|
func (f *File) GetPackage(ctx context.Context) source.Package {
|
|
f.view.mu.Lock()
|
|
defer f.view.mu.Unlock()
|
|
if f.pkg == nil || len(f.view.contentChanges) > 0 {
|
|
errs, err := f.view.parse(ctx, f)
|
|
if err != nil {
|
|
// Create diagnostics for errors if we are able to.
|
|
if len(errs) > 0 {
|
|
return &Package{errors: errs}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
return f.pkg
|
|
}
|
|
|
|
// read is the internal part of GetContent. It assumes that the caller is
|
|
// holding the mutex of the file's view.
|
|
func (f *File) read(ctx context.Context) {
|
|
if f.content != nil {
|
|
if len(f.view.contentChanges) == 0 {
|
|
return
|
|
}
|
|
|
|
f.view.mcache.mu.Lock()
|
|
err := f.view.applyContentChanges(ctx)
|
|
f.view.mcache.mu.Unlock()
|
|
|
|
if err == nil {
|
|
return
|
|
}
|
|
}
|
|
// We might have the content saved in an overlay.
|
|
if content, ok := f.view.Config.Overlay[f.filename]; ok {
|
|
f.content = content
|
|
return
|
|
}
|
|
// We don't know the content yet, so read it.
|
|
content, err := ioutil.ReadFile(f.filename)
|
|
if err != nil {
|
|
f.view.Logger().Errorf(ctx, "unable to read file %s: %v", f.filename, err)
|
|
return
|
|
}
|
|
f.content = content
|
|
}
|
|
|
|
// isPopulated returns true if all of the computed fields of the file are set.
|
|
func (f *File) isPopulated() bool {
|
|
return f.ast != nil && f.token != nil && f.pkg != nil && f.meta != nil && f.imports != nil
|
|
}
|