Skip to content

Commit a189bd2

Browse files
Full multiple definitions support (#33)
* Full multiple definitions support Some references to vars and self were lost along the way This works for most use cases now There's still some refactoring done, both for performance and for cleanliness (lots of repeated code) but it all works now I will add a video on the README once this is merged Closes #6 * comment outside of func * Update pkg/processing/find_field.go Co-authored-by: Zack Zehring <[email protected]> Co-authored-by: Zack Zehring <[email protected]>
1 parent 4cb1092 commit a189bd2

7 files changed

+116
-11
lines changed

pkg/processing/find_field.go

+41-11
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,25 @@ func FindRangesFromIndexList(stack *nodestack.NodeStack, indexList []string, vm
119119
return ranges, nil
120120
}
121121

122-
// Unpack binary nodes. A field could be either in the left or right side of the binary
122+
// Unpack:
123+
// - Binary nodes. A field could be either in the left or right side of the binary
124+
// - Self nodes. We want the object self refers to, not the self node itself
123125
var fieldNodes []ast.Node
124126
for _, foundField := range foundFields {
125127
switch fieldNode := foundField.Body.(type) {
128+
case *ast.Self:
129+
filename := fieldNode.LocRange.FileName
130+
rootNode, _, _ := vm.ImportAST("", filename)
131+
tmpStack, err := FindNodeByPosition(rootNode, fieldNode.LocRange.Begin)
132+
if err != nil {
133+
return nil, err
134+
}
135+
for !tmpStack.IsEmpty() {
136+
_, node := tmpStack.Pop()
137+
if _, ok := node.(*ast.DesugaredObject); ok {
138+
fieldNodes = append(fieldNodes, node)
139+
}
140+
}
126141
case *ast.Binary:
127142
fieldNodes = append(fieldNodes, fieldNode.Right)
128143
fieldNodes = append(fieldNodes, fieldNode.Left)
@@ -134,18 +149,11 @@ func FindRangesFromIndexList(stack *nodestack.NodeStack, indexList []string, vm
134149
for _, fieldNode := range fieldNodes {
135150
switch fieldNode := fieldNode.(type) {
136151
case *ast.Var:
137-
// If the field is a var, we need to find the value of the var
138-
// To do so, we get the stack where the var is used and search that stack for the var's definition
139-
varFileNode, _, _ := vm.ImportAST("", fieldNode.LocRange.FileName)
140-
varStack, err := FindNodeByPosition(varFileNode, fieldNode.Loc().Begin)
152+
varReference, err := findVarReference(fieldNode, vm)
141153
if err != nil {
142-
return nil, fmt.Errorf("got the following error when finding the bind for %s: %w", fieldNode.Id, err)
154+
return nil, err
143155
}
144-
bind := FindBindByIdViaStack(varStack, fieldNode.Id)
145-
if bind == nil {
146-
return nil, fmt.Errorf("could not find bind for %s", fieldNode.Id)
147-
}
148-
foundDesugaredObjects = append(foundDesugaredObjects, bind.Body.(*ast.DesugaredObject))
156+
foundDesugaredObjects = append(foundDesugaredObjects, varReference.(*ast.DesugaredObject))
149157
case *ast.DesugaredObject:
150158
stack = stack.Push(fieldNode)
151159
foundDesugaredObjects = append(foundDesugaredObjects, findDesugaredObjectFromStack(stack))
@@ -237,11 +245,33 @@ func findTopLevelObjects(stack *nodestack.NodeStack, vm *jsonnet.VM) []*ast.Desu
237245
stack.Push(obj.Body)
238246
}
239247
}
248+
case *ast.Var:
249+
varReference, err := findVarReference(curr, vm)
250+
if err != nil {
251+
log.WithError(err).Errorf("Error finding var reference, ignoring this node")
252+
continue
253+
}
254+
stack.Push(varReference)
240255
}
241256
}
242257
return objects
243258
}
244259

260+
// findVarReference finds the object that the variable is referencing
261+
// To do so, we get the stack where the var is used and search that stack for the var's definition
262+
func findVarReference(varNode *ast.Var, vm *jsonnet.VM) (ast.Node, error) {
263+
varFileNode, _, _ := vm.ImportAST("", varNode.LocRange.FileName)
264+
varStack, err := FindNodeByPosition(varFileNode, varNode.Loc().Begin)
265+
if err != nil {
266+
return nil, fmt.Errorf("got the following error when finding the bind for %s: %w", varNode.Id, err)
267+
}
268+
bind := FindBindByIdViaStack(varStack, varNode.Id)
269+
if bind == nil {
270+
return nil, fmt.Errorf("could not find bind for %s", varNode.Id)
271+
}
272+
return bind.Body, nil
273+
}
274+
245275
func findLhsDesugaredObject(stack *nodestack.NodeStack) (*ast.DesugaredObject, error) {
246276
for !stack.IsEmpty() {
247277
_, curr := stack.Pop()

pkg/server/definition_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,38 @@ func TestDefinition(t *testing.T) {
690690
},
691691
}},
692692
},
693+
{
694+
name: "goto deeply nested imported attribute",
695+
filename: "testdata/goto-import-nested-main.jsonnet",
696+
position: protocol.Position{Line: 6, Character: 14},
697+
results: []definitionResult{{
698+
targetFilename: "testdata/goto-import-nested-obj.libsonnet",
699+
targetRange: protocol.Range{
700+
Start: protocol.Position{Line: 2, Character: 2},
701+
End: protocol.Position{Line: 2, Character: 26},
702+
},
703+
targetSelectionRange: protocol.Range{
704+
Start: protocol.Position{Line: 2, Character: 2},
705+
End: protocol.Position{Line: 2, Character: 15},
706+
},
707+
}},
708+
},
709+
{
710+
name: "goto deeply nested imported attribute through self",
711+
filename: "testdata/goto-import-nested-main.jsonnet",
712+
position: protocol.Position{Line: 7, Character: 27},
713+
results: []definitionResult{{
714+
targetFilename: "testdata/goto-import-nested-obj.libsonnet",
715+
targetRange: protocol.Range{
716+
Start: protocol.Position{Line: 2, Character: 2},
717+
End: protocol.Position{Line: 2, Character: 26},
718+
},
719+
targetSelectionRange: protocol.Range{
720+
Start: protocol.Position{Line: 2, Character: 2},
721+
End: protocol.Position{Line: 2, Character: 15},
722+
},
723+
}},
724+
},
693725
}
694726
for _, tc := range testCases {
695727
t.Run(tc.name, func(t *testing.T) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
local imported = import 'goto-import-nested3.libsonnet';
2+
local obj = imported.api.v1.obj;
3+
4+
{
5+
my_obj:
6+
obj.new('test') +
7+
obj.withAttribute('hello') +
8+
obj.nestedSelf.withAttribute('hello'),
9+
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
new(name):: {},
3+
withAttribute(attr):: {},
4+
nestedSelf:: self,
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
api:: {
3+
v1:: {
4+
obj:: import 'goto-import-nested-obj.libsonnet',
5+
},
6+
},
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
local base = import 'goto-import-nested1.libsonnet';
2+
3+
base {
4+
api+:: {
5+
v1+:: {
6+
other_obj+:: {},
7+
},
8+
},
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
(import 'goto-import-nested2.libsonnet')
2+
+ {
3+
local this = self,
4+
_config+:: {
5+
some: true,
6+
attributes: this.util,
7+
},
8+
9+
util+:: {
10+
// other stuff
11+
},
12+
}

0 commit comments

Comments
 (0)