Commit d3318859 authored by Igor Drozdov's avatar Igor Drozdov

Accept string or int type for LSIF ids

Define Id type with custom marshalling which accepts either
int or string, because some languages (for example, Javascript)
define ids in LSIF as ints, but some languages (like Golang) use
string type for ids

It also changes int to uint32 for easier binary conversion
parent a87438cf
......@@ -12,19 +12,19 @@ type Line struct {
type Docs struct {
Root string
Entries map[string]string
DocRanges map[string][]string
Entries map[Id]string
DocRanges map[Id][]Id
Ranges *Ranges
}
type Document struct {
Id string `json:"id"`
Id Id `json:"id"`
Uri string `json:"uri"`
}
type DocumentRange struct {
OutV string `json:"outV"`
RangeIds []string `json:"inVs"`
OutV Id `json:"outV"`
RangeIds []Id `json:"inVs"`
}
type Metadata struct {
......@@ -39,8 +39,8 @@ func NewDocs(tempDir string) (*Docs, error) {
return &Docs{
Root: "file:///",
Entries: make(map[string]string),
DocRanges: make(map[string][]string),
Entries: make(map[Id]string),
DocRanges: make(map[Id][]Id),
Ranges: ranges,
}, nil
}
......
......@@ -23,9 +23,9 @@ func TestRead(t *testing.T) {
require.NoError(t, d.Read(createLine("3", "document", "file:///Users/nested/folder/file.rb")))
require.NoError(t, d.Read(createLine("4", "document", "file:///Users/wrong/file.rb")))
require.Equal(t, d.Entries["2"], "file.rb")
require.Equal(t, d.Entries["3"], "folder/file.rb")
require.Equal(t, d.Entries["4"], "file:///Users/wrong/file.rb")
require.Equal(t, d.Entries[2], "file.rb")
require.Equal(t, d.Entries[3], "folder/file.rb")
require.Equal(t, d.Entries[4], "file:///Users/wrong/file.rb")
}
func TestReadContainsLine(t *testing.T) {
......@@ -37,5 +37,5 @@ func TestReadContainsLine(t *testing.T) {
require.NoError(t, d.Read(line))
require.Equal(t, []string{"2", "3"}, d.DocRanges["1"])
require.Equal(t, []Id{2, 3}, d.DocRanges[1])
}
......@@ -12,7 +12,7 @@ type Offset struct {
}
type Hovers struct {
Offsets map[string]*Offset
Offsets map[Id]*Offset
File *os.File
CurrentOffset int
}
......@@ -22,18 +22,18 @@ type RawResult struct {
}
type RawData struct {
Id string `json:"id"`
Id Id `json:"id"`
Result RawResult `json:"result"`
}
type HoverRef struct {
ResultSetId string `json:"outV"`
HoverId string `json:"inV"`
ResultSetId Id `json:"outV"`
HoverId Id `json:"inV"`
}
type ResultSetRef struct {
ResultSetId string `json:"outV"`
RefId string `json:"inV"`
ResultSetId Id `json:"outV"`
RefId Id `json:"inV"`
}
func NewHovers(tempDir string) (*Hovers, error) {
......@@ -43,7 +43,7 @@ func NewHovers(tempDir string) (*Hovers, error) {
}
return &Hovers{
Offsets: make(map[string]*Offset),
Offsets: make(map[Id]*Offset),
File: file,
CurrentOffset: 0,
}, nil
......@@ -68,7 +68,7 @@ func (h *Hovers) Read(label string, line []byte) error {
return nil
}
func (h *Hovers) For(refId string) json.RawMessage {
func (h *Hovers) For(refId Id) json.RawMessage {
offset, ok := h.Offsets[refId]
if !ok || offset == nil {
return nil
......
......@@ -9,7 +9,7 @@ import (
func TestHoversRead(t *testing.T) {
h := setupHovers(t)
require.Equal(t, `[{"value":"hello"}]`, string(h.For("1")))
require.Equal(t, `[{"value":"hello"}]`, string(h.For(1)))
require.NoError(t, h.Close())
}
......@@ -19,8 +19,8 @@ func setupHovers(t *testing.T) *Hovers {
require.NoError(t, err)
require.NoError(t, h.Read("hoverResult", []byte(`{"id":"2","label":"hoverResult","result":{"contents": ["hello"]}}`)))
require.NoError(t, h.Read("textDocument/hover", []byte(`{"id":"4","label":"textDocument/hover","outV":"3","inV":"2"}`)))
require.NoError(t, h.Read("textDocument/references", []byte(`{"id":"3","label":"textDocument/references","outV":"3","inV":"1"}`)))
require.NoError(t, h.Read("textDocument/hover", []byte(`{"id":4,"label":"textDocument/hover","outV":"3","inV":2}`)))
require.NoError(t, h.Read("textDocument/references", []byte(`{"id":"3","label":"textDocument/references","outV":3,"inV":"1"}`)))
return h
}
package parser
import (
"encoding/json"
"errors"
"strconv"
)
const (
minId = 1
maxId = 20 * 1000 * 1000
)
type Id int32
func (id *Id) UnmarshalJSON(b []byte) error {
if b[0] != '"' {
if err := id.unmarshalInt(b); err != nil {
return err
}
} else {
if err := id.unmarshalString(b); err != nil {
return err
}
}
if *id < minId || *id > maxId {
return errors.New("json: id is invalid")
}
return nil
}
func (id *Id) unmarshalInt(b []byte) error {
return json.Unmarshal(b, (*int32)(id))
}
func (id *Id) unmarshalString(b []byte) error {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
i, err := strconv.Atoi(s)
if err != nil {
return err
}
*id = Id(i)
return nil
}
package parser
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
type jsonWithId struct {
Value Id `json:"value"`
}
func TestId(t *testing.T) {
var v jsonWithId
require.NoError(t, json.Unmarshal([]byte(`{ "value": 1230 }`), &v))
require.Equal(t, Id(1230), v.Value)
require.NoError(t, json.Unmarshal([]byte(`{ "value": "1230" }`), &v))
require.Equal(t, Id(1230), v.Value)
require.Error(t, json.Unmarshal([]byte(`{ "value": "1.5" }`), &v))
require.Error(t, json.Unmarshal([]byte(`{ "value": 1.5 }`), &v))
require.Error(t, json.Unmarshal([]byte(`{ "value": "-1" }`), &v))
require.Error(t, json.Unmarshal([]byte(`{ "value": -1 }`), &v))
require.Error(t, json.Unmarshal([]byte(`{ "value": 21000000 }`), &v))
require.Error(t, json.Unmarshal([]byte(`{ "value": "21000000" }`), &v))
}
......@@ -10,37 +10,37 @@ const Definitions = "definitions"
const References = "references"
type Ranges struct {
Entries map[string]*Range
DefRefs map[string]*DefRef
Entries map[Id]*Range
DefRefs map[Id]*DefRef
Hovers *Hovers
}
type RawRange struct {
Id string `json:"id"`
Id Id `json:"id"`
Data Range `json:"start"`
}
type Range struct {
Line int `json:"line"`
Character int `json:"character"`
RefId string
Line int32 `json:"line"`
Character int32 `json:"character"`
RefId Id
}
type RawDefRef struct {
Property string `json:"property"`
RefId string `json:"outV"`
RangeIds []string `json:"inVs"`
DocId string `json:"document"`
RefId Id `json:"outV"`
RangeIds []Id `json:"inVs"`
DocId Id `json:"document"`
}
type DefRef struct {
Line string
DocId string
DocId Id
}
type SerializedRange struct {
StartLine int `json:"start_line"`
StartChar int `json:"start_char"`
StartLine int32 `json:"start_line"`
StartChar int32 `json:"start_char"`
DefinitionPath string `json:"definition_path,omitempty"`
Hover json.RawMessage `json:"hover"`
}
......@@ -52,8 +52,8 @@ func NewRanges(tempDir string) (*Ranges, error) {
}
return &Ranges{
Entries: make(map[string]*Range),
DefRefs: make(map[string]*DefRef),
Entries: make(map[Id]*Range),
DefRefs: make(map[Id]*DefRef),
Hovers: hovers,
}, nil
}
......@@ -75,7 +75,7 @@ func (r *Ranges) Read(label string, line []byte) error {
return nil
}
func (r *Ranges) Serialize(f io.Writer, rangeIds []string, docs map[string]string) error {
func (r *Ranges) Serialize(f io.Writer, rangeIds []Id, docs map[Id]string) error {
encoder := json.NewEncoder(f)
n := len(rangeIds)
......@@ -112,7 +112,7 @@ func (r *Ranges) Close() error {
return r.Hovers.Close()
}
func (r *Ranges) definitionPathFor(docs map[string]string, refId string) string {
func (r *Ranges) definitionPathFor(docs map[Id]string, refId Id) string {
defRef, ok := r.DefRefs[refId]
if !ok {
return ""
......@@ -157,7 +157,7 @@ func (r *Ranges) addItem(line []byte) error {
defRange := r.Entries[defRef.RangeIds[0]]
r.DefRefs[defRef.RefId] = &DefRef{
Line: strconv.Itoa(defRange.Line + 1),
Line: strconv.Itoa(int(defRange.Line + 1)),
DocId: defRef.DocId,
}
......
......@@ -11,21 +11,21 @@ func TestRangesRead(t *testing.T) {
r, cleanup := setup(t)
defer cleanup()
firstRange := Range{Line: 1, Character: 2, RefId: "3"}
require.Equal(t, &firstRange, r.Entries["1"])
firstRange := Range{Line: 1, Character: 2, RefId: 3}
require.Equal(t, &firstRange, r.Entries[1])
secondRange := Range{Line: 5, Character: 4, RefId: "3"}
require.Equal(t, &secondRange, r.Entries["2"])
secondRange := Range{Line: 5, Character: 4, RefId: 3}
require.Equal(t, &secondRange, r.Entries[2])
}
func TestSerialize(t *testing.T) {
r, cleanup := setup(t)
defer cleanup()
docs := map[string]string{"6": "def-path"}
docs := map[Id]string{6: "def-path"}
var buf bytes.Buffer
err := r.Serialize(&buf, []string{"1"}, docs)
err := r.Serialize(&buf, []Id{1}, docs)
want := `[{"start_line":1,"start_char":2,"definition_path":"def-path#L2","hover":null}` + "\n]"
require.NoError(t, err)
......@@ -36,11 +36,11 @@ func setup(t *testing.T) (*Ranges, func()) {
r, err := NewRanges("")
require.NoError(t, err)
require.NoError(t, r.Read("range", []byte(`{"id":"1","label":"range","start":{"line":1,"character":2}}`)))
require.NoError(t, r.Read("range", []byte(`{"id":1,"label":"range","start":{"line":1,"character":2}}`)))
require.NoError(t, r.Read("range", []byte(`{"id":"2","label":"range","start":{"line":5,"character":4}}`)))
require.NoError(t, r.Read("item", []byte(`{"id":"4","label":"item","property":"definitions","outV":"3","inVs":["1"],"document":"6"}`)))
require.NoError(t, r.Read("item", []byte(`{"id":"4","label":"item","property":"references","outV":"3","inVs":["2"]}`)))
require.NoError(t, r.Read("item", []byte(`{"id":4,"label":"item","property":"definitions","outV":"3","inVs":[1],"document":"6"}`)))
require.NoError(t, r.Read("item", []byte(`{"id":"5","label":"item","property":"references","outV":3,"inVs":["2"]}`)))
cleanup := func() {
require.NoError(t, r.Close())
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment