From 13b9a216df603c15404216117dd20701f3e6f02f Mon Sep 17 00:00:00 2001 From: Daniel Banck Date: Thu, 10 Nov 2022 14:55:32 +0100 Subject: [PATCH] Refactor hoverAtPos to use collected origins --- decoder/hover.go | 57 +++++++------ decoder/hover_expressions_test.go | 133 ++++++++++++++++++++++++++++++ decoder/hover_test.go | 46 +++++++++++ 3 files changed, 212 insertions(+), 24 deletions(-) diff --git a/decoder/hover.go b/decoder/hover.go index 571c0cf9..d4dd1826 100644 --- a/decoder/hover.go +++ b/decoder/hover.go @@ -29,7 +29,7 @@ func (d *PathDecoder) HoverAtPos(ctx context.Context, filename string, pos hcl.P return nil, &NoSchemaError{} } - data, err := d.hoverAtPos(ctx, rootBody, d.pathCtx.Schema, pos) + data, err := d.hoverAtPos(ctx, rootBody, d.pathCtx.Schema, filename, pos) if err != nil { return nil, err } @@ -37,7 +37,7 @@ func (d *PathDecoder) HoverAtPos(ctx context.Context, filename string, pos hcl.P return data, nil } -func (d *PathDecoder) hoverAtPos(ctx context.Context, body *hclsyntax.Body, bodySchema *schema.BodySchema, pos hcl.Pos) (*lang.HoverData, error) { +func (d *PathDecoder) hoverAtPos(ctx context.Context, body *hclsyntax.Body, bodySchema *schema.BodySchema, file string, pos hcl.Pos) (*lang.HoverData, error) { if bodySchema == nil { return nil, nil } @@ -92,7 +92,7 @@ func (d *PathDecoder) hoverAtPos(ctx context.Context, body *hclsyntax.Body, body if attr.Expr.Range().ContainsPos(pos) { exprCons := ExprConstraints(aSchema.Expr) - data, err := d.hoverDataForExpr(ctx, attr.Expr, exprCons, 0, pos) + data, err := d.hoverDataForExpr(ctx, attr.Expr, exprCons, 0, file, pos) if err != nil { return nil, &PositionalError{ Filename: filename, @@ -160,7 +160,7 @@ func (d *PathDecoder) hoverAtPos(ctx context.Context, body *hclsyntax.Body, body return nil, err } - return d.hoverAtPos(ctx, block.Body, mergedSchema, pos) + return d.hoverAtPos(ctx, block.Body, mergedSchema, file, pos) } } } @@ -247,7 +247,7 @@ func (d *PathDecoder) hoverContentForBlock(bType string, schema *schema.BlockSch } } -func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, constraints ExprConstraints, nestingLvl int, pos hcl.Pos) (*lang.HoverData, error) { +func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, constraints ExprConstraints, nestingLvl int, file string, pos hcl.Pos) (*lang.HoverData, error) { switch e := expr.(type) { case *hclsyntax.ScopeTraversalExpr: kw, ok := constraints.KeywordExpr() @@ -266,7 +266,7 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, tes, ok := constraints.TraversalExprs() if ok { - content, err := d.hoverContentForTraversalExpr(e.AsTraversal(), tes) + content, err := d.hoverContentForTraversalExpr(e.AsTraversal(), tes, file, pos) if err != nil { return nil, err } @@ -293,7 +293,7 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, } case *hclsyntax.TemplateExpr: if e.IsStringLiteral() { - data, err := d.hoverDataForExpr(ctx, e.Parts[0], constraints, nestingLvl, pos) + data, err := d.hoverDataForExpr(ctx, e.Parts[0], constraints, nestingLvl, file, pos) if err != nil { return nil, err } @@ -327,7 +327,7 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, } } case *hclsyntax.TemplateWrapExpr: - data, err := d.hoverDataForExpr(ctx, e.Wrapped, constraints, nestingLvl, pos) + data, err := d.hoverDataForExpr(ctx, e.Wrapped, constraints, nestingLvl, file, pos) if err != nil { return nil, err } @@ -352,7 +352,7 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, if ok { for _, elemExpr := range e.Exprs { if elemExpr.Range().ContainsPos(pos) { - return d.hoverDataForExpr(ctx, elemExpr, ExprConstraints(se.Elem), nestingLvl, pos) + return d.hoverDataForExpr(ctx, elemExpr, ExprConstraints(se.Elem), nestingLvl, file, pos) } } content := fmt.Sprintf("_%s_", se.FriendlyName()) @@ -368,7 +368,7 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, if ok { for _, elemExpr := range e.Exprs { if elemExpr.Range().ContainsPos(pos) { - return d.hoverDataForExpr(ctx, elemExpr, ExprConstraints(le.Elem), nestingLvl, pos) + return d.hoverDataForExpr(ctx, elemExpr, ExprConstraints(le.Elem), nestingLvl, file, pos) } } content := fmt.Sprintf("_%s_", le.FriendlyName()) @@ -388,7 +388,7 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, return nil, &ConstraintMismatch{elemExpr} } ec := ExprConstraints(te.Elems[i]) - return d.hoverDataForExpr(ctx, elemExpr, ec, nestingLvl, pos) + return d.hoverDataForExpr(ctx, elemExpr, ec, nestingLvl, file, pos) } } content := fmt.Sprintf("_%s_", te.FriendlyName()) @@ -425,7 +425,7 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, case *hclsyntax.ObjectConsExpr: objExpr, ok := constraints.ObjectExpr() if ok { - return d.hoverDataForObjectExpr(ctx, e, objExpr, nestingLvl, pos) + return d.hoverDataForObjectExpr(ctx, e, objExpr, nestingLvl, file, pos) } mapExpr, ok := constraints.MapExpr() if ok { @@ -501,7 +501,7 @@ func (d *PathDecoder) hoverDataForExpr(ctx context.Context, expr hcl.Expression, return nil, fmt.Errorf("unsupported expression (%T)", expr) } -func (d *PathDecoder) hoverDataForObjectExpr(ctx context.Context, objExpr *hclsyntax.ObjectConsExpr, oe schema.ObjectExpr, nestingLvl int, pos hcl.Pos) (*lang.HoverData, error) { +func (d *PathDecoder) hoverDataForObjectExpr(ctx context.Context, objExpr *hclsyntax.ObjectConsExpr, oe schema.ObjectExpr, nestingLvl int, file string, pos hcl.Pos) (*lang.HoverData, error) { declaredAttributes := make(map[string]hclsyntax.Expression, 0) for _, item := range objExpr.Items { key, _ := item.KeyExpr.Value(nil) @@ -517,7 +517,7 @@ func (d *PathDecoder) hoverDataForObjectExpr(ctx context.Context, objExpr *hclsy } if item.ValueExpr.Range().ContainsPos(pos) { - return d.hoverDataForExpr(ctx, item.ValueExpr, ExprConstraints(attr.Expr), nestingLvl+1, pos) + return d.hoverDataForExpr(ctx, item.ValueExpr, ExprConstraints(attr.Expr), nestingLvl+1, file, pos) } itemRng := hcl.RangeBetween(item.KeyExpr.Range(), item.ValueExpr.Range()) @@ -558,7 +558,7 @@ func (d *PathDecoder) hoverDataForObjectExpr(ctx context.Context, objExpr *hclsy attrData := ec.FriendlyName() if attrExpr, ok := declaredAttributes[name]; ok { - data, err := d.hoverDataForExpr(ctx, attrExpr, ExprConstraints(ec), nestingLvl+1, pos) + data, err := d.hoverDataForExpr(ctx, attrExpr, ExprConstraints(ec), nestingLvl+1, file, pos) if err == nil && data.Content.Value != "" { attrData = data.Content.Value } @@ -625,19 +625,28 @@ func stringValFromTemplateExpr(tplExpr *hclsyntax.TemplateExpr) (cty.Value, bool return cty.StringVal(value), true } -func (d *PathDecoder) hoverContentForTraversalExpr(traversal hcl.Traversal, tes []schema.TraversalExpr) (string, error) { - origin, err := reference.TraversalToLocalOrigin(traversal, tes) - if err != nil { - return "", nil +func (d *PathDecoder) hoverContentForTraversalExpr(traversal hcl.Traversal, tes []schema.TraversalExpr, file string, pos hcl.Pos) (string, error) { + origins, ok := d.pathCtx.ReferenceOrigins.AtPos(file, pos) + if !ok { + return "", &reference.NoOriginFound{} } - targets, ok := d.pathCtx.ReferenceTargets.Match(origin) - if !ok { - return "", &reference.NoTargetFound{} + for _, origin := range origins { + matchableOrigin, ok := origin.(reference.MatchableOrigin) + if !ok { + continue + } + targets, ok := d.pathCtx.ReferenceTargets.Match(matchableOrigin) + if !ok { + // target not found + continue + } + + // TODO: Reflect additional found targets here? + return hoverContentForReferenceTarget(targets[0]) } - // TODO: Reflect additional found targets here? - return hoverContentForReferenceTarget(targets[0]) + return "", &reference.NoTargetFound{} } func hoverContentForReferenceTarget(ref reference.Target) (string, error) { diff --git a/decoder/hover_expressions_test.go b/decoder/hover_expressions_test.go index cde250ed..efea48a9 100644 --- a/decoder/hover_expressions_test.go +++ b/decoder/hover_expressions_test.go @@ -1309,6 +1309,7 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) { name string attrSchema map[string]*schema.AttributeSchema refs reference.Targets + origins reference.Origins cfg string pos hcl.Pos expectedData *lang.HoverData @@ -1324,6 +1325,32 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) { }, }, reference.Targets{}, + reference.Origins{ + reference.LocalOrigin{ + Addr: lang.Address{ + lang.RootStep{Name: "var"}, + lang.AttrStep{Name: "blah"}, + }, + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{ + Line: 1, + Column: 8, + Byte: 7, + }, + End: hcl.Pos{ + Line: 1, + Column: 16, + Byte: 15, + }, + }, + Constraints: reference.OriginConstraints{ + reference.OriginConstraint{ + OfType: cty.String, + }, + }, + }, + }, `attr = var.blah`, hcl.Pos{Line: 1, Column: 10, Byte: 9}, nil, @@ -1347,6 +1374,32 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) { Type: cty.Bool, }, }, + reference.Origins{ + reference.LocalOrigin{ + Addr: lang.Address{ + lang.RootStep{Name: "var"}, + lang.AttrStep{Name: "blah"}, + }, + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{ + Line: 1, + Column: 8, + Byte: 7, + }, + End: hcl.Pos{ + Line: 1, + Column: 16, + Byte: 15, + }, + }, + Constraints: reference.OriginConstraints{ + reference.OriginConstraint{ + OfType: cty.String, + }, + }, + }, + }, `attr = var.blah`, hcl.Pos{Line: 1, Column: 10, Byte: 9}, nil, @@ -1370,6 +1423,32 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) { Type: cty.String, }, }, + reference.Origins{ + reference.LocalOrigin{ + Addr: lang.Address{ + lang.RootStep{Name: "var"}, + lang.AttrStep{Name: "blah"}, + }, + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{ + Line: 1, + Column: 8, + Byte: 7, + }, + End: hcl.Pos{ + Line: 1, + Column: 16, + Byte: 15, + }, + }, + Constraints: reference.OriginConstraints{ + reference.OriginConstraint{ + OfType: cty.String, + }, + }, + }, + }, `attr = var.blah`, hcl.Pos{Line: 1, Column: 10, Byte: 9}, &lang.HoverData{ @@ -1408,6 +1487,33 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) { Type: cty.DynamicPseudoType, }, }, + reference.Origins{ + reference.LocalOrigin{ + Addr: lang.Address{ + lang.RootStep{Name: "var"}, + lang.AttrStep{Name: "foo"}, + lang.AttrStep{Name: "bar"}, + }, + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{ + Line: 1, + Column: 8, + Byte: 7, + }, + End: hcl.Pos{ + Line: 1, + Column: 19, + Byte: 18, + }, + }, + Constraints: reference.OriginConstraints{ + reference.OriginConstraint{ + OfType: cty.String, + }, + }, + }, + }, `attr = var.foo.bar`, hcl.Pos{Line: 1, Column: 10, Byte: 9}, &lang.HoverData{ @@ -1447,6 +1553,32 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) { Name: "special", }, }, + reference.Origins{ + reference.LocalOrigin{ + Addr: lang.Address{ + lang.RootStep{Name: "var"}, + lang.AttrStep{Name: "foo"}, + }, + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{ + Line: 1, + Column: 8, + Byte: 7, + }, + End: hcl.Pos{ + Line: 1, + Column: 15, + Byte: 14, + }, + }, + Constraints: reference.OriginConstraints{ + reference.OriginConstraint{ + OfScopeId: lang.ScopeId("foo"), + }, + }, + }, + }, `attr = var.foo`, hcl.Pos{Line: 1, Column: 10, Byte: 9}, &lang.HoverData{ @@ -1480,6 +1612,7 @@ func TestDecoder_HoverAtPos_traversalExpressions(t *testing.T) { d := testPathDecoder(t, &PathContext{ Schema: bodySchema, ReferenceTargets: tc.refs, + ReferenceOrigins: tc.origins, Files: map[string]*hcl.File{ "test.tf": f, }, diff --git a/decoder/hover_test.go b/decoder/hover_test.go index 603ae6c9..34680896 100644 --- a/decoder/hover_test.go +++ b/decoder/hover_test.go @@ -940,6 +940,7 @@ func TestDecoder_HoverAtPos_extension(t *testing.T) { name string bodySchema *schema.BodySchema RefTargets reference.Targets + origins reference.Origins config string pos hcl.Pos expectedData *lang.HoverData @@ -962,6 +963,7 @@ func TestDecoder_HoverAtPos_extension(t *testing.T) { }, }, reference.Targets{}, + reference.Origins{}, `myblock "foo" "bar" { count = 1 } @@ -1012,6 +1014,19 @@ func TestDecoder_HoverAtPos_extension(t *testing.T) { Description: lang.PlainText("The distinct index number (starting with 0) corresponding to the instance"), }, }, + reference.Origins{ + reference.LocalOrigin{ + Addr: lang.Address{ + lang.RootStep{Name: "count"}, + lang.AttrStep{Name: "index"}, + }, + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 3, Column: 11, Byte: 44}, + End: hcl.Pos{Line: 3, Column: 22, Byte: 55}, + }, + }, + }, `myblock "foo" "bar" { count = 1 foo = count.index @@ -1045,6 +1060,7 @@ func TestDecoder_HoverAtPos_extension(t *testing.T) { }, }, reference.Targets{}, + reference.Origins{}, `myblock "foo" "bar" { count = 3 } @@ -1076,6 +1092,7 @@ func TestDecoder_HoverAtPos_extension(t *testing.T) { "test.tf": f, }, ReferenceTargets: tc.RefTargets, + ReferenceOrigins: tc.origins, }) data, err := d.HoverAtPos(ctx, "test.tf", tc.pos) @@ -1094,6 +1111,7 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) { name string bodySchema *schema.BodySchema refTargets reference.Targets + origins reference.Origins config string pos hcl.Pos expectedData *lang.HoverData @@ -1116,6 +1134,7 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) { }, }, reference.Targets{}, + reference.Origins{}, `myblock "foo" "bar" { for_each = { @@ -1210,6 +1229,19 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) { // TODO: RangePtr & DefRangePtr }, }, + reference.Origins{ + reference.LocalOrigin{ + Addr: lang.Address{ + lang.RootStep{Name: "each"}, + lang.AttrStep{Name: "key"}, + }, + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 2, Column: 8, Byte: 29}, + End: hcl.Pos{Line: 2, Column: 16, Byte: 37}, + }, + }, + }, `myblock "foo" "bar" { foo = each.key for_each = { @@ -1301,6 +1333,19 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) { // TODO: RangePtr & DefRangePtr }, }, + reference.Origins{ + reference.LocalOrigin{ + Addr: lang.Address{ + lang.RootStep{Name: "each"}, + lang.AttrStep{Name: "value"}, + }, + Range: hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 2, Column: 8, Byte: 29}, + End: hcl.Pos{Line: 2, Column: 18, Byte: 39}, + }, + }, + }, `myblock "foo" "bar" { foo = each.value for_each = { @@ -1336,6 +1381,7 @@ func TestDecoder_HoverAtPos_foreach_extension(t *testing.T) { "test.tf": f, }, ReferenceTargets: tc.refTargets, + ReferenceOrigins: tc.origins, }) data, err := d.HoverAtPos(ctx, "test.tf", tc.pos)