Repository: googleapis/api-linter
Pull request #1171 (2023-06-01 20:57:54)

feat: include file path in serialized lint problems


Patch:
diff --git a/lint/problem.go b/lint/problem.go
index 000458d..cbadd22 100644
--- a/lint/problem.go
+++ b/lint/problem.go
@@ -94,7 +94,7 @@ func (p Problem) marshal() interface{} {
 	}{
 		p.Message,
 		p.Suggestion,
-		fileLocationFromPBLocation(loc),
+		fileLocationFromPBLocation(loc, p.Descriptor),
 		p.RuleID,
 		p.GetRuleURI(),
 		p.category,
@@ -120,33 +120,38 @@ type position struct {
 type fileLocation struct {
 	Start position `json:"start_position" yaml:"start_position"`
 	End   position `json:"end_position" yaml:"end_position"`
+	Path  string   `json:"path" yaml:"path"`
 }
 
 // fileLocationFromPBLocation returns a new fileLocation object based on a
 // protocol buffer SourceCodeInfo_Location
-func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location) fileLocation {
+func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location, d desc.Descriptor) fileLocation {
 	// Spans are guaranteed by protobuf to have either three or four ints.
 	span := []int32{0, 0, 1}
 	if l != nil {
 		span = l.Span
 	}
 
+	var fl fileLocation
+	if d != nil {
+		fl = fileLocation{Path: d.GetFile().GetName()}
+	}
+
 	// If `span` has four ints; they correspond to
 	// [start line, start column, end line, end column].
 	//
 	// We add one because spans are zero-indexed, but not to the end column
 	// because we want the ending position to be inclusive and not exclusive.
 	if len(span) == 4 {
-		return fileLocation{
-			Start: position{
-				Line:   int(span[0]) + 1,
-				Column: int(span[1]) + 1,
-			},
-			End: position{
-				Line:   int(span[2]) + 1,
-				Column: int(span[3]),
-			},
+		fl.Start = position{
+			Line:   int(span[0]) + 1,
+			Column: int(span[1]) + 1,
+		}
+		fl.End = position{
+			Line:   int(span[2]) + 1,
+			Column: int(span[3]),
 		}
+		return fl
 	}
 
 	// Okay, `span` has three ints; they correspond to
@@ -154,14 +159,13 @@ func fileLocationFromPBLocation(l *dpb.SourceCodeInfo_Location) fileLocation {
 	//
 	// We add one because spans are zero-indexed, but not to the end column
 	// because we want the ending position to be inclusive and not exclusive.
-	return fileLocation{
-		Start: position{
-			Line:   int(span[0]) + 1,
-			Column: int(span[1]) + 1,
-		},
-		End: position{
-			Line:   int(span[0]) + 1,
-			Column: int(span[2]),
-		},
+	fl.Start = position{
+		Line:   int(span[0]) + 1,
+		Column: int(span[1]) + 1,
+	}
+	fl.End = position{
+		Line:   int(span[0]) + 1,
+		Column: int(span[2]),
 	}
+	return fl
 }


Test patch:
diff --git a/lint/problem_test.go b/lint/problem_test.go
index e1f3dd2..96424c5 100644
--- a/lint/problem_test.go
+++ b/lint/problem_test.go
@@ -84,7 +84,10 @@ func TestProblemYAML(t *testing.T) {
 }
 
 func TestProblemDescriptor(t *testing.T) {
-	m, err := builder.NewMessage("Foo").Build()
+	mb := builder.NewMessage("Foo")
+	builder.NewFile("foo.proto").AddMessage(mb)
+
+	m, err := mb.Build()
 	if err != nil {
 		t.Fatalf("%v", err)
 	}
@@ -107,6 +110,7 @@ func TestProblemDescriptor(t *testing.T) {
 		{"ColumnNumberStart", `column_number: 1`},
 		{"ColumnNumberEnd", `column_number: 79`},
 		{"RuleID", `rule_id: core::0131`},
+		{"Path", `path: foo.proto`},
 	}
 	for _, test := range tests {
 		t.Run(test.testName, func(t *testing.T) {