From 55363e35abcf62b25f017668ef7d870429da29ce Mon Sep 17 00:00:00 2001
From: Patrick Bajao <ebajao@gitlab.com>
Date: Fri, 7 Aug 2020 11:46:35 +0800
Subject: [PATCH] Add References struct

Extract references parsing logic to a separate file and struct.
Also modified `Item` struct to have `Line` as `int32` so it'll
be fixed size.

This is in preparation for another MR wherein references will be
stored in file instead of memory.
---
 internal/lsif_transformer/parser/ranges.go    | 54 ++++++-------------
 .../lsif_transformer/parser/references.go     | 50 +++++++++++++++++
 .../parser/references_test.go                 | 24 +++++++++
 3 files changed, 89 insertions(+), 39 deletions(-)
 create mode 100644 internal/lsif_transformer/parser/references.go
 create mode 100644 internal/lsif_transformer/parser/references_test.go

diff --git a/internal/lsif_transformer/parser/ranges.go b/internal/lsif_transformer/parser/ranges.go
index 3ff90bea5c735..b95b508d4eb6e 100644
--- a/internal/lsif_transformer/parser/ranges.go
+++ b/internal/lsif_transformer/parser/ranges.go
@@ -14,7 +14,7 @@ const (
 
 type Ranges struct {
 	DefRefs           map[Id]Item
-	References        map[Id][]Item
+	References        *References
 	Hovers            *Hovers
 	Cache             *cache
 	ProcessReferences bool
@@ -39,7 +39,7 @@ type RawItem struct {
 }
 
 type Item struct {
-	Line  string
+	Line  int32
 	DocId Id
 }
 
@@ -51,10 +51,6 @@ type SerializedRange struct {
 	References     []SerializedReference `json:"references,omitempty"`
 }
 
-type SerializedReference struct {
-	Path string `json:"path"`
-}
-
 func NewRanges(config Config) (*Ranges, error) {
 	hovers, err := NewHovers(config)
 	if err != nil {
@@ -67,11 +63,10 @@ func NewRanges(config Config) (*Ranges, error) {
 	}
 
 	return &Ranges{
-		DefRefs:           make(map[Id]Item),
-		References:        make(map[Id][]Item),
-		Hovers:            hovers,
-		Cache:             cache,
-		ProcessReferences: config.ProcessReferences,
+		DefRefs:    make(map[Id]Item),
+		References: NewReferences(config),
+		Hovers:     hovers,
+		Cache:      cache,
 	}, nil
 }
 
@@ -111,7 +106,7 @@ func (r *Ranges) Serialize(f io.Writer, rangeIds []Id, docs map[Id]string) error
 			StartChar:      entry.Character,
 			DefinitionPath: r.definitionPathFor(docs, entry.RefId),
 			Hover:          r.Hovers.For(entry.RefId),
-			References:     r.referencesFor(docs, entry.RefId),
+			References:     r.References.For(docs, entry.RefId),
 		}
 		if err := encoder.Encode(serializedRange); err != nil {
 			return err
@@ -143,34 +138,11 @@ func (r *Ranges) definitionPathFor(docs map[Id]string, refId Id) string {
 		return ""
 	}
 
-	defPath := docs[defRef.DocId] + "#L" + defRef.Line
+	defPath := docs[defRef.DocId] + "#L" + strconv.Itoa(int(defRef.Line))
 
 	return defPath
 }
 
-func (r *Ranges) referencesFor(docs map[Id]string, refId Id) []SerializedReference {
-	if !r.ProcessReferences {
-		return nil
-	}
-
-	references, ok := r.References[refId]
-	if !ok {
-		return nil
-	}
-
-	var serializedReferences []SerializedReference
-
-	for _, reference := range references {
-		serializedReference := SerializedReference{
-			Path: docs[reference.DocId] + "#L" + reference.Line,
-		}
-
-		serializedReferences = append(serializedReferences, serializedReference)
-	}
-
-	return serializedReferences
-}
-
 func (r *Ranges) addRange(line []byte) error {
 	var rg RawRange
 	if err := json.Unmarshal(line, &rg); err != nil {
@@ -194,6 +166,8 @@ func (r *Ranges) addItem(line []byte) error {
 		return errors.New("no range IDs")
 	}
 
+	var references []Item
+
 	for _, rangeId := range rawItem.RangeIds {
 		rg, err := r.getRange(rangeId)
 		if err != nil {
@@ -207,17 +181,19 @@ func (r *Ranges) addItem(line []byte) error {
 		}
 
 		item := Item{
-			Line:  strconv.Itoa(int(rg.Line + 1)),
+			Line:  rg.Line + 1,
 			DocId: rawItem.DocId,
 		}
 
 		if rawItem.Property == definitions {
 			r.DefRefs[rawItem.RefId] = item
-		} else if r.ProcessReferences {
-			r.References[rawItem.RefId] = append(r.References[rawItem.RefId], item)
+		} else {
+			references = append(references, item)
 		}
 	}
 
+	r.References.Store(rawItem.RefId, references)
+
 	return nil
 }
 
diff --git a/internal/lsif_transformer/parser/references.go b/internal/lsif_transformer/parser/references.go
new file mode 100644
index 0000000000000..238472f84054d
--- /dev/null
+++ b/internal/lsif_transformer/parser/references.go
@@ -0,0 +1,50 @@
+package parser
+
+import (
+	"strconv"
+)
+
+type References struct {
+	Items             map[Id][]Item
+	ProcessReferences bool
+}
+
+type SerializedReference struct {
+	Path string `json:"path"`
+}
+
+func NewReferences(config Config) *References {
+	return &References{
+		Items:             make(map[Id][]Item),
+		ProcessReferences: config.ProcessReferences,
+	}
+}
+
+func (r *References) Store(refId Id, references []Item) {
+	if r.ProcessReferences {
+		r.Items[refId] = references
+	}
+}
+
+func (r *References) For(docs map[Id]string, refId Id) []SerializedReference {
+	if !r.ProcessReferences {
+		return nil
+	}
+
+	references, ok := r.Items[refId]
+	if !ok {
+		return nil
+	}
+
+	var serializedReferences []SerializedReference
+
+	for _, reference := range references {
+		serializedReference := SerializedReference{
+			Path: docs[reference.DocId] + "#L" + strconv.Itoa(int(reference.Line)),
+		}
+
+		serializedReferences = append(serializedReferences, serializedReference)
+	}
+
+	return serializedReferences
+}
diff --git a/internal/lsif_transformer/parser/references_test.go b/internal/lsif_transformer/parser/references_test.go
new file mode 100644
index 0000000000000..f086b00a2e9e3
--- /dev/null
+++ b/internal/lsif_transformer/parser/references_test.go
@@ -0,0 +1,24 @@
+package parser
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestReferencesStore(t *testing.T) {
+	const (
+		docId = 1
+		refId = 3
+	)
+
+	r := NewReferences(Config{ProcessReferences: true})
+
+	r.Store(refId, []Item{{Line: 2, DocId: docId}, {Line: 3, DocId: docId}})
+
+	docs := map[Id]string{docId: "doc.go"}
+	serializedReferences := r.For(docs, refId)
+
+	require.Contains(t, serializedReferences, SerializedReference{Path: "doc.go#L2"})
+	require.Contains(t, serializedReferences, SerializedReference{Path: "doc.go#L3"})
+}
-- 
GitLab