Skip to content

Commit 67d42e4

Browse files
committed
feat: add line and column to error and warnings
The line and column is taken from the first label with the same level as the report. For error reports is the first error label, and for warning reports is the first warning label.
1 parent d4234e6 commit 67d42e4

File tree

3 files changed

+44
-12
lines changed

3 files changed

+44
-12
lines changed

go/compiler.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ type CompileError struct {
138138
Code string `json:"code"`
139139
// Error title (e.g: "unknown identifier `foo`").
140140
Title string `json:"title"`
141+
// Error line number. This is the line number of the first error label.
142+
Line int `json:"line"`
143+
// Error column number. This is the column number of the first error label.
144+
Column int `json:"column"`
141145
// Each of the labels in the error report.
142146
Labels []Label `json:"labels,omitempty"`
143147
// Each of the footers in the error report.
@@ -148,10 +152,14 @@ type CompileError struct {
148152

149153
// Warning represents each of the warnings returned by [Compiler.Warnings].
150154
type Warning struct {
151-
// Error code (e.g: "slow_pattern").
155+
// Warning code (e.g: "slow_pattern").
152156
Code string `json:"code"`
153-
// Error title (e.g: "slow pattern").
157+
// Warning title (e.g: "slow pattern").
154158
Title string `json:"title"`
159+
// Warning line number. This is the line number of the first warning label.
160+
Line int `json:"line"`
161+
// Warning column number. This is the column number of the first warning label.
162+
Column int `json:"column"`
155163
// Each of the labels in the warning report.
156164
Labels []Label `json:"labels,omitempty"`
157165
// Each of the footers in the warning report.

go/compiler_test.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,10 @@ func TestErrors(t *testing.T) {
163163

164164
assert.Equal(t, []Warning{
165165
{
166-
Code: "invariant_expr",
167-
Title: "invariant boolean expression",
166+
Code: "invariant_expr",
167+
Title: "invariant boolean expression",
168+
Line: 1,
169+
Column: 26,
168170
Labels: []Label{
169171
{
170172
Level: "warning",
@@ -193,8 +195,10 @@ func TestErrors(t *testing.T) {
193195
c.AddSource("rule test_2 { condition: foo }", WithOrigin("test.yar"))
194196
assert.Equal(t, []CompileError{
195197
{
196-
Code: "E009",
197-
Title: "unknown identifier `foo`",
198+
Code: "E009",
199+
Title: "unknown identifier `foo`",
200+
Line: 1,
201+
Column: 26,
198202
Labels: []Label{
199203
{
200204
Level: "error",
@@ -293,8 +297,10 @@ func TestWarnings(t *testing.T) {
293297

294298
assert.Equal(t, []Warning{
295299
{
296-
Code: "consecutive_jumps",
297-
Title: "consecutive jumps in hex pattern `$a`",
300+
Code: "consecutive_jumps",
301+
Title: "consecutive jumps in hex pattern `$a`",
302+
Line: 1,
303+
Column: 31,
298304
Labels: []Label{
299305
{
300306
Level: "warning",
@@ -314,8 +320,10 @@ func TestWarnings(t *testing.T) {
314320
|`,
315321
},
316322
{
317-
Code: "slow_pattern",
318-
Title: "slow pattern",
323+
Code: "slow_pattern",
324+
Title: "slow pattern",
325+
Line: 1,
326+
Column: 22,
319327
Labels: []Label{
320328
{
321329
Level: "warning",

lib/src/compiler/report.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,27 @@ impl Serialize for Report {
149149
where
150150
S: Serializer,
151151
{
152+
let labels = self.labels().collect::<Vec<_>>();
153+
let footers = &self.footers().collect::<Vec<_>>();
154+
152155
let mut s = serializer.serialize_struct("report", 4)?;
156+
153157
s.serialize_field("code", &self.code)?;
154158
s.serialize_field("title", &self.title)?;
155-
s.serialize_field("labels", &self.labels().collect::<Vec<_>>())?;
156-
s.serialize_field("footers", &self.footers().collect::<Vec<_>>())?;
159+
160+
// Find the first label with the same level as the report itself.
161+
// The report's line and column will be the line and column of
162+
// that label.
163+
if let Some(label) = labels
164+
.iter()
165+
.find(|label| label.level == level_as_text(self.level))
166+
{
167+
s.serialize_field("line", &label.line)?;
168+
s.serialize_field("column", &label.column)?;
169+
}
170+
171+
s.serialize_field("labels", &labels)?;
172+
s.serialize_field("footers", &footers)?;
157173
s.serialize_field("text", &self.to_string())?;
158174
s.end()
159175
}

0 commit comments

Comments
 (0)