summaryrefslogtreecommitdiff
path: root/workhorse/internal/lsif_transformer/parser/references.go
diff options
context:
space:
mode:
Diffstat (limited to 'workhorse/internal/lsif_transformer/parser/references.go')
-rw-r--r--workhorse/internal/lsif_transformer/parser/references.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/workhorse/internal/lsif_transformer/parser/references.go b/workhorse/internal/lsif_transformer/parser/references.go
new file mode 100644
index 00000000000..58ff9a61c02
--- /dev/null
+++ b/workhorse/internal/lsif_transformer/parser/references.go
@@ -0,0 +1,107 @@
+package parser
+
+import (
+ "strconv"
+)
+
+type ReferencesOffset struct {
+ Id Id
+ Len int32
+}
+
+type References struct {
+ Items *cache
+ Offsets *cache
+ CurrentOffsetId Id
+}
+
+type SerializedReference struct {
+ Path string `json:"path"`
+}
+
+func NewReferences(config Config) (*References, error) {
+ tempPath := config.TempPath
+
+ items, err := newCache(tempPath, "references", Item{})
+ if err != nil {
+ return nil, err
+ }
+
+ offsets, err := newCache(tempPath, "references-offsets", ReferencesOffset{})
+ if err != nil {
+ return nil, err
+ }
+
+ return &References{
+ Items: items,
+ Offsets: offsets,
+ CurrentOffsetId: 0,
+ }, nil
+}
+
+// Store is responsible for keeping track of references that will be used when
+// serializing in `For`.
+//
+// The references are stored in a file to cache them. It is like
+// `map[Id][]Item` (where `Id` is `refId`) but relies on caching the array and
+// its offset in files for storage to reduce RAM usage. The items can be
+// fetched by calling `getItems`.
+func (r *References) Store(refId Id, references []Item) error {
+ size := len(references)
+
+ if size == 0 {
+ return nil
+ }
+
+ items := append(r.getItems(refId), references...)
+ err := r.Items.SetEntry(r.CurrentOffsetId, items)
+ if err != nil {
+ return err
+ }
+
+ size = len(items)
+ r.Offsets.SetEntry(refId, ReferencesOffset{Id: r.CurrentOffsetId, Len: int32(size)})
+ r.CurrentOffsetId += Id(size)
+
+ return nil
+}
+
+func (r *References) For(docs map[Id]string, refId Id) []SerializedReference {
+ references := r.getItems(refId)
+ if references == nil {
+ 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
+}
+
+func (r *References) Close() error {
+ return combineErrors(
+ r.Items.Close(),
+ r.Offsets.Close(),
+ )
+}
+
+func (r *References) getItems(refId Id) []Item {
+ var offset ReferencesOffset
+ if err := r.Offsets.Entry(refId, &offset); err != nil || offset.Len == 0 {
+ return nil
+ }
+
+ items := make([]Item, offset.Len)
+ if err := r.Items.Entry(offset.Id, &items); err != nil {
+ return nil
+ }
+
+ return items
+}