Skip to content

Commit e68e5f2

Browse files
authored
Refactor semanticTokensInFile to use collected origins (#156)
* Refactor semanticTokensInFile to use collected origins * Add todo about refactoring idea * Add negative hover and semantic token tests
1 parent ece2f1f commit e68e5f2

File tree

4 files changed

+346
-5
lines changed

4 files changed

+346
-5
lines changed

decoder/hover_expressions_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,30 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) {
15991599
},
16001600
nil,
16011601
},
1602+
{
1603+
"matching target but missing collected origin",
1604+
map[string]*schema.AttributeSchema{
1605+
"attr": {
1606+
Expr: schema.ExprConstraints{
1607+
schema.TraversalExpr{OfType: cty.String},
1608+
},
1609+
},
1610+
},
1611+
reference.Targets{
1612+
{
1613+
Addr: lang.Address{
1614+
lang.RootStep{Name: "var"},
1615+
lang.AttrStep{Name: "blah"},
1616+
},
1617+
Type: cty.String,
1618+
},
1619+
},
1620+
reference.Origins{},
1621+
`attr = var.blah`,
1622+
hcl.Pos{Line: 1, Column: 10, Byte: 9},
1623+
nil,
1624+
&reference.NoTargetFound{},
1625+
},
16021626
}
16031627

16041628
for i, tc := range testCases {

decoder/semantic_tokens.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ func (d *PathDecoder) SemanticTokensInFile(ctx context.Context, filename string)
3131

3232
tokens := d.tokensForBody(ctx, body, d.pathCtx.Schema, []lang.SemanticTokenModifier{})
3333

34+
// TODO decouple semantic tokens for valid references from AST walking
35+
// instead of matching targets and origins when encountering a traversal expression,
36+
// we can do this way earlier by comparing pathCtx.ReferenceTargets and
37+
// d.pathCtx.ReferenceOrigins, to build a list of tokens.
38+
// Be sure to sort them afterward!
39+
3440
sort.Slice(tokens, func(i, j int) bool {
3541
return tokens[i].Range.Start.Byte < tokens[j].Range.Start.Byte
3642
})
@@ -206,16 +212,28 @@ func (d *PathDecoder) tokensForExpression(ctx context.Context, expr hclsyntax.Ex
206212
return tokens
207213
}
208214

209-
tes, ok := constraints.TraversalExprs()
210-
if ok && d.pathCtx.ReferenceTargets != nil {
215+
_, ok = constraints.TraversalExprs()
216+
if ok && d.pathCtx.ReferenceTargets != nil && d.pathCtx.ReferenceOrigins != nil {
211217
traversal := eType.AsTraversal()
212218

213-
origin, err := reference.TraversalToLocalOrigin(traversal, tes)
214-
if err != nil {
219+
origins, ok := d.pathCtx.ReferenceOrigins.AtPos(traversal.SourceRange().Filename, traversal.SourceRange().Start)
220+
if !ok {
215221
return tokens
216222
}
217223

218-
_, targetFound := d.pathCtx.ReferenceTargets.Match(origin)
224+
targetFound := false
225+
for _, origin := range origins {
226+
matchableOrigin, ok := origin.(reference.MatchableOrigin)
227+
if !ok {
228+
continue
229+
}
230+
_, ok = d.pathCtx.ReferenceTargets.Match(matchableOrigin)
231+
if ok {
232+
targetFound = true
233+
break
234+
}
235+
}
236+
219237
if !targetFound {
220238
return tokens
221239
}

decoder/semantic_tokens_expr_test.go

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,7 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
14731473
name string
14741474
attrSchema map[string]*schema.AttributeSchema
14751475
refs reference.Targets
1476+
origins reference.Origins
14761477
cfg string
14771478
expectedTokens []lang.SemanticToken
14781479
}{
@@ -1486,6 +1487,27 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
14861487
},
14871488
},
14881489
reference.Targets{},
1490+
reference.Origins{
1491+
reference.LocalOrigin{
1492+
Addr: lang.Address{
1493+
lang.RootStep{Name: "var"},
1494+
lang.AttrStep{Name: "blah"},
1495+
},
1496+
Range: hcl.Range{
1497+
Filename: "test.tf",
1498+
Start: hcl.Pos{
1499+
Line: 1,
1500+
Column: 7,
1501+
Byte: 6,
1502+
},
1503+
End: hcl.Pos{
1504+
Line: 1,
1505+
Column: 15,
1506+
Byte: 14,
1507+
},
1508+
},
1509+
},
1510+
},
14891511
`attr = var.blah
14901512
`,
14911513
[]lang.SemanticToken{
@@ -1526,6 +1548,32 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
15261548
Type: cty.Bool,
15271549
},
15281550
},
1551+
reference.Origins{
1552+
reference.LocalOrigin{
1553+
Addr: lang.Address{
1554+
lang.RootStep{Name: "var"},
1555+
lang.AttrStep{Name: "blah"},
1556+
},
1557+
Range: hcl.Range{
1558+
Filename: "test.tf",
1559+
Start: hcl.Pos{
1560+
Line: 1,
1561+
Column: 7,
1562+
Byte: 6,
1563+
},
1564+
End: hcl.Pos{
1565+
Line: 1,
1566+
Column: 15,
1567+
Byte: 14,
1568+
},
1569+
},
1570+
Constraints: reference.OriginConstraints{
1571+
reference.OriginConstraint{
1572+
OfType: cty.String,
1573+
},
1574+
},
1575+
},
1576+
},
15291577
`attr = var.blah
15301578
`,
15311579
[]lang.SemanticToken{
@@ -1566,6 +1614,32 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
15661614
Type: cty.String,
15671615
},
15681616
},
1617+
reference.Origins{
1618+
reference.LocalOrigin{
1619+
Addr: lang.Address{
1620+
lang.RootStep{Name: "var"},
1621+
lang.AttrStep{Name: "blah"},
1622+
},
1623+
Range: hcl.Range{
1624+
Filename: "test.tf",
1625+
Start: hcl.Pos{
1626+
Line: 1,
1627+
Column: 7,
1628+
Byte: 6,
1629+
},
1630+
End: hcl.Pos{
1631+
Line: 1,
1632+
Column: 15,
1633+
Byte: 14,
1634+
},
1635+
},
1636+
Constraints: reference.OriginConstraints{
1637+
reference.OriginConstraint{
1638+
OfType: cty.String,
1639+
},
1640+
},
1641+
},
1642+
},
15691643
`attr = var.blah
15701644
`,
15711645
[]lang.SemanticToken{
@@ -1640,6 +1714,32 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
16401714
ScopeId: lang.ScopeId("foo"),
16411715
},
16421716
},
1717+
reference.Origins{
1718+
reference.LocalOrigin{
1719+
Addr: lang.Address{
1720+
lang.RootStep{Name: "var"},
1721+
lang.AttrStep{Name: "blah"},
1722+
},
1723+
Range: hcl.Range{
1724+
Filename: "test.tf",
1725+
Start: hcl.Pos{
1726+
Line: 1,
1727+
Column: 7,
1728+
Byte: 6,
1729+
},
1730+
End: hcl.Pos{
1731+
Line: 1,
1732+
Column: 15,
1733+
Byte: 14,
1734+
},
1735+
},
1736+
Constraints: reference.OriginConstraints{
1737+
reference.OriginConstraint{
1738+
OfScopeId: lang.ScopeId("foo"),
1739+
},
1740+
},
1741+
},
1742+
},
16431743
`attr = var.blah
16441744
`,
16451745
[]lang.SemanticToken{
@@ -1716,6 +1816,33 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
17161816
},
17171817
},
17181818
},
1819+
reference.Origins{
1820+
reference.LocalOrigin{
1821+
Addr: lang.Address{
1822+
lang.RootStep{Name: "var"},
1823+
lang.AttrStep{Name: "foo"},
1824+
lang.IndexStep{Key: cty.StringVal("test")},
1825+
lang.AttrStep{Name: "bar"},
1826+
lang.IndexStep{Key: cty.NumberIntVal(4)},
1827+
},
1828+
Range: hcl.Range{
1829+
Filename: "test.tf",
1830+
Start: hcl.Pos{
1831+
Line: 1,
1832+
Column: 7,
1833+
Byte: 6,
1834+
},
1835+
End: hcl.Pos{
1836+
Line: 1,
1837+
Column: 29,
1838+
Byte: 28,
1839+
},
1840+
},
1841+
Constraints: reference.OriginConstraints{
1842+
reference.OriginConstraint{},
1843+
},
1844+
},
1845+
},
17191846
`attr = var.foo["test"].bar[4]
17201847
`,
17211848
[]lang.SemanticToken{
@@ -1841,6 +1968,33 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
18411968
Type: cty.DynamicPseudoType,
18421969
},
18431970
},
1971+
reference.Origins{
1972+
reference.LocalOrigin{
1973+
Addr: lang.Address{
1974+
lang.RootStep{Name: "var"},
1975+
lang.AttrStep{Name: "foo"},
1976+
lang.AttrStep{Name: "bar"},
1977+
},
1978+
Range: hcl.Range{
1979+
Filename: "test.tf",
1980+
Start: hcl.Pos{
1981+
Line: 1,
1982+
Column: 7,
1983+
Byte: 6,
1984+
},
1985+
End: hcl.Pos{
1986+
Line: 1,
1987+
Column: 18,
1988+
Byte: 17,
1989+
},
1990+
},
1991+
Constraints: reference.OriginConstraints{
1992+
reference.OriginConstraint{
1993+
OfType: cty.String,
1994+
},
1995+
},
1996+
},
1997+
},
18441998
`attr = var.foo.bar
18451999
`,
18462000
[]lang.SemanticToken{
@@ -1914,6 +2068,47 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
19142068
},
19152069
},
19162070
},
2071+
{
2072+
"matching target but missing collected origin",
2073+
map[string]*schema.AttributeSchema{
2074+
"attr": {
2075+
Expr: schema.ExprConstraints{
2076+
schema.TraversalExpr{OfType: cty.String},
2077+
},
2078+
},
2079+
},
2080+
reference.Targets{
2081+
reference.Target{
2082+
Addr: lang.Address{
2083+
lang.RootStep{Name: "var"},
2084+
lang.AttrStep{Name: "blah"},
2085+
},
2086+
Type: cty.String,
2087+
},
2088+
},
2089+
reference.Origins{},
2090+
`attr = var.blah
2091+
`,
2092+
[]lang.SemanticToken{
2093+
{ // attr
2094+
Type: lang.TokenAttrName,
2095+
Modifiers: []lang.SemanticTokenModifier{},
2096+
Range: hcl.Range{
2097+
Filename: "test.tf",
2098+
Start: hcl.Pos{
2099+
Line: 1,
2100+
Column: 1,
2101+
Byte: 0,
2102+
},
2103+
End: hcl.Pos{
2104+
Line: 1,
2105+
Column: 5,
2106+
Byte: 4,
2107+
},
2108+
},
2109+
},
2110+
},
2111+
},
19172112
}
19182113

19192114
ctx := context.Background()
@@ -1932,6 +2127,7 @@ func TestDecoder_SemanticTokensInFile_traversalExpression(t *testing.T) {
19322127
d := testPathDecoder(t, &PathContext{
19332128
Schema: bodySchema,
19342129
ReferenceTargets: tc.refs,
2130+
ReferenceOrigins: tc.origins,
19352131
Files: map[string]*hcl.File{
19362132
"test.tf": f,
19372133
},

0 commit comments

Comments
 (0)