From 3a9b369b43bc2759b3bf5258caf9b31631c8a20a Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Tue, 4 May 2021 08:33:39 -0400 Subject: [PATCH] views/json: Fix diag crash with invalid highlight Some diagnostic sources (I'm looking at you, HCL) fail to set the end of the subject range. This is a bug in those code paths, but we can ensure that we generate valid JSON diagnostics by checking for it here. By doing so before the range normalization, we ensure that we generate a unit width highlight whenever possible, so that at least something useful is displayed. --- command/views/json/diagnostic.go | 6 +++ command/views/json/diagnostic_test.go | 43 +++++++++++++++++++ ...ror-with-unset-highlight-end-position.json | 26 +++++++++++ 3 files changed, 75 insertions(+) create mode 100644 command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json diff --git a/command/views/json/diagnostic.go b/command/views/json/diagnostic.go index 12a8d2730..1290e6bb5 100644 --- a/command/views/json/diagnostic.go +++ b/command/views/json/diagnostic.go @@ -133,6 +133,12 @@ func NewDiagnostic(diag tfdiags.Diagnostic, sources map[string][]byte) *Diagnost // We'll borrow HCL's range implementation here, because it has some // handy features to help us produce a nice source code snippet. highlightRange := sourceRefs.Subject.ToHCL() + + // Some diagnostic sources fail to set the end of the subject range. + if highlightRange.End == (hcl.Pos{}) { + highlightRange.End = highlightRange.Start + } + snippetRange := highlightRange if sourceRefs.Context != nil { snippetRange = sourceRefs.Context.ToHCL() diff --git a/command/views/json/diagnostic_test.go b/command/views/json/diagnostic_test.go index 8308b18a6..a11d815e2 100644 --- a/command/views/json/diagnostic_test.go +++ b/command/views/json/diagnostic_test.go @@ -246,6 +246,44 @@ func TestNewDiagnostic(t *testing.T) { }, }, }, + "error with unset highlight end position": { + &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "There is no end", + Detail: "But there is a beginning", + Subject: &hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 1, Column: 16, Byte: 15}, + End: hcl.Pos{Line: 0, Column: 0, Byte: 0}, + }, + }, + &Diagnostic{ + Severity: "error", + Summary: "There is no end", + Detail: "But there is a beginning", + Range: &DiagnosticRange{ + Filename: "test.tf", + Start: Pos{ + Line: 1, + Column: 16, + Byte: 15, + }, + End: Pos{ + Line: 1, + Column: 17, + Byte: 16, + }, + }, + Snippet: &DiagnosticSnippet{ + Context: strPtr(`resource "test_resource" "test"`), + Code: `resource "test_resource" "test" {`, + StartLine: 1, + HighlightStartOffset: 15, + HighlightEndOffset: 16, + Values: []DiagnosticExpressionValue{}, + }, + }, + }, "error with source code subject and known expression": { &hcl.Diagnostic{ Severity: hcl.DiagError, @@ -698,6 +736,11 @@ func TestNewDiagnostic(t *testing.T) { "diagnostic", fmt.Sprintf("%s.json", strings.ReplaceAll(name, " ", "-")), ) + + // Generate golden reference by uncommenting the next two lines: + // gotBytes = append(gotBytes, '\n') + // os.WriteFile(filename, gotBytes, 0644) + wantFile, err := os.Open(filename) if err != nil { t.Fatalf("failed to open golden file: %s", err) diff --git a/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json b/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json new file mode 100644 index 000000000..1f7351f09 --- /dev/null +++ b/command/views/json/testdata/diagnostic/error-with-unset-highlight-end-position.json @@ -0,0 +1,26 @@ +{ + "severity": "error", + "summary": "There is no end", + "detail": "But there is a beginning", + "range": { + "filename": "test.tf", + "start": { + "line": 1, + "column": 16, + "byte": 15 + }, + "end": { + "line": 1, + "column": 17, + "byte": 16 + } + }, + "snippet": { + "context": "resource \"test_resource\" \"test\"", + "code": "resource \"test_resource\" \"test\" {", + "start_line": 1, + "highlight_start_offset": 15, + "highlight_end_offset": 16, + "values": [] + } +}