Skip to content
Merged
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
25 changes: 17 additions & 8 deletions internal/implementations/implementations.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ func AddImplementationRelationships(
pkgs loader.PackageLookup,
allPackages loader.PackageLookup,
symbols *lookup.Global,
) error {
return output.WithProgress("Indexing Implementations", func() error {
) ([]*scip.SymbolInformation, error) {
var externalSymbols []*scip.SymbolInformation
err := output.WithProgress("Indexing Implementations", func() error {
localInterfaces, localTypes, err := extractInterfacesAndConcreteTypes(pkgs, symbols)
if err != nil {
return err
Expand All @@ -123,7 +124,8 @@ func AddImplementationRelationships(

remotePackages[pkgID] = pkg
}
remoteInterfaces, _, err := extractInterfacesAndConcreteTypes(remotePackages, symbols)
remoteInterfaces, remoteTypes, err := extractInterfacesAndConcreteTypes(
remotePackages, symbols)
if err != nil {
return err
}
Expand All @@ -134,15 +136,22 @@ func AddImplementationRelationships(
// local type -> remote interface
findImplementations(localTypes, remoteInterfaces, symbols)

// TODO(author: tjdevries, issue: https://github.com/sourcegraph/scip-go/issues/64)
// We should consider what this would even look like?
// I don't think this makes sense the current way that we are emitting
// implementations. You wouldn't even catch these anyways when uploading
// remote type -> local interface
// findImplementations(remoteTypes, localInterfaces, symbols)
// We emit these as external symbols so index consumer can merge them.
findImplementations(remoteTypes, localInterfaces, symbols)

// Collect remote type symbols that gained relationships
for _, typ := range remoteTypes {
if sym, ok := symbols.GetSymbolInformation(typ.Pkg, typ.Ident.Pos()); ok {
if len(sym.Relationships) > 0 {
externalSymbols = append(externalSymbols, sym)
}
}
}

return nil
})
return externalSymbols, err
}

func implementationsForType(ty ImplDef, tyMethods *intsets.Sparse, interfaceToMethodSet map[*scip.SymbolInformation]*intsets.Sparse) (matching []*scip.SymbolInformation) {
Expand Down
20 changes: 17 additions & 3 deletions internal/index/scip.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,16 @@ func Index(writer func(proto.Message) error, opts config.IndexOpts) error {
return err
}

var externalSymbols []*scip.SymbolInformation
pathToDocument, globalSymbols := indexVisitPackages(opts, projectPackages, allPackages)
if !opts.SkipImplementations {
if err := impls.AddImplementationRelationships(
implSymbols, err := impls.AddImplementationRelationships(
projectPackages, allPackages, globalSymbols,
); err != nil {
)
if err != nil {
return err
}
externalSymbols = implSymbols
}

pkgIDs := slices.Sorted(maps.Keys(projectPackages))
Expand Down Expand Up @@ -156,7 +159,18 @@ func Index(writer func(proto.Message) error, opts config.IndexOpts) error {

output.WithProgressParallel(&wg, "Visiting Project Files", &count, uint64(pkgLen))

return writeErr
if writeErr != nil {
return writeErr
}

// Emit external symbols for remote types that implement local interfaces
for _, sym := range externalSymbols {
if err := writer(sym); err != nil {
return err
}
}

return nil
}

func indexVisitPackages(
Expand Down
9 changes: 9 additions & 0 deletions internal/testdata/snapshots/input/pr198/dep/dep.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dep

import "fmt"

type T struct{}

func (t *T) Bar() {
fmt.Println("Bar")
}
3 changes: 3 additions & 0 deletions internal/testdata/snapshots/input/pr198/dep/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/example/dep

go 1.22
7 changes: 7 additions & 0 deletions internal/testdata/snapshots/input/pr198/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module sg/pr198

go 1.25

require github.com/example/dep v0.0.0

replace github.com/example/dep => ./dep
17 changes: 17 additions & 0 deletions internal/testdata/snapshots/input/pr198/pr198.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package pr198

import "github.com/example/dep"

// Foo is an interface defined downstream of the type that implements it.
// The dep.T type (from a dependency) implements Foo, and scip-go should
// emit an external symbol for dep.T with an IsImplementation relationship
// pointing to Foo.
type Foo interface {
Bar()
}

func UseFoo(f Foo) {}

func Example() {
UseFoo(&dep.T{})
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type Foo int

func (r Foo) nonExportedMethod() {}
func (r Foo) ExportedMethod() {}
func (r Foo) Close() error { return nil }
func (r Foo) ScipTestMethod() {}

type SharedOne interface {
Shared()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package testdata

import "io"

type I3 interface {
Close() error
ScipTestMethod()
}

type EmbeddedI3 interface {
ScipTestMethod()
}

type TClose struct {
io.Closer
EmbeddedI3
}
2 changes: 2 additions & 0 deletions internal/testdata/snapshots/output/pr198/external_symbols.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/example/dep 0.1.test `github.com/example/dep`/T#
relationship 0.1.test `sg/pr198`/Foo# implementation
52 changes: 52 additions & 0 deletions internal/testdata/snapshots/output/pr198/pr198.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package pr198
// ^^^^^ definition 0.1.test `sg/pr198`/
// display_name pr198
// signature_documentation
// > package pr198

import "github.com/example/dep"
// ^^^^^^^^^^^^^^^^^^^^^^ reference github.com/example/dep 0.1.test `github.com/example/dep`/

// Foo is an interface defined downstream of the type that implements it.
// The dep.T type (from a dependency) implements Foo, and scip-go should
// emit an external symbol for dep.T with an IsImplementation relationship
// pointing to Foo.
type Foo interface {
// ^^^ definition 0.1.test `sg/pr198`/Foo#
// signature_documentation
// > type Foo interface{ Bar() }
// documentation
// > Foo is an interface defined downstream of the type that implements it.
// > The dep.T type (from a dependency) implements Foo, and scip-go should
// > emit an external symbol for dep.T with an IsImplementation relationship
// > pointing to Foo.
Bar()
// ^^^ definition 0.1.test `sg/pr198`/Foo#Bar.
// signature_documentation
// > func (Foo).Bar()
}

//⌄ enclosing_range_start 0.1.test `sg/pr198`/UseFoo().
func UseFoo(f Foo) {}
// ^^^^^^ definition 0.1.test `sg/pr198`/UseFoo().
// signature_documentation
// > func UseFoo(f Foo)
// ^ definition local 0
// display_name f
// signature_documentation
// > var f Foo
// ^^^ reference 0.1.test `sg/pr198`/Foo#
// ⌃ enclosing_range_end 0.1.test `sg/pr198`/UseFoo().

//⌄ enclosing_range_start 0.1.test `sg/pr198`/Example().
func Example() {
// ^^^^^^^ definition 0.1.test `sg/pr198`/Example().
// signature_documentation
// > func Example()
UseFoo(&dep.T{})
// ^^^^^^ reference 0.1.test `sg/pr198`/UseFoo().
// ^^^ reference github.com/example/dep 0.1.test `github.com/example/dep`/
// ^ reference github.com/example/dep 0.1.test `github.com/example/dep`/T#
}
//⌃ enclosing_range_end 0.1.test `sg/pr198`/Example().

18 changes: 9 additions & 9 deletions internal/testdata/snapshots/output/testdata/implementations.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
// ^^^ definition 0.1.test `sg/testdata`/Foo#
// signature_documentation
// > type Foo int
// relationship github.com/golang/go/src go1.22 io/Closer# implementation
// relationship 0.1.test `sg/testdata`/EmbeddedI3# implementation
// relationship 0.1.test `sg/testdata`/I3# implementation
// relationship 0.1.test `sg/testdata`/InterfaceWithExportedMethod# implementation
// relationship 0.1.test `sg/testdata`/InterfaceWithNonExportedMethod# implementation
Expand Down Expand Up @@ -141,19 +141,19 @@
// > func (Foo).ExportedMethod()
// relationship 0.1.test `sg/testdata`/InterfaceWithExportedMethod#ExportedMethod. implementation
// ⌃ enclosing_range_end 0.1.test `sg/testdata`/Foo#ExportedMethod().
//⌄ enclosing_range_start 0.1.test `sg/testdata`/Foo#Close().
func (r Foo) Close() error { return nil }
//⌄ enclosing_range_start 0.1.test `sg/testdata`/Foo#ScipTestMethod().
func (r Foo) ScipTestMethod() {}
// ^ definition local 5
// display_name r
// signature_documentation
// > var r Foo
// ^^^ reference 0.1.test `sg/testdata`/Foo#
// ^^^^^ definition 0.1.test `sg/testdata`/Foo#Close().
// signature_documentation
// > func (Foo).Close() error
// relationship github.com/golang/go/src go1.22 io/Closer#Close. implementation
// relationship 0.1.test `sg/testdata`/I3#Close. implementation
// ⌃ enclosing_range_end 0.1.test `sg/testdata`/Foo#Close().
// ^^^^^^^^^^^^^^ definition 0.1.test `sg/testdata`/Foo#ScipTestMethod().
// signature_documentation
// > func (Foo).ScipTestMethod()
// relationship 0.1.test `sg/testdata`/EmbeddedI3#ScipTestMethod. implementation
// relationship 0.1.test `sg/testdata`/I3#ScipTestMethod. implementation
// ⌃ enclosing_range_end 0.1.test `sg/testdata`/Foo#ScipTestMethod().

type SharedOne interface {
// ^^^^^^^^^ definition 0.1.test `sg/testdata`/SharedOne#
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
package testdata
// ^^^^^^^^ definition 0.1.test `sg/testdata`/

import "io"
// ^^ reference github.com/golang/go/src go1.22 io/

type I3 interface {
// ^^ definition 0.1.test `sg/testdata`/I3#
// signature_documentation
// > type I3 interface{ Close() error }
Close() error
// ^^^^^ definition 0.1.test `sg/testdata`/I3#Close.
// signature_documentation
// > func (I3).Close() error
// > type I3 interface{ ScipTestMethod() }
ScipTestMethod()
// ^^^^^^^^^^^^^^ definition 0.1.test `sg/testdata`/I3#ScipTestMethod.
// signature_documentation
// > func (I3).ScipTestMethod()
}

type EmbeddedI3 interface {
// ^^^^^^^^^^ definition 0.1.test `sg/testdata`/EmbeddedI3#
// signature_documentation
// > type EmbeddedI3 interface{ ScipTestMethod() }
ScipTestMethod()
// ^^^^^^^^^^^^^^ definition 0.1.test `sg/testdata`/EmbeddedI3#ScipTestMethod.
// signature_documentation
// > func (EmbeddedI3).ScipTestMethod()
// relationship 0.1.test `sg/testdata`/EmbeddedI3#ScipTestMethod. implementation
// relationship 0.1.test `sg/testdata`/I3#ScipTestMethod. implementation
}

type TClose struct {
// ^^^^^^ definition 0.1.test `sg/testdata`/TClose#
// signature_documentation
// > type TClose struct{ Closer }
// relationship github.com/golang/go/src go1.22 io/Closer# implementation
// > type TClose struct{ EmbeddedI3 }
// relationship 0.1.test `sg/testdata`/EmbeddedI3# implementation
// relationship 0.1.test `sg/testdata`/I3# implementation
io.Closer
// ^^ reference github.com/golang/go/src go1.22 io/
// ^^^^^^ definition 0.1.test `sg/testdata`/TClose#Closer.
// signature_documentation
// > struct field Closer io.Closer
// ^^^^^^ reference github.com/golang/go/src go1.22 io/Closer#
EmbeddedI3
// ^^^^^^^^^^ definition 0.1.test `sg/testdata`/TClose#EmbeddedI3.
// signature_documentation
// > struct field EmbeddedI3 sg/testdata.EmbeddedI3
// ^^^^^^^^^^ reference 0.1.test `sg/testdata`/EmbeddedI3#
}

Loading