Skip to content
This repository has been archived by the owner on Sep 26, 2023. It is now read-only.

Commit

Permalink
Deduplicate external hover result vertices. (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
efritz authored Mar 3, 2020
1 parent 7cc73d2 commit ad3507c
Showing 1 changed file with 78 additions and 17 deletions.
95 changes: 78 additions & 17 deletions internal/index/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,10 @@ type indexer struct {
w *protocol.Writer

// De-duplication
defsIndexed map[string]bool
usesIndexed map[string]bool
ranges map[string]map[int]string // filename -> offset -> rangeID
defsIndexed map[string]bool
usesIndexed map[string]bool
ranges map[string]map[int]string // filename -> offset -> rangeID
hoverResultCache map[string]string

// Type correlation
files map[string]*fileInfo // Keys: filename
Expand Down Expand Up @@ -82,6 +83,7 @@ func NewIndexer(
defsIndexed: map[string]bool{},
usesIndexed: map[string]bool{},
ranges: map[string]map[int]string{},
hoverResultCache: map[string]string{},
files: map[string]*fileInfo{},
imports: map[token.Pos]*defInfo{},
funcs: map[string]*defInfo{},
Expand Down Expand Up @@ -465,14 +467,9 @@ func (i *indexer) indexDefs(pkgs []*packages.Package, p *packages.Package, f *as
}
}

contents, err := findContents(pkgs, p, f, obj)
hoverResultID, err := i.makeCachedHoverResult(pkgs, p, f, obj)
if err != nil {
return fmt.Errorf("find contents: %v", err)
}

hoverResultID, err := i.w.EmitHoverResult(contents)
if err != nil {
return fmt.Errorf(`emit "hoverResult": %v`, err)
return err
}

_, err = i.w.EmitTextDocumentHover(refResult.resultSetID, hoverResultID)
Expand Down Expand Up @@ -539,17 +536,12 @@ func (i *indexer) indexUses(pkgs []*packages.Package, p *packages.Package, fi *f
rangeIDs = append(rangeIDs, rangeID)

if def == nil {
contents, err := externalHoverContents(pkgs, p, obj, pkg)
hoverResultID, err := i.makeCachedExternalHoverResult(pkgs, p, obj, pkg)
if err != nil {
return err
}

if contents != nil {
hoverResultID, err := i.w.EmitHoverResult(contents)
if err != nil {
return fmt.Errorf(`emit "hoverResult": %v`, err)
}

if hoverResultID != "" {
_, err = i.w.EmitTextDocumentHover(rangeID, hoverResultID)
if err != nil {
return fmt.Errorf(`emit "textDocument/hover": %v`, err)
Expand Down Expand Up @@ -604,6 +596,75 @@ func (i *indexer) indexUses(pkgs []*packages.Package, p *packages.Package, fi *f
return nil
}

// makeCachedHoverResult creates a hover result vertex and returns its iD. This
// method should be called for each definition in the set of indexed files. This
// method will not create a new vertex for a pkgName object that has been seen
// before. Because package text is likely to be large, and repeated at each import
// and each use in the file (over many multiple files), this can save many copies
// of the same text.
func (i *indexer) makeCachedHoverResult(pkgs []*packages.Package, p *packages.Package, f *ast.File, obj types.Object) (string, error) {
pkgName, ok := obj.(*types.PkgName)
if !ok {
// Defined in file, generate unique text
return i.makeHoverResult(pkgs, p, f, obj)
}

key := pkgName.Imported().Path()
if hoverResultID, ok := i.hoverResultCache[key]; ok {
return hoverResultID, nil
}

hoverResultID, err := i.makeHoverResult(pkgs, p, f, obj)
if err != nil {
return "", err
}
i.hoverResultCache[key] = hoverResultID

return hoverResultID, nil
}

// makeHoverResult create a hover result vertex and returns its ID. This method
// should be called for each definition in the set of indexed files.
func (i *indexer) makeHoverResult(pkgs []*packages.Package, p *packages.Package, f *ast.File, obj types.Object) (string, error) {
contents, err := findContents(pkgs, p, f, obj)
if err != nil {
return "", fmt.Errorf("find contents: %v", err)
}

hoverResultID, err := i.w.EmitHoverResult(contents)
if err != nil {
return "", fmt.Errorf(`emit "hoverResult": %v`, err)
}

return hoverResultID, nil
}

// makeCachedExternalHoverResult creates a hover result vertex and returns its ID.
// This method should be called for objects defined externally with a resolvable
// package. This method will only make a new vertex if the path and object-position
// pair has not been seen before. Because some methods in an external package are
// likely to be used more than once in a project, this can save many copies of the
// same text.
func (i *indexer) makeCachedExternalHoverResult(pkgs []*packages.Package, p *packages.Package, obj types.Object, pkg *types.Package) (string, error) {
key := fmt.Sprintf("%s::%d", pkg.Path(), obj.Pos())
if hoverResultID, ok := i.hoverResultCache[key]; ok {
return hoverResultID, nil
}

contents, err := externalHoverContents(pkgs, p, obj, pkg)
if err != nil || contents == nil {
return "", err
}

hoverResultID, err := i.w.EmitHoverResult(contents)
if err != nil {
return "", fmt.Errorf(`emit "hoverResult": %v`, err)
}
i.hoverResultCache[key] = hoverResultID

return hoverResultID, nil
}

func (i *indexer) ensurePackageInformation(packageName, version string) (string, error) {
packageInformationID, ok := i.packageInformationIDs[packageName]
if ok {
Expand Down

0 comments on commit ad3507c

Please sign in to comment.