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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +60 -0
- data/LICENSE.txt +21 -0
- data/README.md +647 -0
- data/THIRD_PARTY_NOTICES.md +61 -0
- data/exe/protoc-gen-protostar +7 -0
- data/exe/protostar +7 -0
- data/lib/protostar/builder/generator.rb +71 -0
- data/lib/protostar/builder/sink.rb +35 -0
- data/lib/protostar/builder.rb +965 -0
- data/lib/protostar/cli.rb +267 -0
- data/lib/protostar/codec/decode_generator.rb +199 -0
- data/lib/protostar/codec/decoder.rb +296 -0
- data/lib/protostar/codec/encode_generator.rb +224 -0
- data/lib/protostar/codec/encoder.rb +121 -0
- data/lib/protostar/codec/sizer.rb +91 -0
- data/lib/protostar/codec.rb +15 -0
- data/lib/protostar/compiler/ast.rb +193 -0
- data/lib/protostar/compiler/emitters/descriptor_set.rb +57 -0
- data/lib/protostar/compiler/emitters/google_ruby.rb +103 -0
- data/lib/protostar/compiler/emitters/grpc.rb +175 -0
- data/lib/protostar/compiler/emitters/protostar_rbs.rb +252 -0
- data/lib/protostar/compiler/emitters/rbs.rb +394 -0
- data/lib/protostar/compiler/emitters/ruby.rb +503 -0
- data/lib/protostar/compiler/emitters.rb +268 -0
- data/lib/protostar/compiler/include/LICENSE +32 -0
- data/lib/protostar/compiler/include/google/protobuf/any.proto +106 -0
- data/lib/protostar/compiler/include/google/protobuf/api.proto +229 -0
- data/lib/protostar/compiler/include/google/protobuf/compiler/plugin.proto +180 -0
- data/lib/protostar/compiler/include/google/protobuf/cpp_features.proto +87 -0
- data/lib/protostar/compiler/include/google/protobuf/descriptor.proto +1532 -0
- data/lib/protostar/compiler/include/google/protobuf/duration.proto +115 -0
- data/lib/protostar/compiler/include/google/protobuf/empty.proto +51 -0
- data/lib/protostar/compiler/include/google/protobuf/field_mask.proto +243 -0
- data/lib/protostar/compiler/include/google/protobuf/java_features.proto +132 -0
- data/lib/protostar/compiler/include/google/protobuf/source_context.proto +48 -0
- data/lib/protostar/compiler/include/google/protobuf/struct.proto +111 -0
- data/lib/protostar/compiler/include/google/protobuf/timestamp.proto +145 -0
- data/lib/protostar/compiler/include/google/protobuf/type.proto +217 -0
- data/lib/protostar/compiler/include/google/protobuf/wrappers.proto +157 -0
- data/lib/protostar/compiler/lexer.rb +659 -0
- data/lib/protostar/compiler/linker.rb +894 -0
- data/lib/protostar/compiler/option_interpreter.rb +363 -0
- data/lib/protostar/compiler/parser.rb +1696 -0
- data/lib/protostar/compiler/retention.rb +104 -0
- data/lib/protostar/compiler/run.rb +184 -0
- data/lib/protostar/compiler/source_info.rb +161 -0
- data/lib/protostar/compiler/symbol_table.rb +223 -0
- data/lib/protostar/compiler/text_format.rb +340 -0
- data/lib/protostar/compiler/validator.rb +944 -0
- data/lib/protostar/compiler.rb +304 -0
- data/lib/protostar/diagnostics/codes.rb +1307 -0
- data/lib/protostar/diagnostics/formats.rb +64 -0
- data/lib/protostar/diagnostics/renderer.rb +240 -0
- data/lib/protostar/diagnostics/source.rb +153 -0
- data/lib/protostar/diagnostics.rb +117 -0
- data/lib/protostar/dsl.rb +367 -0
- data/lib/protostar/enum.rb +70 -0
- data/lib/protostar/errors.rb +23 -0
- data/lib/protostar/google/protobuf/any_pb.rb +90 -0
- data/lib/protostar/google/protobuf/api_pb.rb +199 -0
- data/lib/protostar/google/protobuf/compiler/plugin_pb.rb +168 -0
- data/lib/protostar/google/protobuf/descriptor_pb.rb +1239 -0
- data/lib/protostar/google/protobuf/duration_pb.rb +99 -0
- data/lib/protostar/google/protobuf/empty_pb.rb +36 -0
- data/lib/protostar/google/protobuf/field_mask_pb.rb +228 -0
- data/lib/protostar/google/protobuf/source_context_pb.rb +33 -0
- data/lib/protostar/google/protobuf/struct_pb.rb +91 -0
- data/lib/protostar/google/protobuf/timestamp_pb.rb +129 -0
- data/lib/protostar/google/protobuf/type_pb.rb +202 -0
- data/lib/protostar/google/protobuf/wrappers_pb.rb +125 -0
- data/lib/protostar/google_protobuf_shim.rb +24 -0
- data/lib/protostar/json/encoder.rb +340 -0
- data/lib/protostar/json/errors.rb +34 -0
- data/lib/protostar/json/parser.rb +437 -0
- data/lib/protostar/json/path.rb +39 -0
- data/lib/protostar/json.rb +95 -0
- data/lib/protostar/lint/command.rb +197 -0
- data/lib/protostar/lint/config.rb +98 -0
- data/lib/protostar/lint/context.rb +126 -0
- data/lib/protostar/lint/directives.rb +56 -0
- data/lib/protostar/lint/fixer.rb +165 -0
- data/lib/protostar/lint/naming.rb +54 -0
- data/lib/protostar/lint/rule.rb +120 -0
- data/lib/protostar/lint/rules/comment_enum.rb +31 -0
- data/lib/protostar/lint/rules/comment_enum_value.rb +32 -0
- data/lib/protostar/lint/rules/comment_field.rb +33 -0
- data/lib/protostar/lint/rules/comment_message.rb +31 -0
- data/lib/protostar/lint/rules/comment_rpc.rb +31 -0
- data/lib/protostar/lint/rules/comment_service.rb +31 -0
- data/lib/protostar/lint/rules/edition_recommended.rb +31 -0
- data/lib/protostar/lint/rules/enum_first_value_zero.rb +34 -0
- data/lib/protostar/lint/rules/enum_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/enum_value_prefix.rb +38 -0
- data/lib/protostar/lint/rules/enum_value_upper_snake_case.rb +28 -0
- data/lib/protostar/lint/rules/enum_zero_value_suffix.rb +41 -0
- data/lib/protostar/lint/rules/field_lower_snake_case.rb +34 -0
- data/lib/protostar/lint/rules/field_not_required.rb +39 -0
- data/lib/protostar/lint/rules/field_number_reuse_risk.rb +45 -0
- data/lib/protostar/lint/rules/field_numbers_hot_range.rb +44 -0
- data/lib/protostar/lint/rules/file_lower_snake_case.rb +27 -0
- data/lib/protostar/lint/rules/import_no_public.rb +29 -0
- data/lib/protostar/lint/rules/import_no_weak.rb +28 -0
- data/lib/protostar/lint/rules/import_used.rb +33 -0
- data/lib/protostar/lint/rules/message_pascal_case.rb +27 -0
- data/lib/protostar/lint/rules/no_deprecated_features.rb +50 -0
- data/lib/protostar/lint/rules/no_groups.rb +34 -0
- data/lib/protostar/lint/rules/oneof_lower_snake_case.rb +27 -0
- data/lib/protostar/lint/rules/package_defined.rb +28 -0
- data/lib/protostar/lint/rules/package_directory_match.rb +33 -0
- data/lib/protostar/lint/rules/package_lower_snake_case.rb +28 -0
- data/lib/protostar/lint/rules/package_same_directory.rb +39 -0
- data/lib/protostar/lint/rules/package_version_suffix.rb +31 -0
- data/lib/protostar/lint/rules/reserved_names_with_numbers.rb +44 -0
- data/lib/protostar/lint/rules/rpc_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/rpc_request_response_unique.rb +40 -0
- data/lib/protostar/lint/rules/rpc_request_standard_name.rb +32 -0
- data/lib/protostar/lint/rules/rpc_response_standard_name.rb +31 -0
- data/lib/protostar/lint/rules/service_pascal_case.rb +25 -0
- data/lib/protostar/lint/rules/service_suffix.rb +28 -0
- data/lib/protostar/lint/rules/syntax_specified.rb +35 -0
- data/lib/protostar/lint/runner.rb +135 -0
- data/lib/protostar/lint.rb +122 -0
- data/lib/protostar/message/accessors.rb +86 -0
- data/lib/protostar/message/coercion.rb +171 -0
- data/lib/protostar/message/field_info.rb +145 -0
- data/lib/protostar/message/reflection.rb +149 -0
- data/lib/protostar/message.rb +572 -0
- data/lib/protostar/plugin.rb +94 -0
- data/lib/protostar/schema/default_value.rb +113 -0
- data/lib/protostar/schema/descriptor.rb +41 -0
- data/lib/protostar/schema/draft/copy.rb +88 -0
- data/lib/protostar/schema/draft/resolution.rb +177 -0
- data/lib/protostar/schema/draft.rb +779 -0
- data/lib/protostar/schema/enum.rb +106 -0
- data/lib/protostar/schema/extension_range.rb +37 -0
- data/lib/protostar/schema/features.rb +153 -0
- data/lib/protostar/schema/field.rb +201 -0
- data/lib/protostar/schema/file.rb +217 -0
- data/lib/protostar/schema/freezer.rb +61 -0
- data/lib/protostar/schema/message.rb +104 -0
- data/lib/protostar/schema/oneof.rb +38 -0
- data/lib/protostar/schema/options.rb +367 -0
- data/lib/protostar/schema/pool.rb +179 -0
- data/lib/protostar/schema/proto.rb +576 -0
- data/lib/protostar/schema/resolver.rb +118 -0
- data/lib/protostar/schema/service.rb +89 -0
- data/lib/protostar/schema/source_info.rb +53 -0
- data/lib/protostar/schema.rb +65 -0
- data/lib/protostar/short_names/any.rb +7 -0
- data/lib/protostar/short_names/duration.rb +7 -0
- data/lib/protostar/short_names/empty.rb +7 -0
- data/lib/protostar/short_names/field_mask.rb +7 -0
- data/lib/protostar/short_names/struct.rb +9 -0
- data/lib/protostar/short_names/timestamp.rb +7 -0
- data/lib/protostar/short_names/wrappers.rb +15 -0
- data/lib/protostar/text/extensions.rb +114 -0
- data/lib/protostar/text/parser.rb +439 -0
- data/lib/protostar/text/printer.rb +304 -0
- data/lib/protostar/text/tokenizer.rb +116 -0
- data/lib/protostar/text.rb +67 -0
- data/lib/protostar/types.rb +152 -0
- data/lib/protostar/unknown_field.rb +58 -0
- data/lib/protostar/version.rb +5 -0
- data/lib/protostar/view/generator.rb +298 -0
- data/lib/protostar/view/map.rb +194 -0
- data/lib/protostar/view/repeated.rb +143 -0
- data/lib/protostar/view/scan.rb +183 -0
- data/lib/protostar/view.rb +283 -0
- data/lib/protostar/well_known/any.rb +52 -0
- data/lib/protostar/well_known/duration.rb +53 -0
- data/lib/protostar/well_known/list_value.rb +63 -0
- data/lib/protostar/well_known/struct.rb +55 -0
- data/lib/protostar/well_known/timestamp.rb +64 -0
- data/lib/protostar/well_known/value.rb +60 -0
- data/lib/protostar/well_known.rb +38 -0
- data/lib/protostar/wire/io_source.rb +40 -0
- data/lib/protostar/wire/reader.rb +254 -0
- data/lib/protostar/wire/writer.rb +201 -0
- data/lib/protostar/wire.rb +96 -0
- data/lib/protostar.rb +95 -0
- data/shims/google-protobuf/lib/google/protobuf/any_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/api_pb.rb +22 -0
- data/shims/google-protobuf/lib/google/protobuf/compiler/plugin_pb.rb +25 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptor_pb.rb +72 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptor_pool.rb +164 -0
- data/shims/google-protobuf/lib/google/protobuf/descriptors.rb +553 -0
- data/shims/google-protobuf/lib/google/protobuf/duration_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/empty_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/field_mask_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/convert.rb +180 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/extensions.rb +154 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/json.rb +104 -0
- data/shims/google-protobuf/lib/google/protobuf/internal/well_known.rb +140 -0
- data/shims/google-protobuf/lib/google/protobuf/map.rb +216 -0
- data/shims/google-protobuf/lib/google/protobuf/message.rb +544 -0
- data/shims/google-protobuf/lib/google/protobuf/message_exts.rb +41 -0
- data/shims/google-protobuf/lib/google/protobuf/plugin_pb.rb +4 -0
- data/shims/google-protobuf/lib/google/protobuf/repeated_field.rb +366 -0
- data/shims/google-protobuf/lib/google/protobuf/source_context_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/struct_pb.rb +20 -0
- data/shims/google-protobuf/lib/google/protobuf/timestamp_pb.rb +17 -0
- data/shims/google-protobuf/lib/google/protobuf/type_pb.rb +27 -0
- data/shims/google-protobuf/lib/google/protobuf/well_known_types.rb +37 -0
- data/shims/google-protobuf/lib/google/protobuf/wrappers_pb.rb +25 -0
- data/shims/google-protobuf/lib/google/protobuf.rb +107 -0
- data/shims/google-protobuf/lib/google/protobuf_ffi.rb +5 -0
- data/shims/google-protobuf/lib/google/protobuf_native.rb +5 -0
- data/sig/protostar/google/protobuf/any_pb.rbs +77 -0
- data/sig/protostar/google/protobuf/api_pb.rbs +242 -0
- data/sig/protostar/google/protobuf/compiler/plugin_pb.rbs +264 -0
- data/sig/protostar/google/protobuf/descriptor_pb.rbs +2220 -0
- data/sig/protostar/google/protobuf/duration_pb.rbs +82 -0
- data/sig/protostar/google/protobuf/empty_pb.rbs +18 -0
- data/sig/protostar/google/protobuf/field_mask_pb.rbs +170 -0
- data/sig/protostar/google/protobuf/source_context_pb.rbs +24 -0
- data/sig/protostar/google/protobuf/struct_pb.rbs +135 -0
- data/sig/protostar/google/protobuf/timestamp_pb.rbs +102 -0
- data/sig/protostar/google/protobuf/type_pb.rbs +304 -0
- data/sig/protostar/google/protobuf/wrappers_pb.rbs +169 -0
- data/sig/protostar/lint.rbs +216 -0
- data/sig/protostar.rbs +326 -0
- 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
|