protostar 0.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +60 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +647 -0
  5. data/THIRD_PARTY_NOTICES.md +61 -0
  6. data/exe/protoc-gen-protostar +7 -0
  7. data/exe/protostar +7 -0
  8. data/lib/protostar/builder/generator.rb +71 -0
  9. data/lib/protostar/builder/sink.rb +35 -0
  10. data/lib/protostar/builder.rb +965 -0
  11. data/lib/protostar/cli.rb +267 -0
  12. data/lib/protostar/codec/decode_generator.rb +199 -0
  13. data/lib/protostar/codec/decoder.rb +296 -0
  14. data/lib/protostar/codec/encode_generator.rb +224 -0
  15. data/lib/protostar/codec/encoder.rb +121 -0
  16. data/lib/protostar/codec/sizer.rb +91 -0
  17. data/lib/protostar/codec.rb +15 -0
  18. data/lib/protostar/compiler/ast.rb +193 -0
  19. data/lib/protostar/compiler/emitters/descriptor_set.rb +57 -0
  20. data/lib/protostar/compiler/emitters/google_ruby.rb +103 -0
  21. data/lib/protostar/compiler/emitters/grpc.rb +175 -0
  22. data/lib/protostar/compiler/emitters/protostar_rbs.rb +252 -0
  23. data/lib/protostar/compiler/emitters/rbs.rb +394 -0
  24. data/lib/protostar/compiler/emitters/ruby.rb +503 -0
  25. data/lib/protostar/compiler/emitters.rb +268 -0
  26. data/lib/protostar/compiler/include/LICENSE +32 -0
  27. data/lib/protostar/compiler/include/google/protobuf/any.proto +106 -0
  28. data/lib/protostar/compiler/include/google/protobuf/api.proto +229 -0
  29. data/lib/protostar/compiler/include/google/protobuf/compiler/plugin.proto +180 -0
  30. data/lib/protostar/compiler/include/google/protobuf/cpp_features.proto +87 -0
  31. data/lib/protostar/compiler/include/google/protobuf/descriptor.proto +1532 -0
  32. data/lib/protostar/compiler/include/google/protobuf/duration.proto +115 -0
  33. data/lib/protostar/compiler/include/google/protobuf/empty.proto +51 -0
  34. data/lib/protostar/compiler/include/google/protobuf/field_mask.proto +243 -0
  35. data/lib/protostar/compiler/include/google/protobuf/java_features.proto +132 -0
  36. data/lib/protostar/compiler/include/google/protobuf/source_context.proto +48 -0
  37. data/lib/protostar/compiler/include/google/protobuf/struct.proto +111 -0
  38. data/lib/protostar/compiler/include/google/protobuf/timestamp.proto +145 -0
  39. data/lib/protostar/compiler/include/google/protobuf/type.proto +217 -0
  40. data/lib/protostar/compiler/include/google/protobuf/wrappers.proto +157 -0
  41. data/lib/protostar/compiler/lexer.rb +659 -0
  42. data/lib/protostar/compiler/linker.rb +894 -0
  43. data/lib/protostar/compiler/option_interpreter.rb +363 -0
  44. data/lib/protostar/compiler/parser.rb +1696 -0
  45. data/lib/protostar/compiler/retention.rb +104 -0
  46. data/lib/protostar/compiler/run.rb +184 -0
  47. data/lib/protostar/compiler/source_info.rb +161 -0
  48. data/lib/protostar/compiler/symbol_table.rb +223 -0
  49. data/lib/protostar/compiler/text_format.rb +340 -0
  50. data/lib/protostar/compiler/validator.rb +944 -0
  51. data/lib/protostar/compiler.rb +304 -0
  52. data/lib/protostar/diagnostics/codes.rb +1307 -0
  53. data/lib/protostar/diagnostics/formats.rb +64 -0
  54. data/lib/protostar/diagnostics/renderer.rb +240 -0
  55. data/lib/protostar/diagnostics/source.rb +153 -0
  56. data/lib/protostar/diagnostics.rb +117 -0
  57. data/lib/protostar/dsl.rb +367 -0
  58. data/lib/protostar/enum.rb +70 -0
  59. data/lib/protostar/errors.rb +23 -0
  60. data/lib/protostar/google/protobuf/any_pb.rb +90 -0
  61. data/lib/protostar/google/protobuf/api_pb.rb +199 -0
  62. data/lib/protostar/google/protobuf/compiler/plugin_pb.rb +168 -0
  63. data/lib/protostar/google/protobuf/descriptor_pb.rb +1239 -0
  64. data/lib/protostar/google/protobuf/duration_pb.rb +99 -0
  65. data/lib/protostar/google/protobuf/empty_pb.rb +36 -0
  66. data/lib/protostar/google/protobuf/field_mask_pb.rb +228 -0
  67. data/lib/protostar/google/protobuf/source_context_pb.rb +33 -0
  68. data/lib/protostar/google/protobuf/struct_pb.rb +91 -0
  69. data/lib/protostar/google/protobuf/timestamp_pb.rb +129 -0
  70. data/lib/protostar/google/protobuf/type_pb.rb +202 -0
  71. data/lib/protostar/google/protobuf/wrappers_pb.rb +125 -0
  72. data/lib/protostar/google_protobuf_shim.rb +24 -0
  73. data/lib/protostar/json/encoder.rb +340 -0
  74. data/lib/protostar/json/errors.rb +34 -0
  75. data/lib/protostar/json/parser.rb +437 -0
  76. data/lib/protostar/json/path.rb +39 -0
  77. data/lib/protostar/json.rb +95 -0
  78. data/lib/protostar/lint/command.rb +197 -0
  79. data/lib/protostar/lint/config.rb +98 -0
  80. data/lib/protostar/lint/context.rb +126 -0
  81. data/lib/protostar/lint/directives.rb +56 -0
  82. data/lib/protostar/lint/fixer.rb +165 -0
  83. data/lib/protostar/lint/naming.rb +54 -0
  84. data/lib/protostar/lint/rule.rb +120 -0
  85. data/lib/protostar/lint/rules/comment_enum.rb +31 -0
  86. data/lib/protostar/lint/rules/comment_enum_value.rb +32 -0
  87. data/lib/protostar/lint/rules/comment_field.rb +33 -0
  88. data/lib/protostar/lint/rules/comment_message.rb +31 -0
  89. data/lib/protostar/lint/rules/comment_rpc.rb +31 -0
  90. data/lib/protostar/lint/rules/comment_service.rb +31 -0
  91. data/lib/protostar/lint/rules/edition_recommended.rb +31 -0
  92. data/lib/protostar/lint/rules/enum_first_value_zero.rb +34 -0
  93. data/lib/protostar/lint/rules/enum_pascal_case.rb +25 -0
  94. data/lib/protostar/lint/rules/enum_value_prefix.rb +38 -0
  95. data/lib/protostar/lint/rules/enum_value_upper_snake_case.rb +28 -0
  96. data/lib/protostar/lint/rules/enum_zero_value_suffix.rb +41 -0
  97. data/lib/protostar/lint/rules/field_lower_snake_case.rb +34 -0
  98. data/lib/protostar/lint/rules/field_not_required.rb +39 -0
  99. data/lib/protostar/lint/rules/field_number_reuse_risk.rb +45 -0
  100. data/lib/protostar/lint/rules/field_numbers_hot_range.rb +44 -0
  101. data/lib/protostar/lint/rules/file_lower_snake_case.rb +27 -0
  102. data/lib/protostar/lint/rules/import_no_public.rb +29 -0
  103. data/lib/protostar/lint/rules/import_no_weak.rb +28 -0
  104. data/lib/protostar/lint/rules/import_used.rb +33 -0
  105. data/lib/protostar/lint/rules/message_pascal_case.rb +27 -0
  106. data/lib/protostar/lint/rules/no_deprecated_features.rb +50 -0
  107. data/lib/protostar/lint/rules/no_groups.rb +34 -0
  108. data/lib/protostar/lint/rules/oneof_lower_snake_case.rb +27 -0
  109. data/lib/protostar/lint/rules/package_defined.rb +28 -0
  110. data/lib/protostar/lint/rules/package_directory_match.rb +33 -0
  111. data/lib/protostar/lint/rules/package_lower_snake_case.rb +28 -0
  112. data/lib/protostar/lint/rules/package_same_directory.rb +39 -0
  113. data/lib/protostar/lint/rules/package_version_suffix.rb +31 -0
  114. data/lib/protostar/lint/rules/reserved_names_with_numbers.rb +44 -0
  115. data/lib/protostar/lint/rules/rpc_pascal_case.rb +25 -0
  116. data/lib/protostar/lint/rules/rpc_request_response_unique.rb +40 -0
  117. data/lib/protostar/lint/rules/rpc_request_standard_name.rb +32 -0
  118. data/lib/protostar/lint/rules/rpc_response_standard_name.rb +31 -0
  119. data/lib/protostar/lint/rules/service_pascal_case.rb +25 -0
  120. data/lib/protostar/lint/rules/service_suffix.rb +28 -0
  121. data/lib/protostar/lint/rules/syntax_specified.rb +35 -0
  122. data/lib/protostar/lint/runner.rb +135 -0
  123. data/lib/protostar/lint.rb +122 -0
  124. data/lib/protostar/message/accessors.rb +86 -0
  125. data/lib/protostar/message/coercion.rb +171 -0
  126. data/lib/protostar/message/field_info.rb +145 -0
  127. data/lib/protostar/message/reflection.rb +149 -0
  128. data/lib/protostar/message.rb +572 -0
  129. data/lib/protostar/plugin.rb +94 -0
  130. data/lib/protostar/schema/default_value.rb +113 -0
  131. data/lib/protostar/schema/descriptor.rb +41 -0
  132. data/lib/protostar/schema/draft/copy.rb +88 -0
  133. data/lib/protostar/schema/draft/resolution.rb +177 -0
  134. data/lib/protostar/schema/draft.rb +779 -0
  135. data/lib/protostar/schema/enum.rb +106 -0
  136. data/lib/protostar/schema/extension_range.rb +37 -0
  137. data/lib/protostar/schema/features.rb +153 -0
  138. data/lib/protostar/schema/field.rb +201 -0
  139. data/lib/protostar/schema/file.rb +217 -0
  140. data/lib/protostar/schema/freezer.rb +61 -0
  141. data/lib/protostar/schema/message.rb +104 -0
  142. data/lib/protostar/schema/oneof.rb +38 -0
  143. data/lib/protostar/schema/options.rb +367 -0
  144. data/lib/protostar/schema/pool.rb +179 -0
  145. data/lib/protostar/schema/proto.rb +576 -0
  146. data/lib/protostar/schema/resolver.rb +118 -0
  147. data/lib/protostar/schema/service.rb +89 -0
  148. data/lib/protostar/schema/source_info.rb +53 -0
  149. data/lib/protostar/schema.rb +65 -0
  150. data/lib/protostar/short_names/any.rb +7 -0
  151. data/lib/protostar/short_names/duration.rb +7 -0
  152. data/lib/protostar/short_names/empty.rb +7 -0
  153. data/lib/protostar/short_names/field_mask.rb +7 -0
  154. data/lib/protostar/short_names/struct.rb +9 -0
  155. data/lib/protostar/short_names/timestamp.rb +7 -0
  156. data/lib/protostar/short_names/wrappers.rb +15 -0
  157. data/lib/protostar/text/extensions.rb +114 -0
  158. data/lib/protostar/text/parser.rb +439 -0
  159. data/lib/protostar/text/printer.rb +304 -0
  160. data/lib/protostar/text/tokenizer.rb +116 -0
  161. data/lib/protostar/text.rb +67 -0
  162. data/lib/protostar/types.rb +152 -0
  163. data/lib/protostar/unknown_field.rb +58 -0
  164. data/lib/protostar/version.rb +5 -0
  165. data/lib/protostar/view/generator.rb +298 -0
  166. data/lib/protostar/view/map.rb +194 -0
  167. data/lib/protostar/view/repeated.rb +143 -0
  168. data/lib/protostar/view/scan.rb +183 -0
  169. data/lib/protostar/view.rb +283 -0
  170. data/lib/protostar/well_known/any.rb +52 -0
  171. data/lib/protostar/well_known/duration.rb +53 -0
  172. data/lib/protostar/well_known/list_value.rb +63 -0
  173. data/lib/protostar/well_known/struct.rb +55 -0
  174. data/lib/protostar/well_known/timestamp.rb +64 -0
  175. data/lib/protostar/well_known/value.rb +60 -0
  176. data/lib/protostar/well_known.rb +38 -0
  177. data/lib/protostar/wire/io_source.rb +40 -0
  178. data/lib/protostar/wire/reader.rb +254 -0
  179. data/lib/protostar/wire/writer.rb +201 -0
  180. data/lib/protostar/wire.rb +96 -0
  181. data/lib/protostar.rb +95 -0
  182. data/shims/google-protobuf/lib/google/protobuf/any_pb.rb +17 -0
  183. data/shims/google-protobuf/lib/google/protobuf/api_pb.rb +22 -0
  184. data/shims/google-protobuf/lib/google/protobuf/compiler/plugin_pb.rb +25 -0
  185. data/shims/google-protobuf/lib/google/protobuf/descriptor_pb.rb +72 -0
  186. data/shims/google-protobuf/lib/google/protobuf/descriptor_pool.rb +164 -0
  187. data/shims/google-protobuf/lib/google/protobuf/descriptors.rb +553 -0
  188. data/shims/google-protobuf/lib/google/protobuf/duration_pb.rb +17 -0
  189. data/shims/google-protobuf/lib/google/protobuf/empty_pb.rb +17 -0
  190. data/shims/google-protobuf/lib/google/protobuf/field_mask_pb.rb +17 -0
  191. data/shims/google-protobuf/lib/google/protobuf/internal/convert.rb +180 -0
  192. data/shims/google-protobuf/lib/google/protobuf/internal/extensions.rb +154 -0
  193. data/shims/google-protobuf/lib/google/protobuf/internal/json.rb +104 -0
  194. data/shims/google-protobuf/lib/google/protobuf/internal/well_known.rb +140 -0
  195. data/shims/google-protobuf/lib/google/protobuf/map.rb +216 -0
  196. data/shims/google-protobuf/lib/google/protobuf/message.rb +544 -0
  197. data/shims/google-protobuf/lib/google/protobuf/message_exts.rb +41 -0
  198. data/shims/google-protobuf/lib/google/protobuf/plugin_pb.rb +4 -0
  199. data/shims/google-protobuf/lib/google/protobuf/repeated_field.rb +366 -0
  200. data/shims/google-protobuf/lib/google/protobuf/source_context_pb.rb +17 -0
  201. data/shims/google-protobuf/lib/google/protobuf/struct_pb.rb +20 -0
  202. data/shims/google-protobuf/lib/google/protobuf/timestamp_pb.rb +17 -0
  203. data/shims/google-protobuf/lib/google/protobuf/type_pb.rb +27 -0
  204. data/shims/google-protobuf/lib/google/protobuf/well_known_types.rb +37 -0
  205. data/shims/google-protobuf/lib/google/protobuf/wrappers_pb.rb +25 -0
  206. data/shims/google-protobuf/lib/google/protobuf.rb +107 -0
  207. data/shims/google-protobuf/lib/google/protobuf_ffi.rb +5 -0
  208. data/shims/google-protobuf/lib/google/protobuf_native.rb +5 -0
  209. data/sig/protostar/google/protobuf/any_pb.rbs +77 -0
  210. data/sig/protostar/google/protobuf/api_pb.rbs +242 -0
  211. data/sig/protostar/google/protobuf/compiler/plugin_pb.rbs +264 -0
  212. data/sig/protostar/google/protobuf/descriptor_pb.rbs +2220 -0
  213. data/sig/protostar/google/protobuf/duration_pb.rbs +82 -0
  214. data/sig/protostar/google/protobuf/empty_pb.rbs +18 -0
  215. data/sig/protostar/google/protobuf/field_mask_pb.rbs +170 -0
  216. data/sig/protostar/google/protobuf/source_context_pb.rbs +24 -0
  217. data/sig/protostar/google/protobuf/struct_pb.rbs +135 -0
  218. data/sig/protostar/google/protobuf/timestamp_pb.rbs +102 -0
  219. data/sig/protostar/google/protobuf/type_pb.rbs +304 -0
  220. data/sig/protostar/google/protobuf/wrappers_pb.rbs +169 -0
  221. data/sig/protostar/lint.rbs +216 -0
  222. data/sig/protostar.rbs +326 -0
  223. metadata +366 -0
@@ -0,0 +1,1307 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Protostar
4
+ module Diagnostics
5
+ # Every message the compiler can report, with a stable code: `P` for the
6
+ # lexer and parser, `L` for the linker and option interpreter, `V` for the
7
+ # validator (the checks protoc runs once a file is built). Lint rules have
8
+ # `W` codes of their own, in {Lint::RULES}.
9
+ #
10
+ # A message is matched against templates, protoc's wording with `%{name}`
11
+ # where it varies; the captures fill the entry's short title, the label
12
+ # under the span and the `help:` line. `protostar lint --explain CODE`
13
+ # prints {Entry#explanation}.
14
+ module Codes
15
+ # One code
16
+ class Entry
17
+ # @return [String] e.g. "L0301"
18
+ attr_reader :code
19
+ # @return [String] a few words, as `--explain` heads it
20
+ attr_reader :summary
21
+ # @return [Array<String>] protoc's messages, `%{name}` where they vary
22
+ attr_reader :templates
23
+ # @return [String] what the error means, an example and the fix
24
+ attr_reader :explanation
25
+
26
+ def initialize(code, summary, templates, explanation, title: nil, label: nil, help: nil, note: nil)
27
+ @code = code
28
+ @summary = summary
29
+ @templates = templates.freeze
30
+ @explanation = explanation
31
+ @title = title
32
+ @label = label
33
+ @help = help
34
+ @note = note
35
+ @patterns = templates.map { |t| [Codes.pattern(t), t.gsub(/%\{\w+\}/, "").size] }.freeze
36
+ freeze
37
+ end
38
+
39
+ # @return [Array(MatchData, Integer), nil] the best match and its literal length
40
+ def match(message)
41
+ best = nil
42
+ @patterns.each do |pattern, weight|
43
+ m = pattern.match(message)
44
+ best = [m, weight] if m && (best.nil? || weight > best[1])
45
+ end
46
+ best
47
+ end
48
+
49
+ # @return [String, nil] the short title for a match
50
+ def title(captures)
51
+ fill(@title, captures)
52
+ end
53
+
54
+ # @return [String, nil] the label under the primary span
55
+ def label(captures)
56
+ fill(@label, captures)
57
+ end
58
+
59
+ # @return [String, nil]
60
+ def help(captures)
61
+ fill(@help, captures)
62
+ end
63
+
64
+ # @return [String, nil]
65
+ def note(captures)
66
+ fill(@note, captures)
67
+ end
68
+
69
+ private
70
+
71
+ # A template with a capture the match lacks is left out; protoc's quotes
72
+ # in what is filled in become backticks
73
+ def fill(template, captures)
74
+ return nil unless template
75
+ template.gsub(/%\{(\w+)\}/) do
76
+ captures.fetch($1.to_sym) { return nil }.gsub(/"([^"]*)"/, '`\1`')
77
+ end
78
+ end
79
+ end
80
+
81
+ # A {Codes.lookup} result
82
+ class Match
83
+ # @return [Entry]
84
+ attr_reader :entry
85
+ # @return [Hash{Symbol => String}]
86
+ attr_reader :captures
87
+
88
+ def initialize(entry, captures)
89
+ @entry = entry
90
+ @captures = captures.freeze
91
+ freeze
92
+ end
93
+
94
+ # @return [String]
95
+ def code
96
+ @entry.code
97
+ end
98
+ end
99
+
100
+ # @return [Regexp] the template with each `%{name}` as a lazy named group
101
+ def self.pattern(template)
102
+ source = template.split(/(%\{\w+\})/).map do |part|
103
+ part.start_with?("%{") ? "(?<#{part[2..-2]}>.*?)" : Regexp.escape(part)
104
+ end.join
105
+ Regexp.new("\\A#{source}\\z", Regexp::MULTILINE)
106
+ end
107
+
108
+ # @param message [String] as the compiler reports it
109
+ # @return [Match, nil] the entry whose template matches the most literal text
110
+ def self.lookup(message)
111
+ best = nil
112
+ ENTRIES.each do |entry|
113
+ m, weight = entry.match(message)
114
+ best = [entry, m, weight] if m && (best.nil? || weight > best[2])
115
+ end
116
+ return nil unless best
117
+ captures = best[1].names.to_h { |n| [n.to_sym, best[1][n]] }
118
+ Match.new(best[0], captures)
119
+ end
120
+
121
+ # @param code [String]
122
+ # @return [Entry, nil]
123
+ def self.[](code)
124
+ BY_CODE[code.upcase]
125
+ end
126
+
127
+ # @param diagnostic [Compiler::Diagnostic]
128
+ # @return [Compiler::Diagnostic] with the code, title, label, help and note the
129
+ # catalogue has for its message
130
+ def self.annotate(diagnostic)
131
+ match = lookup(diagnostic.message)
132
+ return diagnostic unless match
133
+ entry = match.entry
134
+ c = match.captures
135
+ spans = diagnostic.spans
136
+ spans = [Span.new(diagnostic.line, diagnostic.column)] if spans.empty? && diagnostic.line
137
+ label = entry.label(c)
138
+ if label && (first = spans.first) && first.label.nil?
139
+ spans = [first.with_label(label), *spans.drop(1)]
140
+ end
141
+ diagnostic.with(code: entry.code, title: entry.title(c), spans: spans,
142
+ help: diagnostic.help + [entry.help(c)].compact, notes: diagnostic.notes + [entry.note(c)].compact)
143
+ end
144
+
145
+ ENTRIES = []
146
+
147
+ def self.define(code, summary, templates, explanation, **kwargs)
148
+ ENTRIES << Entry.new(code, summary, Array(templates), explanation, **kwargs)
149
+ end
150
+ private_class_method :define
151
+
152
+ # Lexer
153
+
154
+ define "P0101", "control character in the source", "Invalid control characters encountered in text.", <<~TEXT
155
+ The file holds a byte below 32 that is not whitespace, outside of a string or comment. It usually comes
156
+ from a bad copy and paste or an editor that saved a stray escape.
157
+
158
+ message A {}\\x01
159
+
160
+ Delete the character; `cat -v file.proto` shows where it is.
161
+ TEXT
162
+
163
+ define "P0102", "tokens run together",
164
+ ["Need space between identifier and decimal point.", "Need space between number and identifier."], <<~TEXT,
165
+ A number and a word touch, so the tokenizer cannot tell where one ends.
166
+
167
+ int32 a = 1foo;
168
+ option x = foo.5;
169
+
170
+ Put a space between them, or remove the stray characters.
171
+ TEXT
172
+ title: "missing space between tokens", label: "here"
173
+
174
+ define "P0103", "not UTF-8", "Proto file starts with 0xEF but not UTF-8 BOM. Only UTF-8 is accepted for proto file.",
175
+ <<~TEXT
176
+ The file starts with the first byte of a UTF-8 byte order mark but not the rest of it. `.proto` files are
177
+ UTF-8; this one was probably saved in another encoding.
178
+
179
+ Save the file as UTF-8, with or without the byte order mark.
180
+ TEXT
181
+
182
+ define "P0104", "unterminated string",
183
+ ["Unexpected end of string.", "Multiline strings are not allowed. Did you miss a \"?."], <<~TEXT,
184
+ A string literal is not closed before the end of its line. Strings cannot span lines; adjacent literals
185
+ are joined, so a long one can be split.
186
+
187
+ option java_package = "com.example;
188
+
189
+ Close the quote. For a long string, write `"first part" "second part"`.
190
+ TEXT
191
+ title: "unterminated string literal", label: "string starts here", help: "close the string on the same line"
192
+
193
+ define "P0105", "bad escape sequence",
194
+ ["Expected hex digits for escape sequence.", "Expected four hex digits for \\u escape sequence.",
195
+ "Expected eight hex digits up to 10ffff for \\U escape sequence", "Invalid escape sequence in string literal."],
196
+ <<~TEXT, label: "here"
197
+ A backslash in a string starts an escape that is not one of protobuf's: `\\a \\b \\f \\n \\r \\t \\v \\\\ \\? \\' \\"`,
198
+ octal `\\123`, hex `\\x7f`, `\\u` with four hex digits or `\\U` with eight.
199
+
200
+ string s = 1 [default = "C:\\path"];
201
+
202
+ Escape the backslash itself (`\\\\`) or use one of the escapes above.
203
+ TEXT
204
+
205
+ define "P0106", "malformed number",
206
+ ["\"0x\" must be followed by hex digits.", "Numbers starting with leading zero must be in octal.",
207
+ "\"e\" must be followed by exponent.", "Already saw decimal point or exponent; can't have another one.",
208
+ "Hex and octal numbers must be integers."], <<~TEXT, label: "here"
209
+ A numeric literal does not follow protobuf's grammar: hex is `0x` and hex digits, a leading zero means
210
+ octal, and an exponent needs digits after the `e`.
211
+
212
+ int32 a = 09;
213
+
214
+ Write the number in decimal, or fix the hex, octal or exponent part.
215
+ TEXT
216
+
217
+ define "P0107", "non-ASCII code point", "Interpreting non ascii codepoint %{codepoint}.", <<~TEXT, label: "here"
218
+ A `\\u` or `\\U` escape names a code point above 127 in a context that is read as bytes; protoc warns and
219
+ stores its UTF-8 encoding.
220
+
221
+ If that is what you meant, write the character itself in the UTF-8 source.
222
+ TEXT
223
+
224
+ define "P0108", "nested block comment", "\"/*\" inside block comment. Block comments cannot be nested.",
225
+ <<~TEXT, title: "block comments cannot be nested", label: "nested `/*`"
226
+ A `/*` appears inside a `/* ... */` comment. Block comments end at the first `*/`, so nesting does not work.
227
+
228
+ /* outer /* inner */ */
229
+
230
+ Use `//` line comments to comment out code that has block comments in it.
231
+ TEXT
232
+
233
+ define "P0109", "unterminated block comment", ["End-of-file inside block comment.", " Comment started here."],
234
+ <<~TEXT, title: "unterminated block comment"
235
+ A `/*` comment is never closed, so the rest of the file is part of it.
236
+
237
+ /* TODO
238
+ message A {}
239
+
240
+ Close it with `*/`.
241
+ TEXT
242
+
243
+ # Parser
244
+
245
+ define "P0001", "unexpected token", "Expected %{expected}.", <<~TEXT, title: "expected %{expected}", label: "expected %{expected} here"
246
+ The parser found something other than what the grammar allows at this point. The message names what it
247
+ expected: a `;` at the end of a statement, a name, a number, a type.
248
+
249
+ message A {
250
+ int32 a = 1
251
+ int32 b = 2;
252
+ }
253
+
254
+ A missing `;` is reported at the start of the next statement, so look at the end of the previous line too.
255
+ TEXT
256
+
257
+ define "P0201", "no syntax or edition statement",
258
+ "File must begin with an edition or syntax statement, e.g. 'edition = \"2023\";'.", <<~TEXT
259
+ This parser was told to require a `syntax` or `edition` statement, and the file has none.
260
+
261
+ Start the file with `edition = "2023";`, or `syntax = "proto3";` for proto3.
262
+ TEXT
263
+
264
+ define "P0202", "unknown syntax or edition",
265
+ ["Expected syntax identifier.", "Unrecognized syntax identifier \"%{syntax}\". This parser only recognizes \"proto2\" and \"proto3\".",
266
+ "Unknown edition \"%{edition}\"."], <<~TEXT, label: "not a known syntax or edition"
267
+ `syntax` takes `"proto2"` or `"proto3"`; `edition` takes an edition year protoc knows, like `"2023"` or
268
+ `"2024"`.
269
+
270
+ syntax = "proto4";
271
+
272
+ Use one of the supported values.
273
+ TEXT
274
+
275
+ define "P0203", "not a top-level statement", "Expected top-level statement (e.g. \"message\").", <<~TEXT,
276
+ At the top of a file only `syntax`, `edition`, `package`, `import`, `option`, `message`, `enum`, `service`
277
+ and `extend` can start a statement.
278
+
279
+ mesage A {}
280
+
281
+ Check the spelling of the keyword; a stray `}` or `;` from a previous edit causes this too.
282
+ TEXT
283
+ title: "expected a top-level statement", label: "not `message`, `enum`, `service`, `extend`, `import`, `option` or `package`"
284
+
285
+ define "P0204", "unmatched brace", "Unmatched \"}\".", <<~TEXT, title: "unmatched `}`", label: "no `{` to close"
286
+ A `}` at the top level of the file closes nothing.
287
+
288
+ message A {}
289
+ }
290
+
291
+ Remove it, or find the `{` it was meant to close.
292
+ TEXT
293
+
294
+ define "P0205", "unclosed block", "Reached end of input in %{what} (missing '}').", <<~TEXT,
295
+ The file ends inside a `message`, `enum`, `service`, `oneof`, `extend` or options block.
296
+
297
+ message A {
298
+ int32 a = 1;
299
+
300
+ Add the missing `}`.
301
+ TEXT
302
+ title: "end of file inside %{what}", label: "expected `}`", help: "add the missing `}`"
303
+
304
+ define "P0206", "two package statements", "Multiple package definitions.", <<~TEXT, label: "second `package`"
305
+ A file has one package. Every type in it is named under that package.
306
+
307
+ package a;
308
+ package b;
309
+
310
+ Keep one; split the file if the types belong to two packages.
311
+ TEXT
312
+
313
+ define "P0207", "bad import", "Expected a string naming the file to import.", <<~TEXT, label: "expected a quoted file name"
314
+ `import` takes a quoted path, relative to an include path.
315
+
316
+ import foo/bar.proto;
317
+
318
+ Quote it: `import "foo/bar.proto";`.
319
+ TEXT
320
+
321
+ define "P0208", "misplaced visibility", "'local' and 'export' visibility modifiers are valid only on 'message' and 'enum'",
322
+ <<~TEXT, label: "not before `message` or `enum`"
323
+ Edition 2024's `export` and `local` modifiers apply to messages and enums only.
324
+
325
+ export service S {}
326
+
327
+ Remove the modifier.
328
+ TEXT
329
+
330
+ define "P0209", "nesting too deep", "Reached maximum recursion limit for nested messages.", <<~TEXT
331
+ Messages are nested more than 32 levels deep. protoc stops there to bound its recursion.
332
+
333
+ Move inner messages to the top level; nothing about the wire format needs the nesting.
334
+ TEXT
335
+
336
+ define "P0210", "import kind not allowed here",
337
+ ["option import is not supported before edition 2024.",
338
+ "imports should precede any option imports to ensure proto files can roundtrip.",
339
+ "weak import is not supported in edition 2024 and above. Consider using option import instead."],
340
+ <<~TEXT, label: "here"
341
+ `import option` arrived in edition 2024, which also dropped `import weak`; plain imports come before
342
+ option imports.
343
+
344
+ edition = "2023";
345
+ import option "acme/options.proto";
346
+
347
+ Move the file to edition 2024 for option imports, use `import option` instead of `import weak` there, and
348
+ list plain imports first.
349
+ TEXT
350
+
351
+ define "P0301", "missing label", "Expected \"required\", \"optional\", or \"repeated\".", <<~TEXT,
352
+ In proto2 every field needs a label.
353
+
354
+ syntax = "proto2";
355
+ message A { int32 a = 1; }
356
+
357
+ Write `optional int32 a = 1;` (or `repeated`). Do not reach for `required`: see
358
+ `protostar lint --explain FIELD_NOT_REQUIRED`.
359
+ TEXT
360
+ title: "proto2 fields need a label", label: "expected `optional` or `repeated`", help: "add `optional`"
361
+
362
+ define "P0302", "missing field number", ["Missing field number.", "Expected field number."], <<~TEXT,
363
+ Every field needs `= N` with its field number, the number on the wire.
364
+
365
+ message A { int32 a; }
366
+
367
+ Add the next unused number: `int32 a = 1;`.
368
+ TEXT
369
+ title: "missing field number", label: "expected `= <number>`"
370
+
371
+ define "P0303", "number out of range", ["Field number out of bounds.", "Integer out of range."], <<~TEXT,
372
+ The number does not fit: field numbers go up to 536,870,911, enum values are 32-bit signed integers.
373
+
374
+ enum E { A = 0; B = 4294967296; }
375
+
376
+ Use a smaller number.
377
+ TEXT
378
+ label: "out of range"
379
+
380
+ define "P0304", "malformed group", ["Group names must start with a capital letter.", "Missing group body."], <<~TEXT
381
+ A proto2 `group` declares a field and a message type at once; the type name must be capitalised and the body
382
+ follow in braces.
383
+
384
+ optional group result = 1 { optional string url = 2; }
385
+
386
+ Capitalise the name (`group Result`). Better, do not use groups: see `protostar lint --explain NO_GROUPS`.
387
+ TEXT
388
+
389
+ define "P0305", "map field misuse",
390
+ ["Map fields are not allowed in oneofs.", "Field labels (required/optional/repeated) are not allowed on map fields.",
391
+ "Map fields are not allowed to be extensions."], <<~TEXT
392
+ A `map<K, V>` field is a repeated field of a synthetic entry message: it cannot have a label, sit in a
393
+ `oneof`, or be an extension.
394
+
395
+ repeated map<string, int32> counts = 1;
396
+
397
+ Drop the label; for a map in a oneof, wrap it in a message.
398
+ TEXT
399
+
400
+ define "P0306", "label in a oneof", "Fields in oneofs must not have labels (required / optional / repeated).",
401
+ <<~TEXT, label: "remove the label", help: "oneof members are always optional; to repeat one, wrap it in a message"
402
+ Members of a `oneof` are optional by construction and cannot be repeated.
403
+
404
+ oneof kind { optional string name = 1; }
405
+
406
+ Remove the label.
407
+ TEXT
408
+
409
+ define "P0307", "proto2 syntax in an editions file",
410
+ ["Label \"optional\" is not supported in editions. By default, all singular fields have presence unless features.field_presence is set.",
411
+ "Label \"required\" is not supported in editions, use features.field_presence = LEGACY_REQUIRED.",
412
+ "Group syntax is no longer supported in editions. To get group behavior you can specify features.message_encoding = DELIMITED on a message field."],
413
+ <<~TEXT
414
+ Editions replace labels and groups with features. Singular fields have presence by default, `required` is
415
+ `features.field_presence = LEGACY_REQUIRED`, and a group is a message field with
416
+ `features.message_encoding = DELIMITED`.
417
+
418
+ edition = "2023";
419
+ message A { optional int32 a = 1; }
420
+
421
+ Drop `optional`; spell the other two as features.
422
+ TEXT
423
+
424
+ define "P0308", "obsolete type name", "Type '%{old}' is obsolete in unstable editions, use '%{new}' instead.",
425
+ <<~TEXT, label: "obsolete", help: "write `%{new}`"
426
+ In the unstable edition the integer types were renamed, and the old spelling means something else.
427
+
428
+ Use the spelling the message suggests.
429
+ TEXT
430
+
431
+ define "P0309", "bad default or json_name",
432
+ ["Already set option \"default\".", "Already set option \"json_name\".", "Expected integer for field default value.",
433
+ "Unsigned field can't have negative default value.", "Expected string for field default value.",
434
+ "Expected enum identifier for field default value.", "Expected string for JSON name.",
435
+ "Messages can't have default values."], <<~TEXT, label: "here"
436
+ `default` and `json_name` are written once per field, and the default must be a value of the field's type:
437
+ a number for numbers, a quoted string for strings and bytes, a value name for enums. Message fields have no
438
+ default.
439
+
440
+ optional uint32 a = 1 [default = -1];
441
+
442
+ Fix the value, or remove the duplicate.
443
+ TEXT
444
+
445
+ define "P0401", "unterminated option value",
446
+ ["Unexpected end of stream while parsing aggregate value.", "Unexpected end of stream while parsing option value."],
447
+ <<~TEXT
448
+ The file ends inside an option value, usually an aggregate `{ ... }` that is never closed.
449
+
450
+ Close the braces.
451
+ TEXT
452
+
453
+ define "P0402", "bad negative value", ["Identifier after '-' symbol must be inf or nan.", "Invalid '-' symbol before string."],
454
+ <<~TEXT, label: "here"
455
+ A minus sign can only precede a number, `inf` or `nan`.
456
+
457
+ option (x) = -foo;
458
+
459
+ Remove the `-`, or use a number.
460
+ TEXT
461
+
462
+ define "P0403", "missing option value", "Expected option value.", <<~TEXT, label: "expected a value"
463
+ An option needs a value after `=`: a number, a string, an identifier or an aggregate in braces.
464
+
465
+ option java_package = ;
466
+
467
+ Write the value.
468
+ TEXT
469
+
470
+ define "P0501", "bad reserved or extensions range",
471
+ ["Expected field number range.", "Expected field name or number range.", "Expected enum value or number range.",
472
+ "Expected enum number range."], <<~TEXT, label: "expected a number or range"
473
+ `reserved` and `extensions` take numbers and ranges (`2, 15, 9 to 11, 40 to max`); `reserved` also takes
474
+ names.
475
+
476
+ extensions foo;
477
+
478
+ Write numbers or ranges.
479
+ TEXT
480
+
481
+ define "P0502", "reserved names spelt for the wrong syntax",
482
+ ["Reserved names must be identifiers in editions, not string literals.",
483
+ "Reserved names must be string literals. (Only editions supports identifiers.)",
484
+ "Expected enum value string literal.", "Expected field name string literal.", "Expected enum value identifier.",
485
+ "Expected field name identifier."], <<~TEXT, label: "here"
486
+ Before editions reserved names are quoted strings; under editions they are bare identifiers.
487
+
488
+ syntax = "proto3";
489
+ message A { reserved foo; }
490
+
491
+ Write `reserved "foo";` in proto2 and proto3, `reserved foo;` in editions.
492
+ TEXT
493
+
494
+ define "P0503", "reserved name is not an identifier", "Reserved name \"%{name}\" is not a valid identifier.",
495
+ <<~TEXT, label: "not an identifier"
496
+ A reserved name must be a name a field or value could have.
497
+
498
+ reserved "foo bar";
499
+
500
+ Fix the spelling.
501
+ TEXT
502
+
503
+ define "P0601", "pointless allow_alias",
504
+ ["\"%{enum}\" declares 'option allow_alias = false;' which has no effect. Please remove the declaration.",
505
+ "\"%{enum}\" declares support for enum aliases but no enum values share field numbers. Please remove the unnecessary 'option allow_alias = true;' declaration."],
506
+ <<~TEXT, help: "remove the `allow_alias` option"
507
+ `allow_alias = false` is the default, and `allow_alias = true` with no two values sharing a number does
508
+ nothing; protoc rejects both so the option means something when present.
509
+
510
+ enum E { option allow_alias = true; A = 0; B = 1; }
511
+
512
+ Remove the option.
513
+ TEXT
514
+
515
+ define "P0602", "enum value without a number", "Missing numeric value for enum constant.", <<~TEXT,
516
+ Every enum value needs `= N`.
517
+
518
+ enum Color { COLOR_UNSPECIFIED; }
519
+
520
+ Write `COLOR_UNSPECIFIED = 0;`.
521
+ TEXT
522
+ label: "expected `= <number>`"
523
+
524
+ # Linker: files and imports
525
+
526
+ define "L0101", "file not found", "File not found.", <<~TEXT, help: "check the include paths (-I) and the spelling of the name"
527
+ No include path has a file of that name. For a file named on the command line, the name is resolved against
528
+ `-I` (or the file's own directory when there is none); for an import, against the include paths in order.
529
+
530
+ Pass `-I` with the directory the import is relative to.
531
+ TEXT
532
+
533
+ define "L0102", "import failed",
534
+ ["Import \"%{import}\" was not found or had errors.", "Import \"%{import}\" has not been loaded."], <<~TEXT,
535
+ The imported file could not be found, or it could not be compiled; its own errors are reported above this
536
+ one.
537
+
538
+ import "acme/missing.proto";
539
+
540
+ Fix the imported file's errors first, or the include path that should find it.
541
+ TEXT
542
+ title: "cannot import `%{import}`", label: "not found or has errors"
543
+
544
+ define "L0103", "import listed twice", "Import \"%{import}\" was listed twice.", <<~TEXT, label: "second import", help: "remove one of the imports"
545
+ The same file is imported twice.
546
+
547
+ import "a.proto";
548
+ import "a.proto";
549
+
550
+ Remove the duplicate.
551
+ TEXT
552
+
553
+ define "L0104", "import cycle", "File recursively imports itself: %{chain}", <<~TEXT, title: "import cycle: %{chain}", label: "this import closes the cycle"
554
+ Files cannot import each other in a cycle, directly or through others.
555
+
556
+ Move the types both files need into a third file that both import.
557
+ TEXT
558
+
559
+ define "L0105", "file defined twice",
560
+ ["A file with this name is already in the pool.", "file \"%{file}\" is already in the pool"], <<~TEXT
561
+ A file of this name was already built. This happens when the same file is reachable under two names, or
562
+ when a pool is reused.
563
+
564
+ Name each file once, by one include path.
565
+ TEXT
566
+
567
+ define "L0106", "unsupported edition",
568
+ ["Edition %{edition} is earlier than the minimum supported edition %{minimum}",
569
+ "Edition %{edition} is later than the maximum supported edition %{maximum}"], <<~TEXT, label: "unsupported edition"
570
+ The edition is outside the range this compiler (like protoc 36.2) supports.
571
+
572
+ Use an edition between PROTO2 and 2026.
573
+ TEXT
574
+
575
+ # Linker: names
576
+
577
+ define "L0201", "name already defined",
578
+ ["\"%{name}\" is already defined in \"%{scope}\".", "\"%{name}\" is already defined.",
579
+ "\"%{name}\" is already defined in file \"%{file}\".",
580
+ "\"%{name}\" is already defined (as something other than a package) in file \"%{file}\".",
581
+ "\"%{name}\" is already defined in file \"%{file}\" (redefined in \"%{other}\")",
582
+ "\"%{name}\" is already defined as a package in file \"%{file}\" (redefined as a %{kind} in \"%{other}\")"],
583
+ <<~TEXT, title: "`%{name}` is defined more than once", label: "redefined here"
584
+ Two declarations have the same full name: two fields of one message, two messages in a package, or a type
585
+ and a package. Fields, nested types, oneofs and enum values share one namespace per scope.
586
+
587
+ message A {
588
+ int32 id = 1;
589
+ string id = 2;
590
+ }
591
+
592
+ Rename one of them.
593
+ TEXT
594
+
595
+ define "L0202", "enum values are siblings of their enum",
596
+ "Note that enum values use C++ scoping rules, meaning that enum values are siblings of their type, not children of it. Therefore, \"%{name}\" must be unique within %{scope}, not just within \"%{enum}\".",
597
+ <<~TEXT, title: "enum value names are scoped like C++, not to their enum", help: "prefix the values with the enum's name, e.g. `%{enum}_%{name}`"
598
+ An enum's values live in the scope that contains the enum, not inside it, so two enums in one package
599
+ cannot both have `UNKNOWN`.
600
+
601
+ enum A { UNKNOWN = 0; }
602
+ enum B { UNKNOWN = 0; }
603
+
604
+ Prefix each value with its enum's name: `A_UNKNOWN`, `B_UNKNOWN`. `ENUM_VALUE_PREFIX` checks for this.
605
+ TEXT
606
+
607
+ define "L0203", "name not defined", "\"%{name}\" is not defined.", <<~TEXT, title: "`%{name}` is not defined", label: "not found in this scope"
608
+ No type, option or extension of that name is visible from here: it is misspelt, lives in a package you did
609
+ not qualify, or its file is not imported.
610
+
611
+ message A { Missing m = 1; }
612
+
613
+ Check the spelling and package, and import the file that defines it.
614
+ TEXT
615
+
616
+ define "L0204", "name defined in a file not imported",
617
+ "\"%{name}\" seems to be defined in \"%{file}\", which is not imported by \"%{importer}\". To use it here, please add the necessary import.",
618
+ <<~TEXT, title: "`%{name}` is defined in `%{file}`, which is not imported", label: "not imported", help: "add `import \"%{file}\";`"
619
+ The name exists, but in a file this one does not import (directly or through `import public`).
620
+
621
+ Add the import.
622
+ TEXT
623
+
624
+ define "L0205", "name resolved to the wrong scope",
625
+ ["\"%{name}\" is resolved to \"%{resolved}\", which is not defined. The innermost scope is searched first in name resolution. Consider using a leading '.'(i.e., \".%{full}\") to start from the outermost scope.",
626
+ "Option \"%{name}\" is resolved to \"(%{resolved})\", which is not defined. The innermost scope is searched first in name resolution. Consider using a leading '.'(i.e., \"(.%{full}\") to start from the outermost scope."],
627
+ <<~TEXT, title: "`%{name}` resolves to `%{resolved}`, which is not defined", label: "resolves to `%{resolved}`", help: "write `.%{full}` to start from the outermost scope"
628
+ Names resolve from the innermost scope out, and the first component that matches decides: once `foo` in
629
+ `foo.Bar` matches a nested `foo`, the outer `foo` is never tried.
630
+
631
+ package foo;
632
+ message Bar {}
633
+ message A {
634
+ message foo {}
635
+ foo.Bar b = 1;
636
+ }
637
+
638
+ Qualify the name fully with a leading dot: `.foo.Bar`.
639
+ TEXT
640
+
641
+ define "L0206", "wrong kind of type",
642
+ ["\"%{name}\" is not a message type.", "\"%{name}\" is not a type.", "\"%{name}\" is not an enum type."], <<~TEXT,
643
+ The name resolves, but to the wrong kind of thing: a field or package where a type is needed, an enum
644
+ where an extendee must be a message.
645
+
646
+ message A { int32 x = 1; }
647
+ message B { A.x y = 1; }
648
+
649
+ Point it at a type of the right kind.
650
+ TEXT
651
+ title: "`%{name}` is not the right kind of type", label: "wrong kind"
652
+
653
+ define "L0207", "symbol not visible",
654
+ "Symbol \"%{name}\", defined in \"%{file}\" %{why} is not visible from \"%{importer}\". %{reason} and cannot be accessed outside its own file",
655
+ <<~TEXT, title: "`%{name}` is local to `%{file}`", label: "not visible here"
656
+ Under edition 2024 a type marked `local`, or local by `default_symbol_visibility`, can only be used in its
657
+ own file.
658
+
659
+ Mark it `export`, or move what uses it into its file.
660
+ TEXT
661
+
662
+ # Linker: numbers and ranges
663
+
664
+ define "L0301", "field number already used",
665
+ ["Field number %{number} has already been used in \"%{scope}\" by field \"%{other}\". Next available field number is %{next}.",
666
+ "Field number %{number} has already been used in \"%{scope}\" by field \"%{other}\". There are no available field numbers.",
667
+ "Field number %{number} has already been used in \"%{scope}\" by field \"%{other}\". %{suggestion}."],
668
+ <<~TEXT, title: "field number %{number} is already used in `%{scope}`", label: "reused here", help: "the next available field number is %{next}"
669
+ Two fields of one message have the same number. The number is what goes on the wire, so it must be unique
670
+ within the message.
671
+
672
+ message A {
673
+ int32 a = 1;
674
+ int32 b = 1;
675
+ }
676
+
677
+ Give the new field the next free number. Do not reuse the number of a field you deleted: reserve it.
678
+ TEXT
679
+
680
+ define "L0302", "extension number already used",
681
+ ["Extension number %{number} has already been used in \"%{scope}\" by extension \"%{other}\".",
682
+ "extension number %{number} of \"%{scope}\" is already used by \"%{other}\" (redefined by \"%{name}\")"],
683
+ <<~TEXT, title: "extension number %{number} of `%{scope}` is already used", label: "reused here"
684
+ Two extensions of one message use the same number.
685
+
686
+ Pick another number inside the message's extension ranges.
687
+ TEXT
688
+
689
+ define "L0303", "extension number used in another file",
690
+ "Extension number %{number} has already been used in \"%{scope}\" by extension \"%{other}\" defined in %{file}.",
691
+ <<~TEXT, title: "extension number %{number} of `%{scope}` is already used in %{file}", label: "also used in %{file}"
692
+ Another file already extends this message with this number. Both cannot be linked into one program.
693
+
694
+ Pick a number no other file uses; for options, register one with the protobuf global extension registry.
695
+ TEXT
696
+
697
+ define "L0304", "number not positive",
698
+ ["Field numbers must be positive integers.", "Extension numbers must be positive integers.",
699
+ "Reserved numbers must be positive integers."], <<~TEXT, label: "must be 1 or more"
700
+ Field, extension and reserved numbers start at 1.
701
+
702
+ message A { int32 a = 0; }
703
+
704
+ Use 1 or more.
705
+ TEXT
706
+
707
+ define "L0305", "number too large",
708
+ ["Field numbers cannot be greater than %{max}.", "Extension numbers cannot be greater than %{max}."],
709
+ <<~TEXT, label: "greater than %{max}"
710
+ Field numbers have 29 bits on the wire: the largest is 536,870,911 (2,147,483,647 for MessageSet
711
+ extensions).
712
+
713
+ Use a smaller number. Numbers 1 to 15 take one byte on the wire, so give them to the most common fields.
714
+ TEXT
715
+
716
+ define "L0306", "empty range",
717
+ ["Extension range end number must be greater than start number.", "Reserved range end number must be greater than start number."],
718
+ <<~TEXT, label: "end is not after start"
719
+ A range `a to b` needs `b` at least `a`.
720
+
721
+ reserved 10 to 5;
722
+
723
+ Swap the ends.
724
+ TEXT
725
+
726
+ define "L0307", "overlapping ranges",
727
+ ["Reserved range %{start} to %{end} overlaps with already-defined range %{other_start} to %{other_end}.",
728
+ "Extension range %{start} to %{end} overlaps with reserved range %{other_start} to %{other_end}.",
729
+ "Extension range %{start} to %{end} overlaps with already-defined range %{other_start} to %{other_end}."],
730
+ <<~TEXT, title: "range %{start} to %{end} overlaps %{other_start} to %{other_end}", label: "overlaps"
731
+ Reserved and extension ranges of one message cannot overlap each other.
732
+
733
+ extensions 100 to 199;
734
+ reserved 150 to 160;
735
+
736
+ Make the ranges disjoint.
737
+ TEXT
738
+
739
+ define "L0308", "extension range includes a field", "Extension range %{start} to %{end} includes field \"%{field}\" (%{number}).",
740
+ <<~TEXT, title: "extension range %{start} to %{end} includes field `%{field}`", label: "this range"
741
+ A field's number falls inside one of the message's extension ranges.
742
+
743
+ Move the field or shrink the range.
744
+ TEXT
745
+
746
+ define "L0309", "reserved number used",
747
+ ["Field \"%{name}\" uses reserved number %{number}.", "Enum value \"%{name}\" uses reserved number %{number}."],
748
+ <<~TEXT, title: "`%{name}` uses reserved number %{number}", label: "reserved here", help: "give `%{name}` a number that is not reserved"
749
+ The number was reserved, usually because a field or value that had it was deleted. Reusing it would make
750
+ old data decode as the new field.
751
+
752
+ message A {
753
+ reserved 2;
754
+ int32 b = 2;
755
+ }
756
+
757
+ Use another number.
758
+ TEXT
759
+
760
+ define "L0310", "reserved name used", ["Field name \"%{name}\" is reserved.", "Enum value \"%{name}\" is reserved."],
761
+ <<~TEXT, title: "`%{name}` is a reserved name", label: "reserved"
762
+ The name was reserved, usually because a field or value of that name was deleted; the JSON and text formats
763
+ would read old data into the new field.
764
+
765
+ Use another name.
766
+ TEXT
767
+
768
+ define "L0311", "name reserved twice",
769
+ ["Field name \"%{name}\" is reserved multiple times.", "Enum value \"%{name}\" is reserved multiple times."],
770
+ <<~TEXT, label: "reserved again", help: "remove the duplicate"
771
+ A name appears twice in `reserved`.
772
+
773
+ Remove the duplicate.
774
+ TEXT
775
+
776
+ define "L0312", "suggested field numbers", "Suggested field numbers for %{message}: %{numbers}", <<~TEXT,
777
+ Follows a field number error: these numbers are free in the message.
778
+ TEXT
779
+ title: "free field numbers in `%{message}`: %{numbers}"
780
+
781
+ # Linker: fields
782
+
783
+ define "L0401", "required extension", ["The extension %{name} cannot be required.", "Extensions can't be required."],
784
+ <<~TEXT, label: "required"
785
+ Extensions cannot be `required`: a reader that does not know the extension could never check it.
786
+
787
+ Make it `optional`.
788
+ TEXT
789
+
790
+ define "L0402", "bad default value",
791
+ ["Repeated fields can't have default values.", "Boolean default must be true or false.",
792
+ "Invalid escaping in default value.", "Default value for an enum field must be an identifier.",
793
+ "Enum type \"%{enum}\" has no value named \"%{value}\"."], <<~TEXT, label: "here"
794
+ The `default` does not fit the field: repeated fields have none, booleans take `true` or `false`, enums take
795
+ one of their value names.
796
+
797
+ optional Color c = 1 [default = PURPLE];
798
+
799
+ Fix the value or remove the default.
800
+ TEXT
801
+
802
+ define "L0403", "empty enum or oneof", ["Enums must contain at least one value.", "Oneof must have at least one field."],
803
+ <<~TEXT
804
+ An enum needs at least one value and a oneof at least one field.
805
+
806
+ enum E {}
807
+
808
+ Add one, or remove the declaration.
809
+ TEXT
810
+
811
+ define "L0404", "oneof fields not together",
812
+ "Fields in the same oneof must be defined consecutively. \"%{field}\" cannot be defined before the completion of the \"%{oneof}\" oneof definition.",
813
+ <<~TEXT, title: "oneof `%{oneof}` is interrupted by `%{field}`"
814
+ The members of a oneof are written together inside its braces.
815
+
816
+ Move the field out of the middle of the oneof.
817
+ TEXT
818
+
819
+ define "L0405", "labelled oneof member", "Fields of oneofs must themselves have label LABEL_OPTIONAL.", <<~TEXT
820
+ A descriptor put a oneof member under a label other than optional. Only hand-built descriptors can do this.
821
+ TEXT
822
+
823
+ define "L0406", "not an extension number", "\"%{extendee}\" does not declare %{number} as an extension number.",
824
+ <<~TEXT, title: "`%{extendee}` has no extension range for %{number}", label: "outside the extension ranges"
825
+ An extension's number must fall inside one of the extended message's `extensions` ranges.
826
+
827
+ message A { extensions 100 to 199; }
828
+ extend A { optional int32 x = 5; }
829
+
830
+ Use a number from the ranges, or widen them.
831
+ TEXT
832
+
833
+ define "L0407", "features outside editions",
834
+ ["Features are only valid under editions.", "Feature field `%{feature}` must resolve to a known value, found %{value}"],
835
+ <<~TEXT, label: "here"
836
+ `features` options only exist in editions files, and must be set to a known value.
837
+
838
+ syntax = "proto3";
839
+ option features.field_presence = EXPLICIT;
840
+
841
+ Move the file to editions, or remove the option.
842
+ TEXT
843
+
844
+ # Linker: options
845
+
846
+ define "L0501", "malformed option name", ["Option must have a name.", "Option must not use reserved name \"uninterpreted_option\"."],
847
+ <<~TEXT, label: "here"
848
+ The option has no name, or uses the name protobuf keeps for its own bookkeeping.
849
+
850
+ Name a real option.
851
+ TEXT
852
+
853
+ define "L0502", "unknown option",
854
+ "Option \"%{name}\" unknown. Ensure that your proto definition file imports the proto which defines the option (i.e. via import option after edition 2024).",
855
+ <<~TEXT, title: "unknown option `%{name}`", label: "unknown option", help: "import the file that defines `%{name}`"
856
+ No option of that name is visible. Built-in options are fields of the `*Options` messages in
857
+ descriptor.proto; custom options, written in parentheses, are extensions declared in some file.
858
+
859
+ option (acme.retention_days) = 30;
860
+
861
+ Check the spelling, and import the file that declares the extension.
862
+ TEXT
863
+
864
+ define "L0503", "not a field of the option",
865
+ ["Option field \"%{name}\" is not a field or extension of message \"%{message}\".",
866
+ "Option \"%{name}\" is an atomic type, not a message.",
867
+ "Option field \"%{name}\" is a repeated message. Repeated message options must be initialized using an aggregate value."],
868
+ <<~TEXT, label: "here"
869
+ The option path goes through something that does not have that field: `(opt).a.b` needs `a` to be a
870
+ singular message with a field `b`.
871
+
872
+ Fix the path, or set the whole value with an aggregate: `option (opt) = { a: { b: 1 } };`.
873
+ TEXT
874
+
875
+ define "L0504", "feature used in its own file", "Feature \"%{name}\" can't be used in the same file it's defined in.",
876
+ <<~TEXT, label: "defined in this file"
877
+ A custom feature cannot be used by the file that declares it.
878
+
879
+ Move the declaration to a file of its own and import it.
880
+ TEXT
881
+
882
+ define "L0505", "option set twice", "Option \"%{name}\" was already set.", <<~TEXT, title: "option `%{name}` is set twice", label: "set again", help: "remove one of them"
883
+ The same option is set twice on one element.
884
+
885
+ Remove the duplicate.
886
+ TEXT
887
+
888
+ define "L0506", "option value of the wrong type",
889
+ ["Value must be number for %{type} option \"%{name}\".", "Value must be identifier for boolean option \"%{name}\".",
890
+ "Value must be \"true\" or \"false\" for boolean option \"%{name}\".",
891
+ "Value must be identifier for enum-valued option \"%{name}\".",
892
+ "Value must be quoted string for string option \"%{name}\".",
893
+ "Option \"%{name}\" is a message. To set the entire message, use syntax like \"%{a} = { <proto text format> }\". To set fields within it, use syntax like \"%{b}.foo = value\"."],
894
+ <<~TEXT, label: "wrong type"
895
+ The value does not fit the option's type: numbers for numeric options, `true` or `false` for booleans, a
896
+ value name for enums, a quoted string for strings, an aggregate `{ ... }` for messages.
897
+
898
+ option java_multiple_files = "yes";
899
+
900
+ Write a value of the option's type.
901
+ TEXT
902
+
903
+ define "L0507", "option value out of range",
904
+ ["Value out of range, %{min} to %{max}, for %{type} option \"%{name}\".",
905
+ "Value must be integer, from %{min} to %{max}, for %{type} option \"%{name}\"."],
906
+ <<~TEXT, label: "out of range", help: "use an integer from %{min} to %{max}"
907
+ The number does not fit the option's integer type.
908
+
909
+ Use a value inside the range.
910
+ TEXT
911
+
912
+ define "L0508", "no such enum value for an option",
913
+ ["Enum type \"%{enum}\" has no value named \"%{value}\" for option \"%{name}\". This appears to be a value from a sibling type.",
914
+ "Enum type \"%{enum}\" has no value named \"%{value}\" for option \"%{name}\"."],
915
+ <<~TEXT, title: "`%{enum}` has no value `%{value}`", label: "not a value of `%{enum}`"
916
+ The option is enum-valued, and the value is not one of the enum's.
917
+
918
+ option optimize_for = FAST;
919
+
920
+ Use one of the enum's values (`SPEED`, `CODE_SIZE` or `LITE_RUNTIME` here).
921
+ TEXT
922
+
923
+ define "L0509", "bad aggregate option value", "Error while parsing option value for \"%{name}\": %{error}",
924
+ <<~TEXT, title: "cannot parse the value of `%{name}`", label: "%{error}"
925
+ An aggregate option value `{ ... }` is protobuf text format for the option's message type, and it does not
926
+ parse: an unknown field, a value of the wrong type, a missing brace.
927
+
928
+ option (limits) = { max: "ten" };
929
+
930
+ Fix the text-format value; the message after the colon says what is wrong.
931
+ TEXT
932
+
933
+ # Validator: proto3 and enums
934
+
935
+ define "V0101", "extensions in proto3",
936
+ ["Extension ranges are not allowed in proto3.", "Extensions in proto3 are only allowed for defining options."],
937
+ <<~TEXT, label: "not in proto3"
938
+ proto3 has no extension ranges, and extends only the `*Options` messages to declare custom options. Use
939
+ `google.protobuf.Any`, or editions, for open-ended data.
940
+
941
+ Remove the range or the extension, or move the file to editions.
942
+ TEXT
943
+
944
+ define "V0102", "MessageSet in proto3", "MessageSet is not supported in proto3.", <<~TEXT, label: "message_set_wire_format"
945
+ `message_set_wire_format` is a proto2 legacy option.
946
+
947
+ Remove it, or keep the message in a proto2 file.
948
+ TEXT
949
+
950
+ define "V0103", "required in proto3", "Required fields are not allowed in proto3.", <<~TEXT, label: "required", help: "remove `required`"
951
+ proto3 has no `required` fields: they made schemas impossible to evolve (see
952
+ `protostar lint --explain FIELD_NOT_REQUIRED`).
953
+
954
+ Remove the label and validate presence in code.
955
+ TEXT
956
+
957
+ define "V0104", "default in proto3", "Explicit default values are not allowed in proto3.", <<~TEXT, label: "default", help: "remove the `default`"
958
+ In proto3 the default is always the type's zero value.
959
+
960
+ int32 retries = 1 [default = 3];
961
+
962
+ Remove the option and apply the default in code.
963
+ TEXT
964
+
965
+ define "V0105", "closed enum in proto3",
966
+ "Enum type \"%{enum}\" is not an open enum, but is used in \"%{message}\" which is a proto3 message type.",
967
+ <<~TEXT, title: "closed enum `%{enum}` used in proto3 message `%{message}`", label: "closed enum"
968
+ proto3 messages can only use open enums; proto2 enums are closed, and drop unknown values.
969
+
970
+ Define the enum in a proto3 or editions file, or keep the message in proto2.
971
+ TEXT
972
+
973
+ define "V0106", "groups in proto3", "Groups are not supported in proto3 syntax.", <<~TEXT, label: "group"
974
+ proto3 has no groups.
975
+
976
+ Declare a message type and a field of that type.
977
+ TEXT
978
+
979
+ define "V0107", "first enum value not zero", "The first enum value must be zero for open enums.", <<~TEXT,
980
+ In proto3 and open editions enums the first value must be 0: it is the default every reader sees for an
981
+ unset field and for numbers it does not know.
982
+
983
+ enum Color { RED = 1; }
984
+
985
+ Add a first value `COLOR_UNSPECIFIED = 0;`.
986
+ TEXT
987
+ title: "the first value of an open enum must be zero", label: "not zero", help: "add `UNSPECIFIED = 0;` as the first value"
988
+
989
+ define "V0108", "duplicate enum value number",
990
+ "\"%{name}\" uses the same enum value as \"%{first}\". If this is intended, set 'option allow_alias = true;' to the enum definition.%{next}",
991
+ <<~TEXT, title: "`%{name}` reuses the number of `%{first}`", label: "reused here", help: "set `option allow_alias = true;` if the alias is intended"
992
+ Two values of one enum have the same number. That is an alias, and has to be asked for.
993
+
994
+ enum Status { OK = 0; SUCCESS = 0; }
995
+
996
+ Give the value its own number, or add `option allow_alias = true;`.
997
+ TEXT
998
+
999
+ define "V0109", "enum values clash in JSON",
1000
+ "Enum name %{name} has the same name as %{other} if you ignore case and strip out the enum name prefix (if any). (If you are using allow_alias, please assign the same number to each enum value name.)",
1001
+ <<~TEXT, title: "`%{name}` and `%{other}` clash once the prefix is stripped", label: "clashes with `%{other}`"
1002
+ Some generators strip the enum's name as a prefix and change case, which makes these two values the same.
1003
+
1004
+ Rename one of them.
1005
+ TEXT
1006
+
1007
+ define "V0110", "import kind not allowed in this edition",
1008
+ ["option imports are not supported before edition 2024.", "weak imports are not allowed under edition 2024 and beyond."],
1009
+ <<~TEXT, label: "here"
1010
+ `import option` needs edition 2024 or later, and `import weak` is gone from edition 2024 on.
1011
+
1012
+ Use plain imports before edition 2024 and `import option` from it on.
1013
+ TEXT
1014
+
1015
+ define "V0201", "invalid json_name",
1016
+ "The custom JSON name of field \"%{field}\" (\"%{name}\") is invalid: JSON names may not start with '[' and end with ']'.",
1017
+ <<~TEXT, label: "invalid"
1018
+ `[name]` in JSON is how extensions are written, so a field cannot claim it.
1019
+
1020
+ Choose another `json_name`.
1021
+ TEXT
1022
+
1023
+ define "V0203", "json_name not allowed",
1024
+ ["option json_name is not allowed on extension fields.", "json_name cannot have embedded null characters."],
1025
+ <<~TEXT, label: "json_name"
1026
+ Extensions are written in JSON as `[full.name]`, so they take no `json_name`; and a JSON name cannot contain
1027
+ a NUL character.
1028
+
1029
+ Remove the option, or the NUL.
1030
+ TEXT
1031
+
1032
+ define "V0202", "JSON names clash",
1033
+ "The %{kind} JSON name of field \"%{field}\" (\"%{name}\") conflicts with the %{other_kind} JSON name of field \"%{other}\"%{suffix}.",
1034
+ <<~TEXT, title: "`%{field}` and `%{other}` have the same JSON name `%{name}`", label: "clashes"
1035
+ Two fields of one message map to the same JSON key, so JSON could not tell them apart. The default JSON
1036
+ name is the field name in lowerCamelCase: `foo_bar` and `fooBar` are both `fooBar`.
1037
+
1038
+ message A {
1039
+ int32 foo_bar = 1;
1040
+ int32 fooBar = 2;
1041
+ }
1042
+
1043
+ Rename one field (fields are lower_snake_case), or give one a distinct `json_name`.
1044
+ TEXT
1045
+
1046
+ # Validator: extensions
1047
+
1048
+ define "V0301", "unverified range with declarations",
1049
+ "Cannot mark the extension range as UNVERIFIED when it has extension(s) declared.", <<~TEXT
1050
+ An extension range with `declaration`s is verified by definition.
1051
+
1052
+ Remove `verification = UNVERIFIED`, or the declarations.
1053
+ TEXT
1054
+
1055
+ define "V0302", "bad extension declaration",
1056
+ ["Extension declaration number %{number} is not in the extension range.",
1057
+ "Extension declaration number %{number} is declared multiple times.",
1058
+ "Extension declaration #%{number} should have both \"full_name\" and \"type\" set.",
1059
+ "Extension field name \"%{name}\" is declared multiple times.",
1060
+ "\"%{name}\" must have a leading dot to indicate the fully-qualified scope.",
1061
+ "\"%{name}\" contains invalid identifiers."], <<~TEXT
1062
+ An extension range's `declaration`s must each name a number inside the range once, with a fully
1063
+ qualified `full_name` (leading dot) and a `type`.
1064
+
1065
+ Fix the declaration.
1066
+ TEXT
1067
+
1068
+ define "V0303", "extension does not match its declaration",
1069
+ ["Cannot use number %{number} for extension field %{field}, as it is reserved in the extension declarations for message %{message}.",
1070
+ "Missing extension declaration for field %{field} with number %{number} in extendee message %{message}. An extension range must declare for all extension fields if its verification state is DECLARATION or there's any declaration in the range already. Otherwise, consider splitting up the range.",
1071
+ "\"%{extendee}\" extension field %{number} is expected to be type \"%{type}\", not \"%{actual}\".",
1072
+ "\"%{extendee}\" extension field %{number} is expected to have field name \"%{name}\", not \"%{actual}\".",
1073
+ "\"%{extendee}\" extension field %{number} is expected to be %{label}."], <<~TEXT
1074
+ The extended message declares which extensions may use its numbers, and this one does not match: the
1075
+ number is reserved, undeclared, or declared with another name, type or label.
1076
+
1077
+ Use the declared name, type and label, or another number.
1078
+ TEXT
1079
+
1080
+ define "V0304", "MessageSet misuse",
1081
+ ["Extensions of MessageSets must be optional messages.", "MessageSets cannot have fields, only extensions."],
1082
+ <<~TEXT
1083
+ A MessageSet holds only optional message extensions.
1084
+
1085
+ Remove the field, or make the extension an optional message.
1086
+ TEXT
1087
+
1088
+ define "V0305", "lite runtime mismatch",
1089
+ ["Extensions to non-lite types can only be declared in non-lite files. Note that you cannot extend a non-lite type to contain a lite type, but the reverse is allowed.",
1090
+ "Files that do not use optimize_for = LITE_RUNTIME cannot import files which do use this option. This file is not lite, but it imports \"%{import}\" which is.",
1091
+ "Files with optimize_for = LITE_RUNTIME cannot define services unless you set both options cc_generic_services and java_generic_services to false."],
1092
+ <<~TEXT
1093
+ `optimize_for = LITE_RUNTIME` files generate code for the lite runtime, which full-runtime files cannot
1094
+ depend on.
1095
+
1096
+ Use the same `optimize_for` in files that depend on each other.
1097
+ TEXT
1098
+
1099
+ # Validator: options and features
1100
+
1101
+ define "V0401", "lazy on the wrong field",
1102
+ ["[lazy = true] can only be specified for submessage fields.", "Extensions cannot be marked as unverified_lazy."],
1103
+ <<~TEXT, label: "lazy"
1104
+ Only message fields can be parsed lazily.
1105
+
1106
+ Remove the option.
1107
+ TEXT
1108
+
1109
+ define "V0402", "packed on the wrong field", "[packed = true] can only be specified for repeated primitive fields.",
1110
+ <<~TEXT, label: "packed"
1111
+ Only repeated numeric, enum and bool fields can be packed.
1112
+
1113
+ Remove the option.
1114
+ TEXT
1115
+
1116
+ define "V0403", "jstype on the wrong field",
1117
+ ["Illegal jstype for int64, uint64, sint64, fixed64 or sfixed64 field: %{jstype}",
1118
+ "jstype is only allowed on int64, uint64, sint64, fixed64 or sfixed64 fields."], <<~TEXT, label: "jstype"
1119
+ `jstype` chooses how JavaScript represents a 64-bit integer field, and applies to nothing else.
1120
+
1121
+ Remove the option.
1122
+ TEXT
1123
+
1124
+ define "V0404", "option on the wrong element", "Option %{option} cannot be set on an entity of type `%{type}`.",
1125
+ <<~TEXT, title: "option `%{option}` cannot be set on a %{type}"
1126
+ The option's declaration lists the kinds of element it may be set on (`targets`), and this is not one.
1127
+
1128
+ Move the option to an element it targets.
1129
+ TEXT
1130
+
1131
+ define "V0405", "ctype under edition 2024",
1132
+ "ctype option is not allowed under edition 2024 and beyond. Use the feature string_type = VIEW|CORD|STRING|... instead.",
1133
+ <<~TEXT, label: "ctype"
1134
+ From edition 2024 the C++ string type is a feature.
1135
+
1136
+ Write `[features.(pb.cpp).string_type = CORD]` instead.
1137
+ TEXT
1138
+
1139
+ define "V0501", "proto2 construct in editions",
1140
+ ["Required label is not allowed under editions. Use the feature field_presence = LEGACY_REQUIRED to control this behavior.",
1141
+ "Group types are not allowed under editions. Use the feature message_encoding = DELIMITED to control this behavior.",
1142
+ "Field option packed is not allowed under editions. Use the repeated_field_encoding feature to control this behavior.",
1143
+ "File option java_string_check_utf8 is not allowed under editions. Use the (pb.java).utf8_validation feature to control this behavior."],
1144
+ <<~TEXT, label: "here"
1145
+ Under editions these behaviours are features rather than labels and options.
1146
+
1147
+ Use the feature the message names.
1148
+ TEXT
1149
+
1150
+ define "V0502", "field presence feature misuse",
1151
+ ["Required presence can't be specified by default.", "Implicit presence fields can't specify defaults.",
1152
+ "Implicit presence enum fields must always be open.", "Oneof fields can't specify field presence.",
1153
+ "Repeated fields can't specify field presence.", "Extensions can't specify field presence.",
1154
+ "Message fields can't specify implicit presence."], <<~TEXT, label: "here"
1155
+ `field_presence` applies to singular, non-oneof, non-extension fields; `IMPLICIT` presence has no defaults,
1156
+ does not work for messages, and needs open enums; `LEGACY_REQUIRED` cannot be a file default.
1157
+
1158
+ Remove the feature from this field.
1159
+ TEXT
1160
+
1161
+ define "V0503", "encoding feature on the wrong field",
1162
+ ["Only repeated fields can specify repeated field encoding.", "Only string fields can specify utf8 validation.",
1163
+ "Only repeated primitive fields can specify PACKED repeated field encoding.",
1164
+ "Only message fields can specify message encoding."], <<~TEXT, label: "here"
1165
+ Each encoding feature applies to one kind of field.
1166
+
1167
+ Remove the feature from this field.
1168
+ TEXT
1169
+
1170
+ define "V0504", "bad feature support declaration",
1171
+ ["%{name} was deprecated before it was introduced.", "%{name} is deprecated but does not specify a deprecation warning.",
1172
+ "%{name} specifies a deprecation warning but is not marked deprecated in any edition.",
1173
+ "%{name} was deprecated after it was removed.", "%{name} was removed before it was introduced.",
1174
+ "%{name} has been removed but does not specify a removal error.",
1175
+ "%{name} specifies a removal error but is not marked removed in any edition."], <<~TEXT
1176
+ A feature's `feature_support` must be consistent: introduced, then deprecated with a warning, then removed
1177
+ with an error.
1178
+
1179
+ Fix the declaration's editions and messages.
1180
+ TEXT
1181
+
1182
+ define "V0505", "feature not yet introduced",
1183
+ "%{name} wasn't introduced until edition %{introduced} and can't be used in edition %{edition}", <<~TEXT,
1184
+ The feature or option is newer than the file's edition.
1185
+
1186
+ Move the file to that edition or a later one, or remove it.
1187
+ TEXT
1188
+ title: "`%{name}` needs edition %{introduced}", label: "not in edition %{edition}"
1189
+
1190
+ define "V0506", "feature removed", "%{name} has been removed in edition %{removed}%{reason}", <<~TEXT,
1191
+ The feature or option was removed in the file's edition.
1192
+
1193
+ Remove it; the removal message says what replaces it.
1194
+ TEXT
1195
+ title: "`%{name}` was removed in edition %{removed}", label: "removed"
1196
+
1197
+ define "V0507", "feature deprecated", "%{name} has been deprecated in edition %{deprecated}: %{reason}", <<~TEXT,
1198
+ The feature or option is deprecated in the file's edition and will be removed in a later one.
1199
+
1200
+ Follow the deprecation message. `NO_DEPRECATED_FEATURES` is the lint rule for these.
1201
+ TEXT
1202
+ title: "`%{name}` is deprecated since edition %{deprecated}", label: "deprecated", note: "%{reason}"
1203
+
1204
+ define "V0508", "edition too new",
1205
+ "is a file using edition %{edition}, which is later than the protoc maximum supported edition 2026.", <<~TEXT
1206
+ The file uses an edition newer than protoc 36.2 supports.
1207
+
1208
+ Use edition 2026 or earlier.
1209
+ TEXT
1210
+
1211
+ define "V0601", "map entry misuse",
1212
+ ["map_entry should not be set explicitly. Use map<KeyType, ValueType> instead.",
1213
+ "Groups cannot be map entries. Use a regular message field with map<KeyType, ValueType> syntax instead.",
1214
+ "%{type} is a synthetic MapEntry message type, which is not allowed to be used as a field type.%{hint}"],
1215
+ <<~TEXT, label: "here"
1216
+ Map entry messages are made by the compiler for `map<K, V>` fields; they cannot be written or used by hand.
1217
+
1218
+ message A { map<string, int32> m = 1; MEntry e = 2; }
1219
+
1220
+ Use `map<K, V>`.
1221
+ TEXT
1222
+
1223
+ define "V0602", "bad map key", ["Key in map fields cannot be enum types.", "Key in map fields cannot be float/double, bytes or message types."],
1224
+ <<~TEXT, label: "invalid key type", help: "use a string or integer key"
1225
+ Map keys are integers, bools or strings.
1226
+
1227
+ map<Color, int32> counts = 1;
1228
+
1229
+ Use a string or integer key; for enums, the value's name or number.
1230
+ TEXT
1231
+
1232
+ define "V0603", "map enum value without zero", "Enum value in map must define 0 as the first value.", <<~TEXT, label: "enum"
1233
+ A map value that is an enum needs 0 as its first value, the value a missing entry reads as.
1234
+
1235
+ Add a zero value first.
1236
+ TEXT
1237
+
1238
+ define "V0604", "map entry name clash", "Expanded map entry type %{type} conflicts with an existing %{what}.",
1239
+ <<~TEXT, title: "map entry `%{type}` clashes with an existing %{what}"
1240
+ A `map<K, V> foo_bar` field makes a nested message `FooBarEntry`, and the message already has something of
1241
+ that name.
1242
+
1243
+ Rename the field or the other declaration.
1244
+ TEXT
1245
+
1246
+ # Validator: protoc's command-line checks
1247
+
1248
+ define "V0701", "naming style",
1249
+ ["Package name %{name} %{problem}", "%{kind} name %{name} %{problem}", "Enum value name %{name} %{problem}"],
1250
+ <<~TEXT, label: "here"
1251
+ The file opted into `features.enforce_naming_style` (STYLE2024, the default from edition 2024): packages
1252
+ and fields lower_snake_case, messages, enums, services and methods TitleCase, enum values
1253
+ UPPER_SNAKE_CASE.
1254
+
1255
+ edition = "2024";
1256
+ message user_profile {}
1257
+
1258
+ Rename, or opt out with `option features.enforce_naming_style = STYLE_LEGACY;`.
1259
+ TEXT
1260
+
1261
+ define "V0702", "proto limits",
1262
+ ["Message name %{name} should not contain more than %{limit} fields%{rest}",
1263
+ "Message name %{name} should not contain more than %{limit} oneofs%{rest}",
1264
+ "Oneof name %{name} should not contain more than %{limit} fields%{rest}",
1265
+ "Enum name %{name} should not contain more than %{limit} values%{rest}"], <<~TEXT, label: "too large"
1266
+ Edition 2024 limits how many fields, oneofs and values one message, oneof or enum may have.
1267
+
1268
+ Split it, or opt out with `option features.enforce_proto_limits = LEGACY_NO_EXPLICIT_LIMITS;`.
1269
+ TEXT
1270
+
1271
+ define "V0703", "unused import", "Import %{import} is unused.", <<~TEXT,
1272
+ Nothing in the file uses a name from the imported file. Unused imports slow builds and hide real
1273
+ dependencies.
1274
+
1275
+ Remove the import. `IMPORT_USED` is the lint rule for these.
1276
+ TEXT
1277
+ title: "unused import `%{import}`", label: "unused", help: "remove the import"
1278
+
1279
+ define "V0704", "generic services",
1280
+ "Generic services (cc_generic_services, java_generic_services, and py_generic_services) are deprecated in favor of using plugins that generate code specific to your particular RPC system. Additional code generator options may be required to enable generic services and total removal of these options is planned in future breaking releases.",
1281
+ <<~TEXT, title: "generic services are deprecated", help: "remove the *_generic_services options and use a gRPC plugin"
1282
+ The `*_generic_services` options generate RPC stubs that no RPC system uses any more.
1283
+
1284
+ Remove the options and generate stubs with your RPC system's plugin.
1285
+ TEXT
1286
+
1287
+ define "V0705", "reserved field numbers",
1288
+ "Field numbers 19000 through 19999 are reserved for the protocol buffer library implementation.", <<~TEXT
1289
+ Numbers 19000 to 19999 belong to the protobuf implementation.
1290
+
1291
+ Use another number.
1292
+ TEXT
1293
+
1294
+ define "V0706", "export of a nested type",
1295
+ ["\"%{name}\" is a nested message and cannot be `export` with STRICT default_symbol_visibility. It must be moved to top-level, ideally in its own file in order to be `export`.",
1296
+ "\"%{name}\" is a nested enum and cannot be marked `export` with STRICT default_symbol_visibility. It must be moved to top-level, ideally in its own file in order to be `export`. For C++ namespacing of enums in a messages use: `local message <OuterNamespace> { export enum %{enum} {...} reserved 1 to max; }`"],
1297
+ <<~TEXT, title: "nested `%{name}` cannot be exported under STRICT visibility"
1298
+ With `default_symbol_visibility = STRICT` only top-level types can be exported.
1299
+
1300
+ Move the type to the top level.
1301
+ TEXT
1302
+
1303
+ ENTRIES.freeze
1304
+ BY_CODE = ENTRIES.to_h { |e| [e.code, e] }.freeze
1305
+ end
1306
+ end
1307
+ end