Skip to content
This repository was archived by the owner on Sep 26, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@ require (
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101
github.com/google/go-cmp v0.5.2
github.com/json-iterator/go v1.1.10
github.com/kr/pretty v0.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/pkg/errors v0.9.1
github.com/slimsag/godocmd v0.0.0-20161025000126-a1005ad29fe3
github.com/sourcegraph/lsif-protocol v1.0.0
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v2 v2.2.5 // indirect
)

replace github.com/sourcegraph/lsif-protocol => github.com/alidn/lsif-protocol v1.0.1-0.20210113015314-a4c552ebb760
8 changes: 2 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alidn/lsif-protocol v1.0.1-0.20210113015314-a4c552ebb760 h1:u7CNjLwKGSWHwP9F9Khbj0Oflu1QBmOUcK5PHq/O3w8=
github.com/alidn/lsif-protocol v1.0.1-0.20210113015314-a4c552ebb760/go.mod h1:VEuG8FZ3ISQOAHbzdj+qwS9nUfFlMsP4rVRBnDLztkQ=
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/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/efritz/pentimento v0.0.0-20190429011147-ade47d831101 h1:RylpU+KNJJNEJIk3o8gZ70uPTlutxaYnikKNPko39LA=
github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101/go.mod h1:5ALWO82UZwfAtNRUtwzsWimcrcuYzyieTyyXOXrP6EQ=
github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
Expand All @@ -36,10 +36,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/slimsag/godocmd v0.0.0-20161025000126-a1005ad29fe3 h1:sAARUcYbwxnebBeWHzKX2MeyXtzy25TEglCTz9BhueY=
github.com/slimsag/godocmd v0.0.0-20161025000126-a1005ad29fe3/go.mod h1:AIBPxLCkKUFc2ZkjCXzs/Kk9OUhQLw/Zicdd0Rhqz2U=
github.com/sourcegraph/lsif-protocol v0.0.0-20200827191700-d005ee28c8a1 h1:qzkEXQxHlmGpJrKo6mOe3Tq5zFKZd/+B3DnJlmmrsRA=
github.com/sourcegraph/lsif-protocol v0.0.0-20200827191700-d005ee28c8a1/go.mod h1:VEuG8FZ3ISQOAHbzdj+qwS9nUfFlMsP4rVRBnDLztkQ=
github.com/sourcegraph/lsif-protocol v1.0.0 h1:NLxbnHuN2o4fibjRUrXTwuojD4+kDFPXra9PA1V6tQM=
github.com/sourcegraph/lsif-protocol v1.0.0/go.mod h1:VEuG8FZ3ISQOAHbzdj+qwS9nUfFlMsP4rVRBnDLztkQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
Expand Down
39 changes: 39 additions & 0 deletions internal/indexer/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,23 @@ func findDefintionRangesByDefinitionResultID(elements []interface{}, id uint64)
return ranges
}

func findTypeDefinitionRangesByDefinitionResultID(elements []interface{}, id uint64) (_ protocol.Range, found bool) {
for _, elem := range elements {
switch e := elem.(type) {
case protocol.Item:
if e.OutV == id {
for _, inV := range e.InVs {
if r, ok := findRangeByID(elements, inV); ok {
return r, true
}
}
}
}
}

return protocol.Range{}, false
}

// findReferenceRangesByReferenceResultID returns the ranges attached to the reference result with the given
// identifier.
func findReferenceRangesByReferenceResultID(elements []interface{}, id uint64) (ranges []protocol.Range) {
Expand Down Expand Up @@ -327,6 +344,28 @@ func findDefinitionRangesByRangeOrResultSetID(elements []interface{}, id uint64)
return ranges
}

func findTypeDefinitionRangeByRangeOrResultSetID(elements []interface{}, id uint64) (_ protocol.Range, found bool) {
for _, elem := range elements {
switch e := elem.(type) {
case protocol.TextDocumentTypeDefinition:
if e.OutV == id {
return findTypeDefinitionRangesByDefinitionResultID(elements, e.InV)
}
}
}

for _, elem := range elements {
switch e := elem.(type) {
case protocol.Next:
if e.OutV == id {
return findTypeDefinitionRangeByRangeOrResultSetID(elements, e.InV)
}
}
}

return protocol.Range{}, false
}

// findReferenceRangesByRangeOrResultSetID returns the reference ranges attached to the range or result set with
// the given identifier.
func findReferenceRangesByRangeOrResultSetID(elements []interface{}, id uint64) (ranges []protocol.Range) {
Expand Down
60 changes: 59 additions & 1 deletion internal/indexer/indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func (i *Indexer) Index() error {
i.emitDocuments()
i.addImports()
i.indexDefinitions()
i.indexTypeDefinitions()
i.indexReferences()
i.linkReferenceResultsToRanges()
i.emitContains()
Expand Down Expand Up @@ -267,7 +268,7 @@ func getAllReferencedPackages(pkgs []*packages.Package) (flattened []*packages.P
}

// indexDefinitions emits data for each definition in an index target package. This will emit
// a result set, a definition result, a hover result, and export monikers attached to each range.
// a result set, a definition result, a hover result, a type definition result, and export monikers attached to each range.
// This method will also populate each document's definition range identifier slice.
func (i *Indexer) indexDefinitions() {
i.visitEachPackage("Indexing definitions", i.indexDefinitionsForPackage)
Expand Down Expand Up @@ -319,6 +320,60 @@ func (i *Indexer) indexDefinitionsForPackage(p *packages.Package) {
}
}

// indexTypeDefinitions emits type definition data for each definition and reference in an index target package.
// This will emit an 'item' edge from type definition result to type definition range.
func (i *Indexer) indexTypeDefinitions() {
i.visitEachPackage("Indexing type definitions", i.indexTypeDefinitionForPackage)
}

// indexDefinitionsForPackage emits data for each type definition definition within the given package.
func (i *Indexer) indexTypeDefinitionForPackage(p *packages.Package) {
for _, obj := range p.TypesInfo.Defs {
if obj == nil {
continue
}

defInfo := i.getDefinitionInfo(obj)
if defInfo == nil {
continue
}

if typeRangeID, ok := i.getTypeDefRangeID(obj); ok {
i.emitter.EmitItem(defInfo.TypeDefResultID, []uint64{typeRangeID}, defInfo.DocumentID)
}
}
}

// getTypeDefResultID returns the range id of the type definition if it was emitted. The second result parameter
// indicates whether or not such id is found.
func (i *Indexer) getTypeDefRangeID(obj types.Object) (_ uint64, found bool) {
if namedType, ok := namedTypeFromObj(obj); ok {
if defInfo := i.getDefinitionInfo(namedType.Obj()); defInfo != nil {
return defInfo.RangeID, true
}
}
return 0, false
}

// namedTypeFromObj returns a named type if the given object is of type types.Named, types.Pointer or types.Slice. Otherwise,
// it returns nil and false. If obj is a pointer, it returns the type that it is pointing to, and if it's a slice, it returns
// the type of the slice elements.
func namedTypeFromObj(obj types.Object) (_ *types.Named, ok bool) {
t := obj.Type()
switch t.(type) {
case *types.Named:
res, ok := t.(*types.Named)
return res, ok
case *types.Pointer:
res, ok := t.(*types.Pointer).Elem().(*types.Named)
return res, ok
case *types.Slice:
res, ok := t.(*types.Slice).Elem().(*types.Named)
return res, ok
}
return nil, false
}

// positionAndDocument returns the position of the given object and the document info object
// that contains it. If the given package is not the canonical package for the containing file
// in the packagesByFile map, this method returns false.
Expand Down Expand Up @@ -363,9 +418,11 @@ func (i *Indexer) indexDefinition(p *packages.Package, filename string, document
rangeID := i.emitter.EmitRange(rangeForObject(obj, pos))
resultSetID := i.emitter.EmitResultSet()
defResultID := i.emitter.EmitDefinitionResult()
typeDefResultID := i.emitter.EmitTypeDefinitionResult()

_ = i.emitter.EmitNext(rangeID, resultSetID)
_ = i.emitter.EmitTextDocumentDefinition(resultSetID, defResultID)
_ = i.emitter.EmitTextDocumentTypeDefinition(resultSetID, typeDefResultID)
_ = i.emitter.EmitItem(defResultID, []uint64{rangeID}, document.DocumentID)

if typeSwitchHeader {
Expand Down Expand Up @@ -393,6 +450,7 @@ func (i *Indexer) indexDefinition(p *packages.Package, filename string, document
DocumentID: document.DocumentID,
RangeID: rangeID,
ResultSetID: resultSetID,
TypeDefResultID: typeDefResultID,
ReferenceRangeIDs: map[uint64][]uint64{},
TypeSwitchHeader: typeSwitchHeader,
})
Expand Down
130 changes: 130 additions & 0 deletions internal/indexer/indexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,136 @@ func TestIndexer(t *testing.T) {
compareRange(t, references[3], 26, 1, 26, 3) // wg.Wait()
})

t.Run("Check type definition struct field", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "types.go"), 5, 1)
if !ok {
t.Fatalf("could not find target range")
}

typeDefRange, ok := findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if !ok {
t.Fatalf("expected to find the type definition")
}

compareRange(t, typeDefRange, 2, 5, 2, 15)
})

t.Run("Check type definition struct def field", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "types.go"), 8, 11)
if !ok {
t.Fatalf("could not find target range")
}

typeDefRange, ok := findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if !ok {
t.Fatalf("expected to find the type definition")
}

compareRange(t, typeDefRange, 4, 5, 4, 8)
})

t.Run("Check type definition of reference field", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "types.go"), 9, 1)
if !ok {
t.Fatalf("could not find target range")
}

typeDefRange, ok := findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if !ok {
t.Fatalf("expected to find the type definition")
}

compareRange(t, typeDefRange, 4, 5, 4, 8)
})

t.Run("Check type definition of reference struct", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "types.go"), 10, 9)
if !ok {
t.Fatalf("could not find target range")
}

typeDefRange, ok := findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if !ok {
t.Fatalf("expected to find the type definition")
}

compareRange(t, typeDefRange, 4, 5, 4, 8)
})

t.Run("Check type definition of reference field", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "types.go"), 10, 11)
if !ok {
t.Fatalf("could not find target range")
}

typeDefRange, ok := findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if !ok {
t.Fatalf("expected to find the type definition")
}

compareRange(t, typeDefRange, 2, 5, 2, 15)
})

t.Run("Check type definition of basic type", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "types.go"), 13, 9)
if !ok {
t.Fatalf("could not find target range")
}

_, ok = findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if ok {
t.Fatalf("Did not expect to find the type definition")
}
})

t.Run("Check type definition of pointer", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "types.go"), 16, 9)
if !ok {
t.Fatalf("could not find target range")
}

typeDefRange, ok := findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if !ok {
t.Fatalf("expected to find the type definition")
}

compareRange(t, typeDefRange, 4, 5, 4, 8)
})

t.Run("Check type definition of slice", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "types.go"), 19, 9)
if !ok {
t.Fatalf("could not find target range")
}

typeDefRange, ok := findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if !ok {
t.Fatalf("expected to find the type definition")
}

compareRange(t, typeDefRange, 4, 5, 4, 8)
})

t.Run("Check type definition of var defined in a different package", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "cross_package_types.go"), 6, 9)
if !ok {
t.Fatalf("could not find target range")
}

typeDefRange, ok := findTypeDefinitionRangeByRangeOrResultSetID(w.elements, r.ID)
if !ok {
t.Fatalf("expected to find the type definition")
}

compareRange(t, typeDefRange, 2, 5, 2, 15)

docUri := findDocumentURIContaining(w.elements, typeDefRange.ID)
expectedDocUri := "file://" + filepath.Join(projectRoot, "internal/secret/secret_types.go")
if docUri != expectedDocUri {
t.Fatalf("Unexpected document uri, want=%v have=%v", expectedDocUri, docUri)
}
})

t.Run("check NestedB monikers", func(t *testing.T) {
r, ok := findRange(w.elements, "file://"+filepath.Join(projectRoot, "data.go"), 27, 3)
if !ok {
Expand Down
1 change: 1 addition & 0 deletions internal/indexer/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type DefinitionInfo struct {
DocumentID uint64
RangeID uint64
ResultSetID uint64
TypeDefResultID uint64
ReferenceRangeIDs map[uint64][]uint64
TypeSwitchHeader bool
m sync.Mutex
Expand Down
8 changes: 8 additions & 0 deletions internal/testdata/cross_package_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package testdata

import "github.com/sourcegraph/lsif-go/internal/testdata/internal/secret"

func test() {
secretType := secret.SecretType{}
println(secretType)
}
3 changes: 3 additions & 0 deletions internal/testdata/internal/secret/secret_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package secret

type SecretType struct{}
21 changes: 21 additions & 0 deletions internal/testdata/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package testdata

type InnerField struct{}

type Ali struct {
f InnerField
}

func TryMe(a Ali) {
b := Ali{f: InnerField{}}
println(b.f)

c := "hello"
println(c)

d := &Ali{}
println(d)

e := []Ali{{f: InnerField{}}}
println(e)
}