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

Commit

Permalink
feat: Goto definition of package and imports (#188)
Browse files Browse the repository at this point in the history
See docs/ folder for more information
  • Loading branch information
tjdevries authored Sep 9, 2021
1 parent 204c522 commit ea3036f
Show file tree
Hide file tree
Showing 44 changed files with 2,625 additions and 332 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ All notable changes to `lsif-go` are documented in this file.

## Unreleased changes

## Fixed

- Many issues relating to package declarations, imports and structs have been fixed.
- See [Package Declarations](./docs/package_declarations.md)
- See [Imports](./docs/imports.md)
- See [Structs](./docs/structs.md)
- Additionally, package declarations are now indexed.

## v1.6.7

### Fixed
Expand Down
1 change: 1 addition & 0 deletions docs/examples/imports/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dump.lsif
839 changes: 839 additions & 0 deletions docs/examples/imports/dump.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions docs/examples/imports/gen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

set -e
set -x

lsif-go-imports

lsif-visualize dump.lsif \
--exclude=sourcegraph:documentationResult \
--exclude=hoverResult \
| dot -Tsvg > dump.svg
3 changes: 3 additions & 0 deletions docs/examples/imports/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module imports

go 1.16
17 changes: 17 additions & 0 deletions docs/examples/imports/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

import (
"fmt"
. "net/http"
s "sort"
)

func Main() {
sortedStrings := []string{"hello", "world", "!"}

// s -> sort
s.Strings(sortedStrings)

// http.CanonicalHeaderKey -> CanonicalHeaderKey
fmt.Println(CanonicalHeaderKey(sortedStrings[0]))
}
1 change: 1 addition & 0 deletions docs/examples/smollest/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dump.lsif
137 changes: 137 additions & 0 deletions docs/examples/smollest/dump.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions docs/examples/smollest/gen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

set -e
set -x

lsif-go

lsif-visualize dump.lsif \
--exclude=sourcegraph:documentationResult \
--exclude=hoverResult \
| dot -Tsvg > dump.svg
3 changes: 3 additions & 0 deletions docs/examples/smollest/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module smollest

go 1.16
2 changes: 2 additions & 0 deletions docs/examples/smollest/lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Hello world, this is a docstring. So we pick this file.
package smollest
1 change: 1 addition & 0 deletions docs/examples/smollest/sub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package smollest
48 changes: 48 additions & 0 deletions docs/imports.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Imports

There are two types of imports available in Go. In both cases, we generate the same reference
to the package itself. This is done by creating an importMoniker. This import moniker

```go
import "fmt"
// ^^^------ reference github.com/golang/go/std/fmt

import f "fmt"
// ^--------- local definition
// ^^^---- reference github.com/golang/go/std/fmt


// Special Case, "." generates no local def
import . "fmt"
// no local def
// ^^^---- reference github.com/golang/go/std/fmt
```

## Example

So given this kind of import, you will see the following.

```go
import (
"fmt"
. "net/http"
s "sort"
)
```

- Regular `"fmt"` import. Creates only a reference to the moniker

![fmt_import](/docs/media/fmt_import.png)

- Named `s "sort"` import. Creates both a reference and a definition. Any local
references to `s` in this case will link back to the definition of this import.
`"sort"` will still link to the external package.

![sort_import](/docs/media/sort_import.png)

![s_definition](/docs/media/s_definition.png)

- `.` import. This will also only create a reference, because `.` does not
create a new definition. It just pulls it into scope.

![http_import](/docs/media/http_import.png)
Binary file added docs/media/fmt_import.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/http_import.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/s_definition.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/media/sort_import.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions docs/package_declarations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Package Declarations


In general, we have used `types.*` structs that match the `types.Object`
interface. However there was no struct that represented the statement:

```go
package mypkg
```

That's the because the majority of the information is held in `types.Package`
and the corresponding definition in `packages.Package.Syntax`.

Since there was no types.PkgDeclaration or similar available, we created our own.
See [types.go](/internal/indexer/types.go)

## Definition vs. Reference

We only emit one definition for a package declaration. The way we pick this is detailed
in `findBestPackageDefinitionPath(...)`. For the `package mypkg`, only the "best" is
picked as the defintion, the other are all emitted as references. This makes sure that we
always jump to the best package declaration when jumping between packages.

For example, if we have a project that contains two files:
- [lib.go](/docs/examples/smollest/lib.go)
- [sub.go](/docs/examples/smollest/sub.go)

In this case the project is literally just two
package declarations. The lsif graph will look like this (some nodes removed):

![smollest_graph](/docs/examples/smollest/dump.svg)

NOTE: the two ranges point to the same resultSet but only one of the ranges
(the range from the `lib.go` file) is chosen as the result for the definition
request.

40 changes: 40 additions & 0 deletions docs/structs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Structs

Structs are generally implemented in a relatively straightforward way.

For example:

```go
type MyStruct struct {
Cli http.Client
^^^----------------- definition MyStruct.Cli
^^^^------------ reference github.com/golang/go/std/http
^^^^^^----- reference github.com/golang/go/std/http.Client
}

```

But, for anonymous fields, it is a little more complicated, and ends up looking something like this.

```go
type NestedHandler struct {
LocalItem
^^^^^^^^^-------- definition MyStruct.LocalItem
^^^^^^^^^-------- reference LocalItem
}
```

In this case it is possible to have the same ranges overlapping, so `lsif-go`
will re-use the same range.

However, in the following case, we have three separate ranges that, while they overlap
are not identical, so they cannot be shared and a new range must be created.

```go
type Nested struct {
http.Handler
^^^^^^^^^^^^-------- definition Nested.Handler
^^^^---------------- reference github.com/golang/go/std/http
^^^^^^^-------- reference github.com/golang/go/std/http.Handler
}
```
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/sourcegraph/lsif-go
go 1.15

require (
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101
github.com/google/go-cmp v0.5.6
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mo
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15 h1:AUNCr9CiJuwrRYS3XieqF+Z9B9gNxo/eANAJCF2eiN4=
github.com/alecthomas/units v0.0.0-20210208195552-ff826a37aa15/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
Expand Down Expand Up @@ -48,6 +51,7 @@ github.com/derision-test/go-mockgen v1.1.2/go.mod h1:9H3VGTWYnL1VJoHHCuPKDpPFmNQ
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
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=
Expand Down
Loading

0 comments on commit ea3036f

Please sign in to comment.