Skip to content

Commit

Permalink
decoder: validate required attributes more selectively
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Nov 6, 2023
1 parent 814215d commit d6a7705
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
70 changes: 70 additions & 0 deletions internal/decoder/validations/missing_required_attribute.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package validations

import (
"context"
"fmt"

"github.com/hashicorp/hcl-lang/schema"
"github.com/hashicorp/hcl-lang/schemacontext"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
)

type MissingRequiredAttribute struct{}

func (mra MissingRequiredAttribute) Visit(ctx context.Context, node hclsyntax.Node, nodeSchema schema.Schema) (context.Context, hcl.Diagnostics) {
var diags hcl.Diagnostics
if HasUnknownRequiredAttributes(ctx) {
return ctx, diags
}

switch nodeType := node.(type) {
case *hclsyntax.Block:
// Providers are excluded from the validation for the time being
// due to complexity around required attributes with dynamic defaults
// See https://github.com/hashicorp/vscode-terraform/issues/1616
nestingLvl, nestingOk := schemacontext.BlockNestingLevel(ctx)
if nodeType.Type == "provider" && (nestingOk && nestingLvl == 0) {
ctx = WithUnknownRequiredAttributes(ctx)
}
case *hclsyntax.Body:
if nodeSchema == nil {
return ctx, diags
}

bodySchema := nodeSchema.(*schema.BodySchema)
if bodySchema.Attributes == nil {
return ctx, diags
}

for name, attr := range bodySchema.Attributes {
if attr.IsRequired {
_, ok := nodeType.Attributes[name]
if !ok {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("Required attribute %q not specified", name),
Detail: fmt.Sprintf("An attribute named %q is required here", name),
Subject: nodeType.SrcRange.Ptr(),
})
}
}
}
}

return ctx, diags
}

type unknownRequiredAttrsCtxKey struct{}

func HasUnknownRequiredAttributes(ctx context.Context) bool {
_, ok := ctx.Value(unknownRequiredAttrsCtxKey{}).(bool)
return ok
}

func WithUnknownRequiredAttributes(ctx context.Context) context.Context {
return context.WithValue(ctx, unknownRequiredAttrsCtxKey{}, true)
}
3 changes: 2 additions & 1 deletion internal/decoder/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package decoder

import (
"github.com/hashicorp/hcl-lang/validator"
"github.com/hashicorp/terraform-ls/internal/decoder/validations"
)

var moduleValidators = []validator.Validator{
Expand All @@ -13,7 +14,7 @@ var moduleValidators = []validator.Validator{
validator.DeprecatedBlock{},
validator.MaxBlocks{},
validator.MinBlocks{},
validator.MissingRequiredAttribute{},
validations.MissingRequiredAttribute{},
validator.UnexpectedAttribute{},
validator.UnexpectedBlock{},
}
Expand Down

0 comments on commit d6a7705

Please sign in to comment.