From 35a59aee6e9bc355ef03238e238b185f33ad211b Mon Sep 17 00:00:00 2001 From: Marat Reymers Date: Tue, 28 Oct 2025 14:02:08 +0100 Subject: [PATCH 1/7] Find nearest valid source location by path Closes bufbuild/bufplugin-go#20 --- check/response_writer.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/check/response_writer.go b/check/response_writer.go index 40bb7bf..be80d31 100644 --- a/check/response_writer.go +++ b/check/response_writer.go @@ -339,8 +339,11 @@ func getFileLocationForAddAnnotationOptions( if !ok { return nil, fmt.Errorf("cannot add annotation for unknown file: %q", fileName) } - if len(path) > 0 { + for ; len(path) > 0; path = path[:len(path)-1] { sourceLocation = fileDescriptor.ProtoreflectFileDescriptor().SourceLocations().ByPath(path) + if len(sourceLocation.Path) > 0 { + break + } } return descriptor.NewFileLocation(fileDescriptor, sourceLocation), nil } From 350685dd53f67bb44daaf4e3deb46bfcafdc9323 Mon Sep 17 00:00:00 2001 From: Marat Reymers Date: Wed, 29 Oct 2025 12:58:58 +0100 Subject: [PATCH 2/7] Add test --- check/response_writer_test.go | 132 ++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 check/response_writer_test.go diff --git a/check/response_writer_test.go b/check/response_writer_test.go new file mode 100644 index 0000000..594fe41 --- /dev/null +++ b/check/response_writer_test.go @@ -0,0 +1,132 @@ +package check_test + +import ( + "context" + "os" + "path/filepath" + "testing" + + "buf.build/go/bufplugin/check" + "buf.build/go/bufplugin/check/checktest" + "buf.build/go/bufplugin/check/checkutil" + "buf.build/go/bufplugin/descriptor" + "github.com/stretchr/testify/require" +) + +const protoFile = ` +syntax = "proto3"; +import "google/protobuf/descriptor.proto"; +extend google.protobuf.MessageOptions { + X x = 5000; +} +message X { + string y = 1; +} +message Foo { + option deprecated = true; + option (x).y = "z"; +} +` + +// TestIssue20 checks that an annotation by source path points to the nearest parent if the original one is missing. +func TestIssue20(t *testing.T) { + t.Parallel() + dir := t.TempDir() + const fileName = "file.proto" + const ruleID = "TEST_MISSING_SOURCE_LOCATION" + require.NoError(t, os.WriteFile(filepath.Join(dir, fileName), []byte(protoFile), 0666)) + checktest.CheckTest{ + Request: &checktest.RequestSpec{ + Files: &checktest.ProtoFileSpec{ + DirPaths: []string{dir}, + FilePaths: []string{fileName}, + }, + RuleIDs: []string{ruleID}, + }, + Spec: &check.Spec{ + Rules: []*check.RuleSpec{{ + ID: ruleID, + Purpose: "Purpose.", + Type: check.RuleTypeLint, + Handler: checkutil.NewFileRuleHandler( + func( + _ context.Context, + writer check.ResponseWriter, + _ check.Request, + file descriptor.FileDescriptor, + ) error { + foo := file.ProtoreflectFileDescriptor().Messages().ByName("Foo") + fooPath := file.ProtoreflectFileDescriptor().SourceLocations().ByDescriptor(foo).Path + writer.AddAnnotation( + check.WithMessage("Annotation for message"), + check.WithFileNameAndSourcePath( + fileName, + fooPath, + ), + ) + writer.AddAnnotation( + check.WithMessage("Annotation for option (x).y"), + check.WithFileNameAndSourcePath( + fileName, + append( + fooPath, + 7, // google.protobuf.DescriptorProto.options + 5000, // x + 1, // X.y + ), + ), + ) + writer.AddAnnotation( + check.WithMessage("Annotation for option (x) points to first message option"), + check.WithFileNameAndSourcePath( + fileName, + append( + fooPath, + 7, // google.protobuf.DescriptorProto.options + 5000, // x + ), + ), + ) + return nil + }, + checkutil.WithoutImports(), + ), + }}, + }, + ExpectedAnnotations: []checktest.ExpectedAnnotation{ + { + RuleID: ruleID, + Message: "Annotation for message", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: fileName, + StartLine: 9, + StartColumn: 0, + EndLine: 12, + EndColumn: 1, + }, + }, + { + RuleID: ruleID, + Message: "Annotation for option (x) points to first message option", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: fileName, + StartLine: 10, + StartColumn: 2, + EndLine: 10, + EndColumn: 27, + }, + }, + { + RuleID: ruleID, + Message: "Annotation for option (x).y", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: fileName, + StartLine: 11, + StartColumn: 2, + EndLine: 11, + EndColumn: 21, + }, + }, + }, + }.Run(t) +} From d7ddf8473b72ccae6a476cf6d69f93878272af45 Mon Sep 17 00:00:00 2001 From: Marat Reimers Date: Mon, 27 Apr 2026 22:52:38 +0200 Subject: [PATCH 3/7] Add license header --- check/response_writer_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/check/response_writer_test.go b/check/response_writer_test.go index 594fe41..f2d4d1f 100644 --- a/check/response_writer_test.go +++ b/check/response_writer_test.go @@ -1,3 +1,17 @@ +// Copyright 2024-2025 Buf Technologies, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package check_test import ( From b7afe8079a1dfddee95700d7be160823c976ce89 Mon Sep 17 00:00:00 2001 From: Marat Reimers Date: Mon, 27 Apr 2026 23:00:46 +0200 Subject: [PATCH 4/7] Extract proto file to testdata --- check/response_writer_test.go | 42 +++++-------------- check/testdata/source_location_fallback.proto | 16 +++++++ 2 files changed, 27 insertions(+), 31 deletions(-) create mode 100644 check/testdata/source_location_fallback.proto diff --git a/check/response_writer_test.go b/check/response_writer_test.go index f2d4d1f..e1da335 100644 --- a/check/response_writer_test.go +++ b/check/response_writer_test.go @@ -16,43 +16,23 @@ package check_test import ( "context" - "os" - "path/filepath" "testing" "buf.build/go/bufplugin/check" "buf.build/go/bufplugin/check/checktest" "buf.build/go/bufplugin/check/checkutil" "buf.build/go/bufplugin/descriptor" - "github.com/stretchr/testify/require" ) -const protoFile = ` -syntax = "proto3"; -import "google/protobuf/descriptor.proto"; -extend google.protobuf.MessageOptions { - X x = 5000; -} -message X { - string y = 1; -} -message Foo { - option deprecated = true; - option (x).y = "z"; -} -` - -// TestIssue20 checks that an annotation by source path points to the nearest parent if the original one is missing. -func TestIssue20(t *testing.T) { +// TestSourceLocationFallback checks that an annotation by source path points to the nearest parent if the original one is missing. +func TestSourceLocationFallback(t *testing.T) { t.Parallel() - dir := t.TempDir() - const fileName = "file.proto" - const ruleID = "TEST_MISSING_SOURCE_LOCATION" - require.NoError(t, os.WriteFile(filepath.Join(dir, fileName), []byte(protoFile), 0666)) + const fileName = "source_location_fallback.proto" + const ruleID = "TEST_SOURCE_LOCATION_FALLBACK" checktest.CheckTest{ Request: &checktest.RequestSpec{ Files: &checktest.ProtoFileSpec{ - DirPaths: []string{dir}, + DirPaths: []string{"testdata"}, FilePaths: []string{fileName}, }, RuleIDs: []string{ruleID}, @@ -113,9 +93,9 @@ func TestIssue20(t *testing.T) { Message: "Annotation for message", FileLocation: &checktest.ExpectedFileLocation{ FileName: fileName, - StartLine: 9, + StartLine: 12, StartColumn: 0, - EndLine: 12, + EndLine: 15, EndColumn: 1, }, }, @@ -124,9 +104,9 @@ func TestIssue20(t *testing.T) { Message: "Annotation for option (x) points to first message option", FileLocation: &checktest.ExpectedFileLocation{ FileName: fileName, - StartLine: 10, + StartLine: 13, StartColumn: 2, - EndLine: 10, + EndLine: 13, EndColumn: 27, }, }, @@ -135,9 +115,9 @@ func TestIssue20(t *testing.T) { Message: "Annotation for option (x).y", FileLocation: &checktest.ExpectedFileLocation{ FileName: fileName, - StartLine: 11, + StartLine: 14, StartColumn: 2, - EndLine: 11, + EndLine: 14, EndColumn: 21, }, }, diff --git a/check/testdata/source_location_fallback.proto b/check/testdata/source_location_fallback.proto new file mode 100644 index 0000000..1c3b4b7 --- /dev/null +++ b/check/testdata/source_location_fallback.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.MessageOptions { + X x = 5000; +} + +message X { + string y = 1; +} + +message Foo { + option deprecated = true; + option (x).y = "z"; +} From e40269a8f71282806d25d0f37bdc8daeb82abc37 Mon Sep 17 00:00:00 2001 From: Marat Reimers Date: Tue, 28 Apr 2026 01:06:40 +0200 Subject: [PATCH 5/7] Improve algorithm by finding the best match --- check/response_writer.go | 42 ++++- check/response_writer_test.go | 170 +++++++++++++----- check/testdata/source_location_fallback.proto | 22 ++- 3 files changed, 180 insertions(+), 54 deletions(-) diff --git a/check/response_writer.go b/check/response_writer.go index be80d31..28575db 100644 --- a/check/response_writer.go +++ b/check/response_writer.go @@ -334,18 +334,46 @@ func getFileLocationForAddAnnotationOptions( return nil, nil } if fileName != "" { - var sourceLocation protoreflect.SourceLocation fileDescriptor, ok := fileNameToFileDescriptor[fileName] if !ok { return nil, fmt.Errorf("cannot add annotation for unknown file: %q", fileName) } - for ; len(path) > 0; path = path[:len(path)-1] { - sourceLocation = fileDescriptor.ProtoreflectFileDescriptor().SourceLocations().ByPath(path) - if len(sourceLocation.Path) > 0 { - break - } - } + sourceLocation := nearestLocation(fileDescriptor.ProtoreflectFileDescriptor().SourceLocations(), path) return descriptor.NewFileLocation(fileDescriptor, sourceLocation), nil } return nil, nil } + +// nearestLocation returns the best available source location for path, preferring: +// 1. an exact source location +// 2. the first descendant source location +// 3. the nearest ancestor source location +func nearestLocation(locations protoreflect.SourceLocations, path protoreflect.SourcePath) protoreflect.SourceLocation { + if loc := locations.ByPath(path); len(loc.Path) > 0 { + return loc // exact match + } + var bestLoc protoreflect.SourceLocation + var bestCommon int + for i := range locations.Len() { + loc := locations.Get(i) + common := commonLength(loc.Path, path) + if common == len(path) { + return loc // first descendant + } + if common >= bestCommon { + bestLoc = loc + bestCommon = common + } + } + return bestLoc // nearest ancestor +} + +func commonLength(a, b protoreflect.SourcePath) int { + n := min(len(a), len(b)) + for i := range n { + if a[i] != b[i] { + return i + } + } + return n +} diff --git a/check/response_writer_test.go b/check/response_writer_test.go index e1da335..85786a5 100644 --- a/check/response_writer_test.go +++ b/check/response_writer_test.go @@ -24,16 +24,16 @@ import ( "buf.build/go/bufplugin/descriptor" ) -// TestSourceLocationFallback checks that an annotation by source path points to the nearest parent if the original one is missing. +// TestSourceLocationFallback checks that an annotation by source path points to the nearest location if the original one is missing. func TestSourceLocationFallback(t *testing.T) { t.Parallel() - const fileName = "source_location_fallback.proto" + const file = "source_location_fallback.proto" const ruleID = "TEST_SOURCE_LOCATION_FALLBACK" checktest.CheckTest{ Request: &checktest.RequestSpec{ Files: &checktest.ProtoFileSpec{ DirPaths: []string{"testdata"}, - FilePaths: []string{fileName}, + FilePaths: []string{file}, }, RuleIDs: []string{ruleID}, }, @@ -47,39 +47,54 @@ func TestSourceLocationFallback(t *testing.T) { _ context.Context, writer check.ResponseWriter, _ check.Request, - file descriptor.FileDescriptor, + fd descriptor.FileDescriptor, ) error { - foo := file.ProtoreflectFileDescriptor().Messages().ByName("Foo") - fooPath := file.ProtoreflectFileDescriptor().SourceLocations().ByDescriptor(foo).Path + const options = 7 // google.protobuf.DescriptorProto.options + const a = 5000 // a + const ab = 1 // A.b + const ac = 2 // A.c + const acd = 3 // C.d + + fooMsg := fd.ProtoreflectFileDescriptor().Messages().ByName("Foo") + foo := fd.ProtoreflectFileDescriptor().SourceLocations().ByDescriptor(fooMsg).Path + writer.AddAnnotation( + check.WithMessage("Foo - message - right location"), + check.WithFileNameAndSourcePath(file, foo), + ) + writer.AddAnnotation( + check.WithMessage("Foo - option (a) - fallback to (a).b"), + check.WithFileNameAndSourcePath(file, append(foo, options, a)), + ) + writer.AddAnnotation( + check.WithMessage("Foo - option (a).b - right location"), + check.WithFileNameAndSourcePath(file, append(foo, options, a, ab)), + ) + writer.AddAnnotation( + check.WithMessage("Foo - option (a).c - fallback to (a).c.d"), + check.WithFileNameAndSourcePath(file, append(foo, options, a, ac)), + ) + writer.AddAnnotation( + check.WithMessage("Foo - option (a).c.d - right location"), + check.WithFileNameAndSourcePath(file, append(foo, options, a, ac, acd)), + ) + + barMsg := fd.ProtoreflectFileDescriptor().Messages().ByName("Bar") + bar := fd.ProtoreflectFileDescriptor().SourceLocations().ByDescriptor(barMsg).Path + writer.AddAnnotation( + check.WithMessage("Bar - option (a) - fallback to (a).c"), + check.WithFileNameAndSourcePath(file, append(bar, options, a)), + ) writer.AddAnnotation( - check.WithMessage("Annotation for message"), - check.WithFileNameAndSourcePath( - fileName, - fooPath, - ), + check.WithMessage("Bar - option (a).c - right location"), + check.WithFileNameAndSourcePath(file, append(bar, options, a, ac)), ) writer.AddAnnotation( - check.WithMessage("Annotation for option (x).y"), - check.WithFileNameAndSourcePath( - fileName, - append( - fooPath, - 7, // google.protobuf.DescriptorProto.options - 5000, // x - 1, // X.y - ), - ), + check.WithMessage("Bar - option (a).c.d - right location"), + check.WithFileNameAndSourcePath(file, append(bar, options, a, ac, acd)), ) writer.AddAnnotation( - check.WithMessage("Annotation for option (x) points to first message option"), - check.WithFileNameAndSourcePath( - fileName, - append( - fooPath, - 7, // google.protobuf.DescriptorProto.options - 5000, // x - ), - ), + check.WithMessage("Bar - option (a).b - right location"), + check.WithFileNameAndSourcePath(file, append(bar, options, a, ab)), ) return nil }, @@ -88,36 +103,105 @@ func TestSourceLocationFallback(t *testing.T) { }}, }, ExpectedAnnotations: []checktest.ExpectedAnnotation{ + // Foo { RuleID: ruleID, - Message: "Annotation for message", + Message: "Foo - message - right location", FileLocation: &checktest.ExpectedFileLocation{ - FileName: fileName, - StartLine: 12, + FileName: file, + StartLine: 17, StartColumn: 0, - EndLine: 15, + EndLine: 21, EndColumn: 1, }, }, { RuleID: ruleID, - Message: "Annotation for option (x) points to first message option", + Message: "Foo - option (a) - fallback to (a).b", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: file, + StartLine: 19, + StartColumn: 2, + EndLine: 19, + EndColumn: 21, + }, + }, + { + RuleID: ruleID, + Message: "Foo - option (a).b - right location", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: file, + StartLine: 19, + StartColumn: 2, + EndLine: 19, + EndColumn: 21, + }, + }, + { + RuleID: ruleID, + Message: "Foo - option (a).c - fallback to (a).c.d", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: file, + StartLine: 20, + StartColumn: 2, + EndLine: 20, + EndColumn: 23, + }, + }, + { + RuleID: ruleID, + Message: "Foo - option (a).c.d - right location", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: file, + StartLine: 20, + StartColumn: 2, + EndLine: 20, + EndColumn: 23, + }, + }, + + // Bar + { + RuleID: ruleID, + Message: "Bar - option (a) - fallback to (a).c", FileLocation: &checktest.ExpectedFileLocation{ - FileName: fileName, - StartLine: 13, + FileName: file, + StartLine: 25, StartColumn: 2, - EndLine: 13, - EndColumn: 27, + EndLine: 27, + EndColumn: 4, + }, + }, + { + RuleID: ruleID, + Message: "Bar - option (a).c - right location", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: file, + StartLine: 25, + StartColumn: 2, + EndLine: 27, + EndColumn: 4, + }, + }, + { + RuleID: ruleID, + Message: "Bar - option (a).c.d - right location", + FileLocation: &checktest.ExpectedFileLocation{ + FileName: file, + StartLine: 26, + StartColumn: 4, + EndLine: 26, + EndColumn: 10, }, }, { RuleID: ruleID, - Message: "Annotation for option (x).y", + Message: "Bar - option (a).b - right location", FileLocation: &checktest.ExpectedFileLocation{ - FileName: fileName, - StartLine: 14, + FileName: file, + StartLine: 28, StartColumn: 2, - EndLine: 14, + EndLine: 28, EndColumn: 21, }, }, diff --git a/check/testdata/source_location_fallback.proto b/check/testdata/source_location_fallback.proto index 1c3b4b7..24c5eb9 100644 --- a/check/testdata/source_location_fallback.proto +++ b/check/testdata/source_location_fallback.proto @@ -3,14 +3,28 @@ syntax = "proto3"; import "google/protobuf/descriptor.proto"; extend google.protobuf.MessageOptions { - X x = 5000; + A a = 5000; } -message X { - string y = 1; +message A { + string b = 1; + C c = 2; +} + +message C { + string d = 3; } message Foo { option deprecated = true; - option (x).y = "z"; + option (a).b = "x"; + option (a).c.d = "y"; +} + +message Bar { + option deprecated = true; + option (a).c = { + d: "y", + }; + option (a).b = "x"; } From 822ed93e1184272ac4d534d6d2e7352d8d0996cd Mon Sep 17 00:00:00 2001 From: Marat Reimers Date: Wed, 29 Apr 2026 00:49:35 +0200 Subject: [PATCH 6/7] Fix test --- .../example/cmd/buf-plugin-syntax-specified/main_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/check/internal/example/cmd/buf-plugin-syntax-specified/main_test.go b/check/internal/example/cmd/buf-plugin-syntax-specified/main_test.go index 77f7f85..1ba5372 100644 --- a/check/internal/example/cmd/buf-plugin-syntax-specified/main_test.go +++ b/check/internal/example/cmd/buf-plugin-syntax-specified/main_test.go @@ -54,7 +54,8 @@ func TestSimpleFailure(t *testing.T) { { RuleID: syntaxSpecifiedRuleID, FileLocation: &checktest.ExpectedFileLocation{ - FileName: "simple.proto", + FileName: "simple.proto", + EndColumn: 15, }, }, }, From ef7de4bc23d085ce66d2f5da13c3377f865c2cf5 Mon Sep 17 00:00:00 2001 From: Marat Reimers Date: Wed, 29 Apr 2026 01:42:25 +0200 Subject: [PATCH 7/7] Fix linter --- check/response_writer.go | 12 ++++++------ check/response_writer_test.go | 36 +++++++++++++++++------------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/check/response_writer.go b/check/response_writer.go index 28575db..4b2f47b 100644 --- a/check/response_writer.go +++ b/check/response_writer.go @@ -345,9 +345,9 @@ func getFileLocationForAddAnnotationOptions( } // nearestLocation returns the best available source location for path, preferring: -// 1. an exact source location -// 2. the first descendant source location -// 3. the nearest ancestor source location +// 1. an exact source location +// 2. the first descendant source location +// 3. the nearest ancestor source location func nearestLocation(locations protoreflect.SourceLocations, path protoreflect.SourcePath) protoreflect.SourceLocation { if loc := locations.ByPath(path); len(loc.Path) > 0 { return loc // exact match @@ -369,11 +369,11 @@ func nearestLocation(locations protoreflect.SourceLocations, path protoreflect.S } func commonLength(a, b protoreflect.SourcePath) int { - n := min(len(a), len(b)) - for i := range n { + minLen := min(len(a), len(b)) + for i := range minLen { if a[i] != b[i] { return i } } - return n + return minLen } diff --git a/check/response_writer_test.go b/check/response_writer_test.go index 85786a5..a91cda6 100644 --- a/check/response_writer_test.go +++ b/check/response_writer_test.go @@ -47,54 +47,54 @@ func TestSourceLocationFallback(t *testing.T) { _ context.Context, writer check.ResponseWriter, _ check.Request, - fd descriptor.FileDescriptor, + fileDescriptor descriptor.FileDescriptor, ) error { - const options = 7 // google.protobuf.DescriptorProto.options - const a = 5000 // a - const ab = 1 // A.b - const ac = 2 // A.c - const acd = 3 // C.d + const optsNum = 7 // google.protobuf.DescriptorProto.options + const aNum = 5000 // a + const abNum = 1 // A.b + const acNum = 2 // A.c + const acdNum = 3 // C.d - fooMsg := fd.ProtoreflectFileDescriptor().Messages().ByName("Foo") - foo := fd.ProtoreflectFileDescriptor().SourceLocations().ByDescriptor(fooMsg).Path + fooMsg := fileDescriptor.ProtoreflectFileDescriptor().Messages().ByName("Foo") + foo := fileDescriptor.ProtoreflectFileDescriptor().SourceLocations().ByDescriptor(fooMsg).Path writer.AddAnnotation( check.WithMessage("Foo - message - right location"), check.WithFileNameAndSourcePath(file, foo), ) writer.AddAnnotation( check.WithMessage("Foo - option (a) - fallback to (a).b"), - check.WithFileNameAndSourcePath(file, append(foo, options, a)), + check.WithFileNameAndSourcePath(file, append(foo, optsNum, aNum)), ) writer.AddAnnotation( check.WithMessage("Foo - option (a).b - right location"), - check.WithFileNameAndSourcePath(file, append(foo, options, a, ab)), + check.WithFileNameAndSourcePath(file, append(foo, optsNum, aNum, abNum)), ) writer.AddAnnotation( check.WithMessage("Foo - option (a).c - fallback to (a).c.d"), - check.WithFileNameAndSourcePath(file, append(foo, options, a, ac)), + check.WithFileNameAndSourcePath(file, append(foo, optsNum, aNum, acNum)), ) writer.AddAnnotation( check.WithMessage("Foo - option (a).c.d - right location"), - check.WithFileNameAndSourcePath(file, append(foo, options, a, ac, acd)), + check.WithFileNameAndSourcePath(file, append(foo, optsNum, aNum, acNum, acdNum)), ) - barMsg := fd.ProtoreflectFileDescriptor().Messages().ByName("Bar") - bar := fd.ProtoreflectFileDescriptor().SourceLocations().ByDescriptor(barMsg).Path + barMsg := fileDescriptor.ProtoreflectFileDescriptor().Messages().ByName("Bar") + bar := fileDescriptor.ProtoreflectFileDescriptor().SourceLocations().ByDescriptor(barMsg).Path writer.AddAnnotation( check.WithMessage("Bar - option (a) - fallback to (a).c"), - check.WithFileNameAndSourcePath(file, append(bar, options, a)), + check.WithFileNameAndSourcePath(file, append(bar, optsNum, aNum)), ) writer.AddAnnotation( check.WithMessage("Bar - option (a).c - right location"), - check.WithFileNameAndSourcePath(file, append(bar, options, a, ac)), + check.WithFileNameAndSourcePath(file, append(bar, optsNum, aNum, acNum)), ) writer.AddAnnotation( check.WithMessage("Bar - option (a).c.d - right location"), - check.WithFileNameAndSourcePath(file, append(bar, options, a, ac, acd)), + check.WithFileNameAndSourcePath(file, append(bar, optsNum, aNum, acNum, acdNum)), ) writer.AddAnnotation( check.WithMessage("Bar - option (a).b - right location"), - check.WithFileNameAndSourcePath(file, append(bar, options, a, ab)), + check.WithFileNameAndSourcePath(file, append(bar, optsNum, aNum, abNum)), ) return nil },