cmd/protoc-gen-go: add test for "import option" directive
See https://protobuf.dev/editions/overview/#import-option for context.
Change-Id: Iea73299fdd828301fe451ca3c6b9234e8dd9acf3
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/699715
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mike Kruskal <mkruskal@google.com>
Reviewed-by: Lasse Folger <lassefolger@google.com>
diff --git a/cmd/protoc-gen-go/importoption_test.go b/cmd/protoc-gen-go/importoption_test.go
new file mode 100644
index 0000000..5492c03
--- /dev/null
+++ b/cmd/protoc-gen-go/importoption_test.go
@@ -0,0 +1,56 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ importoptionpb "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option"
+ "google.golang.org/protobuf/encoding/protowire"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/types/descriptorpb"
+
+ // Ensure the custom option is linked into this test binary.
+ // NB: import_option_unlinked is not linked into this test binary.
+ importoptioncustompb "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option_custom"
+)
+
+func TestImportOption(t *testing.T) {
+ var nilMessage *importoptionpb.TestMessage
+ md := nilMessage.ProtoReflect().Descriptor()
+
+ // Options from import option that are linked in should be available through
+ // the extension API as usual.
+ {
+ fd := md.Fields().ByName("hello")
+ fopts := fd.Options().(*descriptorpb.FieldOptions)
+ if !proto.HasExtension(fopts, importoptioncustompb.E_FieldOption) {
+ t.Errorf("FieldDescriptor(hello) does not have FieldOption extension set")
+ }
+ }
+
+ // Options from import option that are not linked in should be in unknown bytes.
+ {
+ fd := md.Fields().ByName("world")
+ fopts := fd.Options().(*descriptorpb.FieldOptions)
+ unknown := fopts.ProtoReflect().GetUnknown()
+ var fields []protowire.Number
+ b := unknown
+ for len(b) > 0 {
+ num, _, n := protowire.ConsumeField(b)
+ if n < 0 {
+ t.Errorf("FieldDescriptor(world) contains invalid wire format: ConsumeField = %d", n)
+ }
+ fields = append(fields, num)
+ b = b[n:]
+ }
+ want := []protowire.Number{504589222}
+ if diff := cmp.Diff(want, fields); diff != "" {
+ t.Errorf("FieldDescriptor(world) unknown bytes contain unexpected fields: diff (-want +got):\n%s", diff)
+ }
+ }
+
+}
diff --git a/cmd/protoc-gen-go/testdata/gen_test.go b/cmd/protoc-gen-go/testdata/gen_test.go
index 234019b..6eb5905 100644
--- a/cmd/protoc-gen-go/testdata/gen_test.go
+++ b/cmd/protoc-gen-go/testdata/gen_test.go
@@ -15,6 +15,9 @@
_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/extensions/extra"
_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/extensions/proto3"
_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/fieldnames"
+ _ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option"
+ _ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option_custom"
+ _ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option_unlinked"
_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_public"
_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_public/sub"
_ "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_public/sub2"
diff --git a/cmd/protoc-gen-go/testdata/import_option/import_option.pb.go b/cmd/protoc-gen-go/testdata/import_option/import_option.pb.go
new file mode 100644
index 0000000..428683e
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/import_option/import_option.pb.go
@@ -0,0 +1,172 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: cmd/protoc-gen-go/testdata/import_option/import_option.proto
+
+package import_option
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ _ "google.golang.org/protobuf/types/descriptorpb"
+ reflect "reflect"
+ unsafe "unsafe"
+)
+
+type TestMessage struct {
+ state protoimpl.MessageState `protogen:"opaque.v1"`
+ xxx_hidden_Hello *string `protobuf:"bytes,1,opt,name=hello"`
+ xxx_hidden_World *string `protobuf:"bytes,2,opt,name=world"`
+ XXX_raceDetectHookData protoimpl.RaceDetectHookData
+ XXX_presence [1]uint32
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *TestMessage) Reset() {
+ *x = TestMessage{}
+ mi := &file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TestMessage) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TestMessage) ProtoMessage() {}
+
+func (x *TestMessage) ProtoReflect() protoreflect.Message {
+ mi := &file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+func (x *TestMessage) GetHello() string {
+ if x != nil {
+ if x.xxx_hidden_Hello != nil {
+ return *x.xxx_hidden_Hello
+ }
+ return ""
+ }
+ return ""
+}
+
+func (x *TestMessage) GetWorld() string {
+ if x != nil {
+ if x.xxx_hidden_World != nil {
+ return *x.xxx_hidden_World
+ }
+ return ""
+ }
+ return ""
+}
+
+func (x *TestMessage) SetHello(v string) {
+ x.xxx_hidden_Hello = &v
+ protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 2)
+}
+
+func (x *TestMessage) SetWorld(v string) {
+ x.xxx_hidden_World = &v
+ protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 2)
+}
+
+func (x *TestMessage) HasHello() bool {
+ if x == nil {
+ return false
+ }
+ return protoimpl.X.Present(&(x.XXX_presence[0]), 0)
+}
+
+func (x *TestMessage) HasWorld() bool {
+ if x == nil {
+ return false
+ }
+ return protoimpl.X.Present(&(x.XXX_presence[0]), 1)
+}
+
+func (x *TestMessage) ClearHello() {
+ protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
+ x.xxx_hidden_Hello = nil
+}
+
+func (x *TestMessage) ClearWorld() {
+ protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 1)
+ x.xxx_hidden_World = nil
+}
+
+type TestMessage_builder struct {
+ _ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+ Hello *string
+ World *string
+}
+
+func (b0 TestMessage_builder) Build() *TestMessage {
+ m0 := &TestMessage{}
+ b, x := &b0, m0
+ _, _ = b, x
+ if b.Hello != nil {
+ protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 2)
+ x.xxx_hidden_Hello = b.Hello
+ }
+ if b.World != nil {
+ protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 2)
+ x.xxx_hidden_World = b.World
+ }
+ return m0
+}
+
+var File_cmd_protoc_gen_go_testdata_import_option_import_option_proto protoreflect.FileDescriptor
+
+const file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_rawDesc = "" +
+ "\n" +
+ "<cmd/protoc-gen-go/testdata/import_option/import_option.proto\x12\x10testimportoption\x1a google/protobuf/descriptor.proto\"M\n" +
+ "\vTestMessage\x12\x1e\n" +
+ "\x05hello\x18\x01 \x01(\tB\b\xaa\xba\xed\x84\x0f\x02\b\x17R\x05hello\x12\x1e\n" +
+ "\x05world\x18\x02 \x01(\tB\b\xb2\xba\xed\x84\x0f\x02\b\x17R\x05worldBEZCgoogle.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_optionb\beditionsp\xe9\azJcmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.protozNcmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.proto"
+
+var file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_goTypes = []any{
+ (*TestMessage)(nil), // 0: testimportoption.TestMessage
+}
+var file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_depIdxs = []int32{
+ 0, // [0:0] is the sub-list for method output_type
+ 0, // [0:0] is the sub-list for method input_type
+ 0, // [0:0] is the sub-list for extension type_name
+ 0, // [0:0] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_init() }
+func file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_init() {
+ if File_cmd_protoc_gen_go_testdata_import_option_import_option_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_rawDesc), len(file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 1,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_goTypes,
+ DependencyIndexes: file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_depIdxs,
+ MessageInfos: file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_msgTypes,
+ }.Build()
+ File_cmd_protoc_gen_go_testdata_import_option_import_option_proto = out.File
+ file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_goTypes = nil
+ file_cmd_protoc_gen_go_testdata_import_option_import_option_proto_depIdxs = nil
+}
diff --git a/cmd/protoc-gen-go/testdata/import_option/import_option.proto b/cmd/protoc-gen-go/testdata/import_option/import_option.proto
new file mode 100644
index 0000000..d5d25bc
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/import_option/import_option.proto
@@ -0,0 +1,18 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+edition = "2024";
+
+package testimportoption;
+
+import "google/protobuf/descriptor.proto";
+import option "cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.proto";
+import option "cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.proto";
+
+option go_package = "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option";
+
+message TestMessage {
+ string hello = 1 [(testimportoption_custom.field_option) = { plain_field: 23 }];
+ string world = 2 [(testimportoption_unlinked.field_option) = { plain_field: 23 }];
+}
diff --git a/cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.pb.go b/cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.pb.go
new file mode 100644
index 0000000..b5feec8
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.pb.go
@@ -0,0 +1,158 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.proto
+
+package import_option_custom
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ descriptorpb "google.golang.org/protobuf/types/descriptorpb"
+ reflect "reflect"
+ unsafe "unsafe"
+)
+
+type OptionsMessage struct {
+ state protoimpl.MessageState `protogen:"opaque.v1"`
+ xxx_hidden_PlainField int32 `protobuf:"varint,1,opt,name=plain_field,json=plainField"`
+ XXX_raceDetectHookData protoimpl.RaceDetectHookData
+ XXX_presence [1]uint32
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *OptionsMessage) Reset() {
+ *x = OptionsMessage{}
+ mi := &file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *OptionsMessage) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OptionsMessage) ProtoMessage() {}
+
+func (x *OptionsMessage) ProtoReflect() protoreflect.Message {
+ mi := &file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+func (x *OptionsMessage) GetPlainField() int32 {
+ if x != nil {
+ return x.xxx_hidden_PlainField
+ }
+ return 0
+}
+
+func (x *OptionsMessage) SetPlainField(v int32) {
+ x.xxx_hidden_PlainField = v
+ protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 1)
+}
+
+func (x *OptionsMessage) HasPlainField() bool {
+ if x == nil {
+ return false
+ }
+ return protoimpl.X.Present(&(x.XXX_presence[0]), 0)
+}
+
+func (x *OptionsMessage) ClearPlainField() {
+ protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
+ x.xxx_hidden_PlainField = 0
+}
+
+type OptionsMessage_builder struct {
+ _ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+ PlainField *int32
+}
+
+func (b0 OptionsMessage_builder) Build() *OptionsMessage {
+ m0 := &OptionsMessage{}
+ b, x := &b0, m0
+ _, _ = b, x
+ if b.PlainField != nil {
+ protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 1)
+ x.xxx_hidden_PlainField = *b.PlainField
+ }
+ return m0
+}
+
+var file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_extTypes = []protoimpl.ExtensionInfo{
+ {
+ ExtendedType: (*descriptorpb.FieldOptions)(nil),
+ ExtensionType: (*OptionsMessage)(nil),
+ Field: 504589221,
+ Name: "testimportoption_custom.field_option",
+ Tag: "bytes,504589221,opt,name=field_option",
+ Filename: "cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.proto",
+ },
+}
+
+// Extension fields to descriptorpb.FieldOptions.
+var (
+ // optional testimportoption_custom.OptionsMessage field_option = 504589221;
+ E_FieldOption = &file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_extTypes[0]
+)
+
+var File_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto protoreflect.FileDescriptor
+
+const file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_rawDesc = "" +
+ "\n" +
+ "Jcmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.proto\x12\x17testimportoption_custom\x1a google/protobuf/descriptor.proto\"1\n" +
+ "\x0eOptionsMessage\x12\x1f\n" +
+ "\vplain_field\x18\x01 \x01(\x05R\n" +
+ "plainField:m\n" +
+ "\ffield_option\x12\x1d.google.protobuf.FieldOptions\x18\xa5\xd7\xcd\xf0\x01 \x01(\v2'.testimportoption_custom.OptionsMessageR\vfieldOptionBLZJgoogle.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option_customb\beditionsp\xe9\a"
+
+var file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_goTypes = []any{
+ (*OptionsMessage)(nil), // 0: testimportoption_custom.OptionsMessage
+ (*descriptorpb.FieldOptions)(nil), // 1: google.protobuf.FieldOptions
+}
+var file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_depIdxs = []int32{
+ 1, // 0: testimportoption_custom.field_option:extendee -> google.protobuf.FieldOptions
+ 0, // 1: testimportoption_custom.field_option:type_name -> testimportoption_custom.OptionsMessage
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 1, // [1:2] is the sub-list for extension type_name
+ 0, // [0:1] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_init() }
+func file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_init() {
+ if File_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_rawDesc), len(file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 1,
+ NumExtensions: 1,
+ NumServices: 0,
+ },
+ GoTypes: file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_goTypes,
+ DependencyIndexes: file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_depIdxs,
+ MessageInfos: file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_msgTypes,
+ ExtensionInfos: file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_extTypes,
+ }.Build()
+ File_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto = out.File
+ file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_goTypes = nil
+ file_cmd_protoc_gen_go_testdata_import_option_custom_import_option_custom_proto_depIdxs = nil
+}
diff --git a/cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.proto b/cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.proto
new file mode 100644
index 0000000..6befc41
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/import_option_custom/import_option_custom.proto
@@ -0,0 +1,19 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+edition = "2024";
+
+package testimportoption_custom;
+
+import "google/protobuf/descriptor.proto";
+
+option go_package = "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option_custom";
+
+extend google.protobuf.FieldOptions {
+ OptionsMessage field_option = 504589221;
+}
+
+message OptionsMessage {
+ int32 plain_field = 1;
+}
diff --git a/cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.pb.go b/cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.pb.go
new file mode 100644
index 0000000..8d6ee67
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.pb.go
@@ -0,0 +1,160 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.proto
+
+package import_option_unlinked
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ descriptorpb "google.golang.org/protobuf/types/descriptorpb"
+ reflect "reflect"
+ unsafe "unsafe"
+)
+
+type OptionsMessage struct {
+ state protoimpl.MessageState `protogen:"opaque.v1"`
+ xxx_hidden_PlainField int32 `protobuf:"varint,1,opt,name=plain_field,json=plainField"`
+ XXX_raceDetectHookData protoimpl.RaceDetectHookData
+ XXX_presence [1]uint32
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
+}
+
+func (x *OptionsMessage) Reset() {
+ *x = OptionsMessage{}
+ mi := &file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *OptionsMessage) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*OptionsMessage) ProtoMessage() {}
+
+func (x *OptionsMessage) ProtoReflect() protoreflect.Message {
+ mi := &file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+func (x *OptionsMessage) GetPlainField() int32 {
+ if x != nil {
+ return x.xxx_hidden_PlainField
+ }
+ return 0
+}
+
+func (x *OptionsMessage) SetPlainField(v int32) {
+ x.xxx_hidden_PlainField = v
+ protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 1)
+}
+
+func (x *OptionsMessage) HasPlainField() bool {
+ if x == nil {
+ return false
+ }
+ return protoimpl.X.Present(&(x.XXX_presence[0]), 0)
+}
+
+func (x *OptionsMessage) ClearPlainField() {
+ protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
+ x.xxx_hidden_PlainField = 0
+}
+
+type OptionsMessage_builder struct {
+ _ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
+
+ PlainField *int32
+}
+
+func (b0 OptionsMessage_builder) Build() *OptionsMessage {
+ m0 := &OptionsMessage{}
+ b, x := &b0, m0
+ _, _ = b, x
+ if b.PlainField != nil {
+ protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 1)
+ x.xxx_hidden_PlainField = *b.PlainField
+ }
+ return m0
+}
+
+var file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_extTypes = []protoimpl.ExtensionInfo{
+ {
+ ExtendedType: (*descriptorpb.FieldOptions)(nil),
+ ExtensionType: (*OptionsMessage)(nil),
+ Field: 504589222,
+ Name: "testimportoption_unlinked.field_option",
+ Tag: "bytes,504589222,opt,name=field_option",
+ Filename: "cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.proto",
+ },
+}
+
+// Extension fields to descriptorpb.FieldOptions.
+var (
+ // optional testimportoption_unlinked.OptionsMessage field_option = 504589222;
+ E_FieldOption = &file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_extTypes[0]
+)
+
+var File_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto protoreflect.FileDescriptor
+
+const file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_rawDesc = "" +
+ "\n" +
+ "Ncmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.proto\x12\x19testimportoption_unlinked\x1a google/protobuf/descriptor.proto\"1\n" +
+ "\x0eOptionsMessage\x12\x1f\n" +
+ "\vplain_field\x18\x01 \x01(\x05R\n" +
+ "plainField:o\n" +
+ "\ffield_option\x12\x1d.google.protobuf.FieldOptions\x18\xa6\xd7\xcd\xf0\x01 \x01(\v2).testimportoption_unlinked.OptionsMessageR\vfieldOptionBNZLgoogle.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option_unlinkedb\beditionsp\xe9\a"
+
+var file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_goTypes = []any{
+ (*OptionsMessage)(nil), // 0: testimportoption_unlinked.OptionsMessage
+ (*descriptorpb.FieldOptions)(nil), // 1: google.protobuf.FieldOptions
+}
+var file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_depIdxs = []int32{
+ 1, // 0: testimportoption_unlinked.field_option:extendee -> google.protobuf.FieldOptions
+ 0, // 1: testimportoption_unlinked.field_option:type_name -> testimportoption_unlinked.OptionsMessage
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 1, // [1:2] is the sub-list for extension type_name
+ 0, // [0:1] is the sub-list for extension extendee
+ 0, // [0:0] is the sub-list for field type_name
+}
+
+func init() {
+ file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_init()
+}
+func file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_init() {
+ if File_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: unsafe.Slice(unsafe.StringData(file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_rawDesc), len(file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_rawDesc)),
+ NumEnums: 0,
+ NumMessages: 1,
+ NumExtensions: 1,
+ NumServices: 0,
+ },
+ GoTypes: file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_goTypes,
+ DependencyIndexes: file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_depIdxs,
+ MessageInfos: file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_msgTypes,
+ ExtensionInfos: file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_extTypes,
+ }.Build()
+ File_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto = out.File
+ file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_goTypes = nil
+ file_cmd_protoc_gen_go_testdata_import_option_unlinked_import_option_unlinked_proto_depIdxs = nil
+}
diff --git a/cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.proto b/cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.proto
new file mode 100644
index 0000000..8f85f3d
--- /dev/null
+++ b/cmd/protoc-gen-go/testdata/import_option_unlinked/import_option_unlinked.proto
@@ -0,0 +1,19 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+edition = "2024";
+
+package testimportoption_unlinked;
+
+import "google/protobuf/descriptor.proto";
+
+option go_package = "google.golang.org/protobuf/cmd/protoc-gen-go/testdata/import_option_unlinked";
+
+extend google.protobuf.FieldOptions {
+ OptionsMessage field_option = 504589222;
+}
+
+message OptionsMessage {
+ int32 plain_field = 1;
+}