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

Commit

Permalink
Do not emit duplicate ranges (#37)
Browse files Browse the repository at this point in the history
  • Loading branch information
efritz authored Feb 13, 2020
1 parent 5805e96 commit a69df3e
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 41 deletions.
8 changes: 6 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ require (
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/google/uuid v1.1.1
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/slimsag/godocmd v0.0.0-20161025000126-a1005ad29fe3
golang.org/x/tools v0.0.0-20191121040551-947d4aa89328
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.2.5 // indirect
)
27 changes: 22 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2c
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/slimsag/godocmd v0.0.0-20161025000126-a1005ad29fe3 h1:sAARUcYbwxnebBeWHzKX2MeyXtzy25TEglCTz9BhueY=
Expand All @@ -16,14 +21,26 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191121040551-947d4aa89328 h1:t3X42h9e6xdbrCD/gPyWqAXr2BEpdJqRd1brThaaxII=
golang.org/x/tools v0.0.0-20191121040551-947d4aa89328/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56 h1:DFtSed2q3HtNuVazwVDZ4nSRS/JrZEig0gz2BY4VNrg=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
164 changes: 130 additions & 34 deletions index/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ type indexer struct {
toolInfo protocol.ToolInfo
w io.Writer

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

// Type correlation
id int // The ID counter of the last element emitted
files map[string]*fileInfo // Keys: filename
Expand Down Expand Up @@ -70,6 +75,9 @@ func NewIndexer(projectRoot, moduleName, moduleVersion string, dependencies map[
w: w,

// Empty maps
defsIndexed: map[string]bool{},
usesIndexed: map[string]bool{},
ranges: map[string]map[int]string{},
files: map[string]*fileInfo{},
imports: map[token.Pos]*defInfo{},
funcs: map[string]*defInfo{},
Expand Down Expand Up @@ -120,8 +128,6 @@ func (e *indexer) packages() ([]*packages.Package, error) {
}

func (e *indexer) index(pkgs []*packages.Package) (*Stats, error) {
log.Infoln("Indexing packages...")

_, err := e.emitMetaData("file://"+e.projectRoot, e.toolInfo)
if err != nil {
return nil, fmt.Errorf(`emit "metadata": %v`, err)
Expand All @@ -137,11 +143,23 @@ func (e *indexer) index(pkgs []*packages.Package) (*Stats, error) {
}

for _, p := range pkgs {
if err := e.indexPkg(p, proID); err != nil {
if err := e.indexPkgDocs(p, proID); err != nil {
return nil, fmt.Errorf("index package %q: %v", p.Name, err)
}

if err := e.indexPkgDefs(p, proID); err != nil {
return nil, fmt.Errorf("index package defs %q: %v", p.Name, err)
}
}

for _, p := range pkgs {
if err := e.indexPkgUses(p, proID); err != nil {
return nil, fmt.Errorf("index package uses %q: %v", p.Name, err)
}
}

log.Infoln("Linking references...")

for _, f := range e.files {
if e.printProgressDots {
fmt.Fprintf(os.Stdout, ".")
Expand Down Expand Up @@ -174,7 +192,20 @@ func (e *indexer) index(pkgs []*packages.Package) (*Stats, error) {
}

if len(f.defRangeIDs) > 0 || len(f.useRangeIDs) > 0 {
_, err = e.emitContains(f.docID, append(f.defRangeIDs, f.useRangeIDs...))
// Deduplicate ranges before emitting a contains edge
union := map[string]bool{}
for _, id := range f.defRangeIDs {
union[id] = true
}
for _, id := range f.useRangeIDs {
union[id] = true
}
allRanges := []string{}
for id := range union {
allRanges = append(allRanges, id)
}

_, err = e.emitContains(f.docID, allRanges)
if err != nil {
return nil, fmt.Errorf(`emit "contains": %v`, err)
}
Expand Down Expand Up @@ -204,35 +235,71 @@ func (e *indexer) index(pkgs []*packages.Package) (*Stats, error) {
}, nil
}

func (e *indexer) indexPkg(p *packages.Package, proID string) (err error) {
log.Infoln("Package:", p.Name)
func (e *indexer) indexPkgDocs(p *packages.Package, proID string) (err error) {
log.Infoln("Emitting documents for package", p.Name)
defer log.Infoln()

for _, f := range p.Syntax {
fpos := p.Fset.Position(f.Package)
if !strings.HasPrefix(fpos.Filename, e.projectRoot) {
// Indexing test files means that we're also indexing the code generated by go test;
// e.g. file://Users/efritz/Library/Caches/go-build/07/{64-character identifier}-d
continue
}

if _, ok := e.files[fpos.Filename]; ok {
// Emit each document only once
continue
}

log.Infoln("\tFile:", fpos.Filename)

fi, ok := e.files[fpos.Filename]
if !ok {
docID, err := e.emitDocument(fpos.Filename)
if err != nil {
return fmt.Errorf(`emit "document": %v`, err)
}
docID, err := e.emitDocument(fpos.Filename)
if err != nil {
return fmt.Errorf(`emit "document": %v`, err)
}

_, err = e.emitBeginEvent("document", docID)
if err != nil {
return fmt.Errorf(`emit "begin": %v`, err)
}
_, err = e.emitBeginEvent("document", docID)
if err != nil {
return fmt.Errorf(`emit "begin": %v`, err)
}

_, err = e.emitContains(proID, []string{docID})
if err != nil {
return fmt.Errorf(`emit "contains": %v`, err)
}
_, err = e.emitContains(proID, []string{docID})
if err != nil {
return fmt.Errorf(`emit "contains": %v`, err)
}

fi := &fileInfo{docID: docID}
e.files[fpos.Filename] = fi

// Create the map used to deduplicate ids within this file. This will be used
// by indexPkgDefs and indexPkgUses, which assumes this key is already populated.
e.ranges[fpos.Filename] = map[int]string{}
}

fi = &fileInfo{docID: docID}
e.files[fpos.Filename] = fi
return nil
}

func (e *indexer) indexPkgDefs(p *packages.Package, proID string) (err error) {
log.Infoln("Emitting definitions for package", p.Name)
defer log.Infoln()

for _, f := range p.Syntax {
fpos := p.Fset.Position(f.Package)
fi, ok := e.files[fpos.Filename]
if !ok {
// File skipped in the loop above
continue
}

if _, ok := e.defsIndexed[fpos.Filename]; ok {
// Defs already indexed
continue
}
e.defsIndexed[fpos.Filename] = true

log.Infoln("\tFile:", fpos.Filename)

if err = e.addImports(p, f, fi); err != nil {
return fmt.Errorf("error indexing imports of %q: %v", p.PkgPath, err)
}
Expand All @@ -242,14 +309,30 @@ func (e *indexer) indexPkg(p *packages.Package, proID string) (err error) {
}
}

// NOTE: As long as the flag `packages.NeedDeps` is passed to the load config,
// `go/packages` does a post-order traversal of packages. That means
// dependencies of a package are visited before the package itself, which
// guarantees all defs that would be referenced in this package have been
// added by the time this package is visited.
return nil
}

func (e *indexer) indexPkgUses(p *packages.Package, proID string) (err error) {
log.Infoln("Emitting references for package", p.Name)
defer log.Infoln()

for _, f := range p.Syntax {
fpos := p.Fset.Position(f.Package)
if err := e.indexUses(p, e.files[fpos.Filename], fpos.Filename); err != nil {
fi, ok := e.files[fpos.Filename]
if !ok {
// File skipped in the loop above
continue
}

if _, ok := e.usesIndexed[fpos.Filename]; ok {
// Uses already indexed
continue
}
e.usesIndexed[fpos.Filename] = true

log.Infoln("\tFile:", fpos.Filename)

if err := e.indexUses(p, fi, fpos.Filename); err != nil {
return fmt.Errorf("error indexing uses of %q: %v", p.PkgPath, err)
}
}
Expand Down Expand Up @@ -298,18 +381,23 @@ func (e *indexer) indexDefs(p *packages.Package, f *ast.File, fi *fileInfo, proI
continue
}

// TODO(jchen): emit other documents on the fly, thus we do not need to iterate
// over this map once for every file.
// Only emit if the object belongs to current file
ipos := p.Fset.Position(ident.Pos())
if ipos.Filename != filename {
continue
}

// If we have a range for this offset then we've already indexed
// this definition. Just early out in this situation.
if _, ok := e.ranges[filename][ipos.Offset]; ok {
continue
}

rangeID, err := e.emitRange(lspRange(ipos, ident.Name))
if err != nil {
return fmt.Errorf(`emit "range": %v`, err)
}
e.ranges[filename][ipos.Offset] = rangeID

refResult, ok := e.refs[rangeID]
if !ok {
Expand Down Expand Up @@ -501,10 +589,19 @@ func (e *indexer) indexUses(p *packages.Package, fi *fileInfo, filename string)
continue
}

rangeID, err := e.emitRange(lspRange(ipos, ident.Name))
if err != nil {
return fmt.Errorf(`emit "range": %v`, err)
var err error

// Make a new range if we haven't already seen a def or a use that had
// constructed a range at the same position.
rangeID, ok := e.ranges[filename][ipos.Offset]
if !ok {
rangeID, err = e.emitRange(lspRange(ipos, ident.Name))
if err != nil {
return fmt.Errorf(`emit "range": %v`, err)
}
e.ranges[filename][ipos.Offset] = rangeID
}

rangeIDs = append(rangeIDs, rangeID)

if def == nil {
Expand Down Expand Up @@ -553,7 +650,6 @@ func (e *indexer) indexUses(p *packages.Package, fi *fileInfo, filename string)
}

fi.useRangeIDs = append(fi.useRangeIDs, rangeIDs...)

return nil
}

Expand Down

0 comments on commit a69df3e

Please sign in to comment.