Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-22 08:53:15

0001 // Protocol Buffers - Google's data interchange format
0002 // Copyright 2024 Google LLC.  All rights reserved.
0003 //
0004 // Use of this source code is governed by a BSD-style
0005 // license that can be found in the LICENSE file or at
0006 // https://developers.google.com/open-source/licenses/bsd
0007 
0008 // Author: kenton@google.com (Kenton Varda)
0009 //  Based on original Protocol Buffers design by
0010 //  Sanjay Ghemawat, Jeff Dean, and others.
0011 //
0012 // Utility class for writing text to a ZeroCopyOutputStream.
0013 
0014 #ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
0015 #define GOOGLE_PROTOBUF_IO_PRINTER_H__
0016 
0017 #include <cstddef>
0018 #include <functional>
0019 #include <initializer_list>
0020 #include <optional>
0021 #include <string>
0022 #include <type_traits>
0023 #include <utility>
0024 #include <variant>
0025 #include <vector>
0026 
0027 #include "absl/cleanup/cleanup.h"
0028 #include "absl/container/flat_hash_map.h"
0029 #include "absl/functional/any_invocable.h"
0030 #include "absl/functional/function_ref.h"
0031 #include "absl/log/absl_check.h"
0032 #include "absl/meta/type_traits.h"
0033 #include "absl/strings/str_cat.h"
0034 #include "absl/strings/str_format.h"
0035 #include "absl/strings/string_view.h"
0036 #include "absl/types/span.h"
0037 #include "google/protobuf/io/zero_copy_sink.h"
0038 #include "google/protobuf/io/zero_copy_stream.h"
0039 
0040 
0041 // Must be included last.
0042 #include "google/protobuf/port_def.inc"
0043 
0044 namespace google {
0045 namespace protobuf {
0046 namespace io {
0047 
0048 // Records annotations about a Printer's output.
0049 class PROTOBUF_EXPORT AnnotationCollector {
0050  public:
0051   // Annotation is a offset range and a payload pair. This payload's layout is
0052   // specific to derived types of AnnotationCollector.
0053   using Annotation = std::pair<std::pair<size_t, size_t>, std::string>;
0054 
0055   // The semantic meaning of an annotation. This enum mirrors
0056   // google.protobuf.GeneratedCodeInfo.Annotation.Semantic, and the enumerator values
0057   // should match it.
0058   enum Semantic {
0059     kNone = 0,
0060     kSet = 1,
0061     kAlias = 2,
0062   };
0063 
0064   virtual ~AnnotationCollector() = default;
0065 
0066   // Records that the bytes in file_path beginning with begin_offset and ending
0067   // before end_offset are associated with the SourceCodeInfo-style path.
0068   virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
0069                              const std::string& file_path,
0070                              const std::vector<int>& path) = 0;
0071 
0072   virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
0073                              const std::string& file_path,
0074                              const std::vector<int>& path,
0075                              std::optional<Semantic> semantic) {
0076     AddAnnotation(begin_offset, end_offset, file_path, path);
0077   }
0078 
0079   // TODO I don't see why we need virtuals here. Just a vector of
0080   // range, payload pairs stored in a context should suffice.
0081   virtual void AddAnnotationNew(Annotation&) {}
0082 };
0083 
0084 // Records annotations about a Printer's output to a Protobuf message,
0085 // assuming that it has a repeated submessage field named `annotation` with
0086 // fields matching
0087 //
0088 // message ??? {
0089 //   repeated int32 path = 1;
0090 //   optional string source_file = 2;
0091 //   optional int32 begin = 3;
0092 //   optional int32 end = 4;
0093 //   optional int32 semantic = 5;
0094 // }
0095 template <typename AnnotationProto>
0096 class AnnotationProtoCollector : public AnnotationCollector {
0097  private:
0098   // Some users of this type use it with a proto that does not have a
0099   // "semantic" field. Therefore, we need to detect it with SFINAE.
0100 
0101   // go/ranked-overloads
0102   struct Rank0 {};
0103   struct Rank1 : Rank0 {};
0104 
0105   template <typename Proto>
0106   static auto SetSemantic(Proto* p, int semantic, Rank1)
0107       -> decltype(p->set_semantic(
0108           static_cast<typename Proto::Semantic>(semantic))) {
0109     return p->set_semantic(static_cast<typename Proto::Semantic>(semantic));
0110   }
0111 
0112   template <typename Proto>
0113   static void SetSemantic(Proto*, int, Rank0) {}
0114 
0115  public:
0116   explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
0117       : annotation_proto_(annotation_proto) {}
0118 
0119   void AddAnnotation(size_t begin_offset, size_t end_offset,
0120                      const std::string& file_path,
0121                      const std::vector<int>& path) override {
0122     AddAnnotation(begin_offset, end_offset, file_path, path, std::nullopt);
0123   }
0124 
0125   void AddAnnotation(size_t begin_offset, size_t end_offset,
0126                      const std::string& file_path, const std::vector<int>& path,
0127                      std::optional<Semantic> semantic) override {
0128     auto* annotation = annotation_proto_->add_annotation();
0129     for (const int segment : path) {
0130       annotation->add_path(segment);
0131     }
0132     annotation->set_source_file(file_path);
0133     annotation->set_begin(begin_offset);
0134     annotation->set_end(end_offset);
0135 
0136     if (semantic.has_value()) {
0137       SetSemantic(annotation, *semantic, Rank1{});
0138     }
0139   }
0140 
0141   void AddAnnotationNew(Annotation& a) override {
0142     auto* annotation = annotation_proto_->add_annotation();
0143     annotation->ParseFromString(a.second);
0144     annotation->set_begin(a.first.first);
0145     annotation->set_end(a.first.second);
0146   }
0147 
0148  private:
0149   AnnotationProto* annotation_proto_;
0150 };
0151 
0152 // A source code printer for assisting in code generation.
0153 //
0154 // This type implements a simple templating language for substituting variables
0155 // into static, user-provided strings, and also tracks indentation
0156 // automatically.
0157 //
0158 // The main entry-point for this type is the Emit function, which can be used
0159 // as thus:
0160 //
0161 //   Printer p(output);
0162 //   p.Emit({{"class", my_class_name}}, R"cc(
0163 //     class $class$ {
0164 //      public:
0165 //       $class$(int x) : x_(x) {}
0166 //      private:
0167 //       int x_;
0168 //     };
0169 //   )cc");
0170 //
0171 // Substitutions are of the form $var$, which is looked up in the map passed in
0172 // as the first argument. The variable delimiter character, $, can be chosen to
0173 // be something convenient for the target language. For example, in PHP, which
0174 // makes heavy use of $, it can be made into something like # instead.
0175 //
0176 // A literal $ can be emitted by writing $$.
0177 //
0178 // Substitutions may contain spaces around the name of the variable, which will
0179 // be ignored for the purposes of looking up the variable to substitute in, but
0180 // which will be reproduced in the output:
0181 //
0182 //   p.Emit({{"foo", "bar"}}, "$ foo $");
0183 //
0184 // emits the string " bar ". If the substituted-in variable is the empty string,
0185 // then the surrounding spaces are *not* printed:
0186 //
0187 //   p.Emit({{"xyz", xyz}}, "$xyz $Thing");
0188 //
0189 // If xyz is "Foo", this will become "Foo Thing", but if it is "", this becomes
0190 // "Thing", rather than " Thing". This helps minimize awkward whitespace in the
0191 // output.
0192 //
0193 // The value may be any type that can be stringified with `absl::StrCat`:
0194 //
0195 //   p.Emit({{"num", 5}}, "x = $num$;");
0196 //
0197 // If a variable that is referenced in the format string is missing, the program
0198 // will crash. Callers must statically know that every variable reference is
0199 // valid, and MUST NOT pass user-provided strings directly into Emit().
0200 //
0201 // In practice, this means the first member of io::Printer::Sub here:
0202 //
0203 //   p.Emit({{"num", 5}}, "x = $num$;");
0204 //            ^
0205 // must always be a string literal.
0206 //
0207 // Substitutions can be configured to "chomp" a single character after them, to
0208 // help make indentation work out. This can be configured by passing a
0209 // io::Printer::Sub().WithSuffix() into Emit's substitution map:
0210 //   p.Emit({io::Printer::Sub("var", var_decl).WithSuffix(";")}, R"cc(
0211 //     class $class$ {
0212 //      public:
0213 //       $var$;
0214 //     };
0215 //   )cc");
0216 //
0217 // This will delete the ; after $var$, regardless of whether it was an empty
0218 // declaration or not. It will also intelligently attempt to clean up
0219 // empty lines that follow, if it was on an empty line; this promotes cleaner
0220 // formatting of the output.
0221 //
0222 // You can configure a large set of skippable characters, but when chomping,
0223 // only one character will actually be skipped at a time. For example, callback
0224 // substitutions (see below) use ";," by default as their "chomping set".
0225 //
0226 //   p.Emit({io::Printer::Sub("var", 123).WithSuffix(";,")}, R"cc(
0227 //       $var$,;
0228 //   )cc");
0229 //
0230 // will produce "123,".
0231 //
0232 // # Callback Substitution
0233 //
0234 // Instead of passing a string into Emit(), it is possible to pass in a callback
0235 // as a variable mapping. This will take indentation into account, which allows
0236 // factoring out parts of a formatting string while ensuring braces are
0237 // balanced:
0238 //
0239 //   p.Emit(
0240 //     {{"methods", [&] {
0241 //       p.Emit(R"cc(
0242 //         int Bar() {
0243 //            return 42;
0244 //         }
0245 //       )cc");
0246 //     }}},
0247 //     R"cc(
0248 //       class Foo {
0249 //        public:
0250 //         $methods$;
0251 //       };
0252 //     )cc"
0253 //   );
0254 //
0255 // This emits
0256 //
0257 //   class Foo {
0258 //    public:
0259 //     int Bar() {
0260 //       return 42;
0261 //     }
0262 //   };
0263 //
0264 // # Comments
0265 //
0266 // It may be desirable to place comments in a raw string that are stripped out
0267 // before printing. The prefix for Printer-ignored comments can be configured
0268 // in Options. By default, this is `//~`.
0269 //
0270 //   p.Emit(R"cc(
0271 //     // Will be printed in the output.
0272 //     //~ Won't be.
0273 //   )cc");
0274 //
0275 // # Lookup Frames
0276 //
0277 // If many calls to Emit() use the same set of variables, they can be stored
0278 // in a *variable lookup frame*, like so:
0279 //
0280 //   auto vars = p.WithVars({{"class_name", my_class_name}});
0281 //   p.Emit(R"cc(
0282 //     class $class_name$ {
0283 //      public:
0284 //       $class_name$(int x);
0285 //       // Etc.
0286 //     };
0287 //   )cc");
0288 //
0289 // WithVars() returns an RAII object that will "pop" the lookup frame on scope
0290 // exit, ensuring that the variables remain local. There are a few different
0291 // overloads of WithVars(); it accepts a map type, like absl::flat_hash_map,
0292 // either by-value (which will cause the Printer to store a copy), or by
0293 // pointer (which will cause the Printer to store a pointer, potentially
0294 // avoiding a copy.)
0295 //
0296 // p.Emit(vars, "..."); is effectively syntax sugar for
0297 //
0298 //  { auto v = p.WithVars(vars); p.Emit("..."); }
0299 //
0300 // NOTE: callbacks are *not* allowed with WithVars; callbacks should be local
0301 // to a specific Emit() call.
0302 //
0303 // # Annotations
0304 //
0305 // If Printer is given an AnnotationCollector, it will use it to record which
0306 // spans of generated code correspond to user-indicated descriptors. There are
0307 // a few different ways of indicating when to emit annotations.
0308 //
0309 // The WithAnnotations() function is like WithVars(), but accepts maps with
0310 // string keys and descriptor values. It adds an annotation variable frame and
0311 // returns an RAII object that pops the frame.
0312 //
0313 // There are two different ways to annotate code. In the first, when
0314 // substituting a variable, if there is an annotation with the same name, then
0315 // the resulting expanded value's span will be annotated with that annotation.
0316 // For example:
0317 //
0318 //   auto v = p.WithVars({{"class_name", my_class_name}});
0319 //   auto a = p.WithAnnotations({{"class_name", message_descriptor}});
0320 //   p.Emit(R"cc(
0321 //     class $class_name$ {
0322 //      public:
0323 //       $class_name$(int x);
0324 //       // Etc.
0325 //     };
0326 //   )cc");
0327 //
0328 // The span corresponding to whatever $class_name$ expands to will be annotated
0329 // as having come from message_descriptor.
0330 //
0331 // For convenience, this can be done with a single WithVars(), using the special
0332 // three-argument form:
0333 //
0334 //   auto v = p.WithVars({{"class_name", my_class_name, message_descriptor}});
0335 //   p.Emit(R"cc(
0336 //     class $class_name$ {
0337 //      public:
0338 //       $class_name$(int x);
0339 //       // Etc.
0340 //     };
0341 //   )cc");
0342 //
0343 //
0344 // Alternatively, a range may be given explicitly:
0345 //
0346 //   auto a = p.WithAnnotations({{"my_desc", message_descriptor}});
0347 //   p.Emit(R"cc(
0348 //     $_start$my_desc$
0349 //     class Foo {
0350 //       // Etc.
0351 //     };
0352 //     $_end$my_desc$
0353 //   )cc");
0354 //
0355 // The special $_start$ and $_end$ variables indicate the start and end of an
0356 // annotated span, which is annotated with the variable that follows. This
0357 // form can produce somewhat unreadable format strings and is not recommended.
0358 //
0359 // Note that whitespace after a $_start$ and before an $_end$ is not printed.
0360 //
0361 // # Indentation
0362 //
0363 // Printer tracks an indentation amount to add to each new line, independent
0364 // from indentation in an Emit() call's literal. The amount of indentation to
0365 // add is controlled by the WithIndent() function:
0366 //
0367 //   p.Emit("class $class_name$ {");
0368 //   {
0369 //     auto indent = p.WithIndent();
0370 //     p.Emit(R"cc(
0371 //       public:
0372 //        $class_name$(int x);
0373 //     )cc");
0374 //   }
0375 //   p.Emit("};");
0376 //
0377 // This will automatically add one level of indentation to all code in scope of
0378 // `indent`, which is an RAII object much like the return value of `WithVars()`.
0379 //
0380 // # Old API
0381 // TODO: Delete this documentation.
0382 //
0383 // Printer supports an older-style API that is in the process of being
0384 // re-written. The old documentation is reproduced here until all use-cases are
0385 // handled.
0386 //
0387 // This simple utility class assists in code generation.  It basically
0388 // allows the caller to define a set of variables and then output some
0389 // text with variable substitutions.  Example usage:
0390 //
0391 //   Printer printer(output, '$');
0392 //   map<string, string> vars;
0393 //   vars["name"] = "Bob";
0394 //   printer.Print(vars, "My name is $name$.");
0395 //
0396 // The above writes "My name is Bob." to the output stream.
0397 //
0398 // Printer aggressively enforces correct usage, crashing (with assert failures)
0399 // in the case of undefined variables in debug builds. This helps greatly in
0400 // debugging code which uses it.
0401 //
0402 // If a Printer is constructed with an AnnotationCollector, it will provide it
0403 // with annotations that connect the Printer's output to paths that can identify
0404 // various descriptors.  In the above example, if person_ is a descriptor that
0405 // identifies Bob, we can associate the output string "My name is Bob." with
0406 // a source path pointing to that descriptor with:
0407 //
0408 //   printer.Annotate("name", person_);
0409 //
0410 // The AnnotationCollector will be sent an annotation linking the output range
0411 // covering "Bob" to the logical path provided by person_.  Tools may use
0412 // this association to (for example) link "Bob" in the output back to the
0413 // source file that defined the person_ descriptor identifying Bob.
0414 //
0415 // Annotate can only examine variables substituted during the last call to
0416 // Print.  It is invalid to refer to a variable that was used multiple times
0417 // in a single Print call.
0418 //
0419 // In full generality, one may specify a range of output text using a beginning
0420 // substitution variable and an ending variable.  The resulting annotation will
0421 // span from the first character of the substituted value for the beginning
0422 // variable to the last character of the substituted value for the ending
0423 // variable.  For example, the Annotate call above is equivalent to this one:
0424 //
0425 //   printer.Annotate("name", "name", person_);
0426 //
0427 // This is useful if multiple variables combine to form a single span of output
0428 // that should be annotated with the same source path.  For example:
0429 //
0430 //   Printer printer(output, '$');
0431 //   map<string, string> vars;
0432 //   vars["first"] = "Alice";
0433 //   vars["last"] = "Smith";
0434 //   printer.Print(vars, "My name is $first$ $last$.");
0435 //   printer.Annotate("first", "last", person_);
0436 //
0437 // This code would associate the span covering "Alice Smith" in the output with
0438 // the person_ descriptor.
0439 //
0440 // Note that the beginning variable must come before (or overlap with, in the
0441 // case of zero-sized substitution values) the ending variable.
0442 //
0443 // It is also sometimes useful to use variables with zero-sized values as
0444 // markers.  This avoids issues with multiple references to the same variable
0445 // and also allows annotation ranges to span literal text from the Print
0446 // templates:
0447 //
0448 //   Printer printer(output, '$');
0449 //   map<string, string> vars;
0450 //   vars["foo"] = "bar";
0451 //   vars["function"] = "call";
0452 //   vars["mark"] = "";
0453 //   printer.Print(vars, "$function$($foo$,$foo$)$mark$");
0454 //   printer.Annotate("function", "mark", call_);
0455 //
0456 // This code associates the span covering "call(bar,bar)" in the output with the
0457 // call_ descriptor.
0458 class PROTOBUF_EXPORT Printer {
0459  private:
0460   struct AnnotationRecord;
0461 
0462  public:
0463   // This type exists to work around an absl type that has not yet been
0464   // released.
0465   struct SourceLocation {
0466     static SourceLocation current() { return {}; }
0467     absl::string_view file_name() const { return "<unknown>"; }
0468     int line() const { return 0; }
0469   };
0470 
0471   static constexpr char kDefaultVariableDelimiter = '$';
0472   static constexpr absl::string_view kProtocCodegenTrace =
0473       "PROTOC_CODEGEN_TRACE";
0474 
0475   // Sink type for constructing substitutions to pass to WithVars() and Emit().
0476   class Sub;
0477 
0478   // Options for controlling how the output of a Printer is formatted.
0479   struct Options {
0480     Options() = default;
0481     Options(const Options&) = default;
0482     Options(Options&&) = default;
0483     Options(char variable_delimiter, AnnotationCollector* annotation_collector)
0484         : variable_delimiter(variable_delimiter),
0485           annotation_collector(annotation_collector) {}
0486 
0487     // The delimiter for variable substitutions, e.g. $foo$.
0488     char variable_delimiter = kDefaultVariableDelimiter;
0489     // An optional listener the Printer calls whenever it emits a source
0490     // annotation; may be null.
0491     AnnotationCollector* annotation_collector = nullptr;
0492     // The "comment start" token for the language being generated. This is used
0493     // to allow the Printer to emit debugging annotations in the source code
0494     // output.
0495     absl::string_view comment_start = "//";
0496     // The token for beginning comments that are discarded by Printer's internal
0497     // formatter.
0498     absl::string_view ignored_comment_start = "//~";
0499     // The number of spaces that a single level of indentation adds by default;
0500     // this is the amount that WithIndent() increases indentation by.
0501     size_t spaces_per_indent = 2;
0502     // Whether to emit a "codegen trace" for calls to Emit(). If true, each call
0503     // to Emit() will print a comment indicating where in the source of the
0504     // compiler the Emit() call occurred.
0505     //
0506     // If disengaged, defaults to whether or not the environment variable
0507     // `PROTOC_CODEGEN_TRACE` is set.
0508     std::optional<bool> enable_codegen_trace = std::nullopt;
0509   };
0510 
0511   // Constructs a new Printer with the default options to output to
0512   // `output`.
0513   explicit Printer(ZeroCopyOutputStream* output);
0514 
0515   // Constructs a new printer with the given set of options to output to
0516   // `output`.
0517   Printer(ZeroCopyOutputStream* output, Options options);
0518 
0519   // Old-style constructor. Avoid in preference to the two constructors above.
0520   //
0521   // Will eventually be marked as deprecated.
0522   Printer(ZeroCopyOutputStream* output, char variable_delimiter,
0523           AnnotationCollector* annotation_collector = nullptr);
0524 
0525   Printer(const Printer&) = delete;
0526   Printer& operator=(const Printer&) = delete;
0527 
0528   // Pushes a new variable lookup frame that stores `vars` by reference.
0529   //
0530   // Returns an RAII object that pops the lookup frame.
0531   template <typename Map>
0532   auto WithVars(const Map* vars);
0533 
0534   // Pushes a new variable lookup frame that stores `vars` by value.
0535   //
0536   // Returns an RAII object that pops the lookup frame.
0537   template <
0538       typename Map = absl::flat_hash_map<absl::string_view, absl::string_view>,
0539       typename = std::enable_if_t<!std::is_pointer<Map>::value>,
0540       // Prefer the more specific span impl if this could be turned into
0541       // a span.
0542       typename = std::enable_if_t<
0543           !std::is_convertible<Map, absl::Span<const Sub>>::value>>
0544   auto WithVars(Map&& vars);
0545 
0546   // Pushes a new variable lookup frame that stores `vars` by value.
0547   //
0548   // Returns an RAII object that pops the lookup frame.
0549   auto WithVars(absl::Span<const Sub> vars);
0550 
0551   // Looks up a variable set with WithVars().
0552   //
0553   // Will crash if:
0554   // - `var` is not present in the lookup frame table.
0555   // - `var` is a callback, rather than a string.
0556   absl::string_view LookupVar(absl::string_view var);
0557 
0558   // Pushes a new annotation lookup frame that stores `vars` by reference.
0559   //
0560   // Returns an RAII object that pops the lookup frame.
0561   template <typename Map>
0562   auto WithAnnotations(const Map* vars);
0563 
0564   // Pushes a new variable lookup frame that stores `vars` by value.
0565   //
0566   // When writing `WithAnnotations({...})`, this is the overload that will be
0567   // called, and it will synthesize an `absl::flat_hash_map`.
0568   //
0569   // Returns an RAII object that pops the lookup frame.
0570   template <typename Map = absl::flat_hash_map<std::string, AnnotationRecord>>
0571   auto WithAnnotations(Map&& vars);
0572 
0573   // Increases the indentation by `indent` spaces; when nullopt, increments
0574   // indentation by the configured default spaces_per_indent.
0575   //
0576   // Returns an RAII object that removes this indentation.
0577   auto WithIndent(std::optional<size_t> indent = std::nullopt) {
0578     size_t delta = indent.value_or(options_.spaces_per_indent);
0579     indent_ += delta;
0580     return absl::MakeCleanup([this, delta] { indent_ -= delta; });
0581   }
0582 
0583   // Emits formatted source code to the underlying output. See the class
0584   // documentation for more details.
0585   //
0586   // `format` MUST be a string constant.
0587   void Emit(absl::string_view format,
0588             SourceLocation loc = SourceLocation::current());
0589 
0590   // Emits formatted source code to the underlying output, injecting
0591   // additional variables as a lookup frame for just this call. See the class
0592   // documentation for more details.
0593   //
0594   // `format` MUST be a string constant.
0595   void Emit(absl::Span<const Sub> vars, absl::string_view format,
0596             SourceLocation loc = SourceLocation::current());
0597 
0598   // Write a string directly to the underlying output, performing no formatting
0599   // of any sort.
0600   void PrintRaw(absl::string_view data) { WriteRaw(data.data(), data.size()); }
0601 
0602   // Write a string directly to the underlying output, performing no formatting
0603   // of any sort.
0604   void WriteRaw(const char* data, size_t size);
0605 
0606   // True if any write to the underlying stream failed.  (We don't just
0607   // crash in this case because this is an I/O failure, not a programming
0608   // error.)
0609   bool failed() const { return failed_; }
0610 
0611   // -- Old-style API below; to be deprecated and removed. --
0612   // TODO: Deprecate these APIs.
0613 
0614   template <
0615       typename Map = absl::flat_hash_map<absl::string_view, absl::string_view>>
0616   void Print(const Map& vars, absl::string_view text);
0617 
0618   template <typename... Args>
0619   void Print(absl::string_view text, const Args&... args);
0620 
0621   // Link a substitution variable emitted by the last call to Print to the
0622   // object described by descriptor.
0623   template <typename SomeDescriptor>
0624   void Annotate(
0625       absl::string_view varname, const SomeDescriptor* descriptor,
0626       std::optional<AnnotationCollector::Semantic> semantic = std::nullopt) {
0627     Annotate(varname, varname, descriptor, semantic);
0628   }
0629 
0630   // Link the output range defined by the substitution variables as emitted by
0631   // the last call to Print to the object described by descriptor. The range
0632   // begins at begin_varname's value and ends after the last character of the
0633   // value substituted for end_varname.
0634   template <typename Desc>
0635   void Annotate(
0636       absl::string_view begin_varname, absl::string_view end_varname,
0637       const Desc* descriptor,
0638       std::optional<AnnotationCollector::Semantic> semantic = std::nullopt);
0639 
0640   // Link a substitution variable emitted by the last call to Print to the file
0641   // with path file_name.
0642   void Annotate(
0643       absl::string_view varname, absl::string_view file_name,
0644       std::optional<AnnotationCollector::Semantic> semantic = std::nullopt) {
0645     Annotate(varname, varname, file_name, semantic);
0646   }
0647 
0648   // Link the output range defined by the substitution variables as emitted by
0649   // the last call to Print to the file with path file_name. The range begins
0650   // at begin_varname's value and ends after the last character of the value
0651   // substituted for end_varname.
0652   void Annotate(
0653       absl::string_view begin_varname, absl::string_view end_varname,
0654       absl::string_view file_name,
0655       std::optional<AnnotationCollector::Semantic> semantic = std::nullopt) {
0656     if (options_.annotation_collector == nullptr) {
0657       return;
0658     }
0659 
0660     Annotate(begin_varname, end_varname, file_name, {}, semantic);
0661   }
0662 
0663   // Indent text by `options.spaces_per_indent`; undone by Outdent().
0664   void Indent() { indent_ += options_.spaces_per_indent; }
0665 
0666   // Undoes a call to Indent().
0667   void Outdent(SourceLocation loc = SourceLocation::current());
0668 
0669   // FormatInternal is a helper function not meant to use directly, use
0670   // compiler::cpp::Formatter instead.
0671   template <typename Map = absl::flat_hash_map<std::string, std::string>>
0672   void FormatInternal(absl::Span<const std::string> args, const Map& vars,
0673                       absl::string_view format);
0674 
0675   // Injects a substitution listener for the lifetime of the RAII object
0676   // returned.
0677   // While the listener is active it will receive a callback on each
0678   // substitution label found.
0679   // This can be used to add basic verification on top of emit routines.
0680   auto WithSubstitutionListener(
0681       absl::AnyInvocable<void(absl::string_view, SourceLocation)> listener) {
0682     ABSL_CHECK(substitution_listener_ == nullptr);
0683     substitution_listener_ = std::move(listener);
0684     return absl::MakeCleanup([this] { substitution_listener_ = nullptr; });
0685   }
0686 
0687  private:
0688   struct PrintOptions;
0689   struct Format;
0690 
0691   // Helper type for wrapping a variable substitution expansion result.
0692   template <bool owned>
0693   struct ValueImpl;
0694 
0695   using ValueView = ValueImpl</*owned=*/false>;
0696   using Value = ValueImpl</*owned=*/true>;
0697 
0698   // Provide a helper to use heterogeneous lookup when it's available.
0699   template <typename...>
0700   using Void = void;
0701 
0702   template <typename Map, typename = void>
0703   struct HasHeteroLookup : std::false_type {};
0704   template <typename Map>
0705   struct HasHeteroLookup<Map, Void<decltype(std::declval<Map>().find(
0706                                   std::declval<absl::string_view>()))>>
0707       : std::true_type {};
0708 
0709   template <typename Map,
0710             typename = std::enable_if_t<HasHeteroLookup<Map>::value>>
0711   static absl::string_view ToStringKey(absl::string_view x) {
0712     return x;
0713   }
0714 
0715   template <typename Map,
0716             typename = std::enable_if_t<!HasHeteroLookup<Map>::value>>
0717   static std::string ToStringKey(absl::string_view x) {
0718     return std::string(x);
0719   }
0720 
0721   Format TokenizeFormat(absl::string_view format_string,
0722                         const PrintOptions& options);
0723 
0724   // Emit an annotation for the range defined by the given substitution
0725   // variables, as set by the most recent call to PrintImpl() that set
0726   // `use_substitution_map` to true.
0727   //
0728   // The range begins at the start of `begin_varname`'s value and ends after the
0729   // last byte of `end_varname`'s value.
0730   //
0731   // `begin_varname` and `end_varname may` refer to the same variable.
0732   void Annotate(absl::string_view begin_varname, absl::string_view end_varname,
0733                 absl::string_view file_path, const std::vector<int>& path,
0734                 std::optional<AnnotationCollector::Semantic> semantic);
0735 
0736   // The core printing implementation. There are three public entry points,
0737   // which enable different slices of functionality that are controlled by the
0738   // `opts` argument.
0739   void PrintImpl(absl::string_view format, absl::Span<const std::string> args,
0740                  PrintOptions opts);
0741 
0742   // This is a private function only so that it can see PrintOptions.
0743   static bool Validate(bool cond, PrintOptions opts,
0744                        absl::FunctionRef<std::string()> message);
0745   static bool Validate(bool cond, PrintOptions opts, absl::string_view message);
0746 
0747   // Performs calls to `Validate()` to check that `index < current_arg_index`
0748   // and `index < args_len`, producing appropriate log lines if the checks fail,
0749   // and crashing if necessary.
0750   bool ValidateIndexLookupInBounds(size_t index, size_t current_arg_index,
0751                                    size_t args_len, PrintOptions opts);
0752 
0753   // Prints indentation if `at_start_of_line_` is true.
0754   void IndentIfAtStart();
0755 
0756   // Prints a codegen trace, for the given location in the compiler's source.
0757   void PrintCodegenTrace(std::optional<SourceLocation> loc);
0758 
0759   // The core implementation for "fully-elaborated" variable definitions.
0760   auto WithDefs(absl::Span<const Sub> vars, bool allow_callbacks);
0761 
0762   // Returns the start and end of the value that was substituted in place of
0763   // the variable `varname` in the last call to PrintImpl() (with
0764   // `use_substitution_map` set), if such a variable was substituted exactly
0765   // once.
0766   std::optional<std::pair<size_t, size_t>> GetSubstitutionRange(
0767       absl::string_view varname, PrintOptions opts);
0768 
0769   google::protobuf::io::zc_sink_internal::ZeroCopyStreamByteSink sink_;
0770   Options options_;
0771   size_t indent_ = 0;
0772   bool at_start_of_line_ = true;
0773   bool failed_ = false;
0774 
0775   size_t paren_depth_ = 0;
0776   std::vector<size_t> paren_depth_to_omit_;
0777 
0778   std::vector<std::function<std::optional<ValueView>(absl::string_view)>>
0779       var_lookups_;
0780 
0781   std::vector<std::function<std::optional<AnnotationRecord>(absl::string_view)>>
0782       annotation_lookups_;
0783 
0784   // If set, we invoke this when we do a label substitution. This can be used to
0785   // verify consistency of the generated code while we generate it.
0786   absl::AnyInvocable<void(absl::string_view, SourceLocation)>
0787       substitution_listener_;
0788 
0789   // A map from variable name to [start, end) offsets in the output buffer.
0790   //
0791   // This stores the data looked up by GetSubstitutionRange().
0792   absl::flat_hash_map<std::string, std::pair<size_t, size_t>> substitutions_;
0793   // Keeps track of the keys in `substitutions_` that need to be updated when
0794   // indents are inserted. These are keys that refer to the beginning of the
0795   // current line.
0796   std::vector<std::string> line_start_variables_;
0797 };
0798 
0799 // Options for PrintImpl().
0800 struct Printer::PrintOptions {
0801   // The callsite of the public entry-point. Only Emit() sets this.
0802   std::optional<SourceLocation> loc;
0803   // If set, Validate() calls will not crash the program.
0804   bool checks_are_debug_only = false;
0805   // If set, the `substitutions_` map will be populated as variables are
0806   // substituted.
0807   bool use_substitution_map = false;
0808   // If set, the ${1$ and $}$ forms will be substituted. These are used for
0809   // a slightly janky annotation-insertion mechanism in FormatInternal, that
0810   // requires that passed-in substitution variables be serialized protos.
0811   bool use_curly_brace_substitutions = false;
0812   // If set, the $n$ forms will be substituted, pulling from the `args`
0813   // argument to PrintImpl().
0814   bool allow_digit_substitutions = true;
0815   // If set, when a variable substitution with spaces in it, such as $ var$,
0816   // is encountered, the spaces are stripped, so that it is as if it was
0817   // $var$. If $var$ substitutes to a non-empty string, the removed spaces are
0818   // printed around the substituted value.
0819   //
0820   // See the class documentation for more information on this behavior.
0821   bool strip_spaces_around_vars = true;
0822   // If set, leading whitespace will be stripped from the format string to
0823   // determine the "extraneous indentation" that is produced when the format
0824   // string is a C++ raw string. This is used to remove leading spaces from
0825   // a raw string that would otherwise result in erratic indentation in the
0826   // output.
0827   bool strip_raw_string_indentation = false;
0828   // If set, the annotation lookup frames are searched, per the annotation
0829   // semantics of Emit() described in the class documentation.
0830   bool use_annotation_frames = true;
0831 };
0832 
0833 // Helper type for wrapping a variable substitution expansion result.
0834 template <bool owned>
0835 struct Printer::ValueImpl {
0836  private:
0837   template <typename T>
0838   struct IsSubImpl : std::false_type {};
0839   template <bool a>
0840   struct IsSubImpl<ValueImpl<a>> : std::true_type {};
0841 
0842  public:
0843   using StringType = std::conditional_t<owned, std::string, absl::string_view>;
0844   // These callbacks return false if this is a recursive call.
0845   using Callback = std::function<bool()>;
0846   using StringOrCallback = std::variant<StringType, Callback>;
0847 
0848   ValueImpl() = default;
0849 
0850   // This is a template to avoid colliding with the copy constructor below.
0851   template <typename Value,
0852             typename = std::enable_if_t<
0853                 !IsSubImpl<absl::remove_cvref_t<Value>>::value>>
0854   ValueImpl(Value&& value)  // NOLINT
0855       : value(ToStringOrCallback(std::forward<Value>(value), Rank2{})) {
0856     if (std::holds_alternative<Callback>(this->value)) {
0857       consume_after = ";,";
0858     }
0859   }
0860 
0861   // Copy ctor/assign allow interconversion of the two template parameters.
0862   template <bool that_owned>
0863   ValueImpl(const ValueImpl<that_owned>& that) {  // NOLINT
0864     *this = that;
0865   }
0866 
0867   template <bool that_owned>
0868   ValueImpl& operator=(const ValueImpl<that_owned>& that);
0869 
0870   const StringType* AsString() const { return std::get_if<StringType>(&value); }
0871 
0872   const Callback* AsCallback() const { return std::get_if<Callback>(&value); }
0873 
0874   StringOrCallback value;
0875   std::string consume_after;
0876   bool consume_parens_if_empty = false;
0877 
0878  private:
0879   // go/ranked-overloads
0880   struct Rank0 {};
0881   struct Rank1 : Rank0 {};
0882   struct Rank2 : Rank1 {};
0883 
0884   // Dummy template for delayed instantiation, which is required for the
0885   // static assert below to kick in only when this function is called when it
0886   // shouldn't.
0887   //
0888   // This is done to produce a better error message than the "candidate does
0889   // not match" SFINAE errors.
0890   template <typename Cb, typename = decltype(std::declval<Cb&&>()())>
0891   StringOrCallback ToStringOrCallback(Cb&& cb, Rank2);
0892 
0893   // Separate from the AlphaNum overload to avoid copies when taking strings
0894   // by value when in `owned` mode.
0895   StringOrCallback ToStringOrCallback(StringType s, Rank1) { return s; }
0896 
0897   StringOrCallback ToStringOrCallback(const absl::AlphaNum& s, Rank0) {
0898     return StringType(s.Piece());
0899   }
0900 };
0901 
0902 template <bool owned>
0903 template <bool that_owned>
0904 Printer::ValueImpl<owned>& Printer::ValueImpl<owned>::operator=(
0905     const ValueImpl<that_owned>& that) {
0906   // Cast to void* is required, since this and that may potentially be of
0907   // different types (due to the `that_owned` parameter).
0908   if (static_cast<const void*>(this) == static_cast<const void*>(&that)) {
0909     return *this;
0910   }
0911 
0912   using ThatStringType = typename ValueImpl<that_owned>::StringType;
0913 
0914   if (auto* str = std::get_if<ThatStringType>(&that.value)) {
0915     value = StringType(*str);
0916   } else {
0917     value = std::get<Callback>(that.value);
0918   }
0919 
0920   consume_after = that.consume_after;
0921   consume_parens_if_empty = that.consume_parens_if_empty;
0922   return *this;
0923 }
0924 
0925 template <bool owned>
0926 template <typename Cb, typename /*Sfinae*/>
0927 auto Printer::ValueImpl<owned>::ToStringOrCallback(Cb&& cb, Rank2)
0928     -> StringOrCallback {
0929   return Callback(
0930       [cb = std::forward<Cb>(cb), is_called = false]() mutable -> bool {
0931         if (is_called) {
0932           // Catch whether or not this function is being called recursively.
0933           return false;
0934         }
0935         is_called = true;
0936         cb();
0937         is_called = false;
0938         return true;
0939       });
0940 }
0941 
0942 struct Printer::AnnotationRecord {
0943   std::vector<int> path;
0944   std::string file_path;
0945   std::optional<AnnotationCollector::Semantic> semantic;
0946 
0947   // AnnotationRecord's constructors are *not* marked as explicit,
0948   // specifically so that it is possible to construct a
0949   // map<string, AnnotationRecord> by writing
0950   //
0951   // {{"foo", my_cool_descriptor}, {"bar", "file.proto"}}
0952 
0953   template <
0954       typename String,
0955       std::enable_if_t<std::is_convertible<const String&, std::string>::value,
0956                        int> = 0>
0957   AnnotationRecord(  // NOLINT(google-explicit-constructor)
0958       const String& file_path,
0959       std::optional<AnnotationCollector::Semantic> semantic = std::nullopt)
0960       : file_path(file_path), semantic(semantic) {}
0961 
0962   template <typename Desc,
0963             // This SFINAE clause excludes char* from matching this
0964             // constructor.
0965             std::enable_if_t<std::is_class<Desc>::value, int> = 0>
0966   AnnotationRecord(  // NOLINT(google-explicit-constructor)
0967       const Desc* desc,
0968       std::optional<AnnotationCollector::Semantic> semantic = std::nullopt)
0969       : file_path(desc->file()->name()), semantic(semantic) {
0970     desc->GetLocationPath(&path);
0971   }
0972 };
0973 
0974 class Printer::Sub {
0975  public:
0976   template <typename Value>
0977   Sub(std::string key, Value&& value)
0978       : key_(std::move(key)),
0979         value_(std::forward<Value>(value)),
0980         annotation_(std::nullopt) {}
0981 
0982   Sub AnnotatedAs(AnnotationRecord annotation) && {
0983     annotation_ = std::move(annotation);
0984     return std::move(*this);
0985   }
0986 
0987   Sub WithSuffix(std::string sub_suffix) && {
0988     value_.consume_after = std::move(sub_suffix);
0989     return std::move(*this);
0990   }
0991 
0992   Sub ConditionalFunctionCall() && {
0993     value_.consume_parens_if_empty = true;
0994     return std::move(*this);
0995   }
0996 
0997   absl::string_view key() const { return key_; }
0998 
0999   absl::string_view value() const {
1000     const auto* str = value_.AsString();
1001     ABSL_CHECK(str != nullptr)
1002         << "could not find " << key() << "; found callback instead";
1003     return *str;
1004   }
1005 
1006  private:
1007   friend class Printer;
1008 
1009   std::string key_;
1010   Value value_;
1011   std::optional<AnnotationRecord> annotation_;
1012 };
1013 
1014 template <typename Map>
1015 auto Printer::WithVars(const Map* vars) {
1016   var_lookups_.emplace_back(
1017       [vars](absl::string_view var) -> std::optional<ValueView> {
1018         auto it = vars->find(ToStringKey<Map>(var));
1019         if (it == vars->end()) {
1020           return std::nullopt;
1021         }
1022         return ValueView(it->second);
1023       });
1024   return absl::MakeCleanup([this] { var_lookups_.pop_back(); });
1025 }
1026 
1027 template <typename Map, typename, typename /*Sfinae*/>
1028 auto Printer::WithVars(Map&& vars) {
1029   var_lookups_.emplace_back(
1030       [vars = std::forward<Map>(vars)](
1031           absl::string_view var) -> std::optional<ValueView> {
1032         auto it = vars.find(ToStringKey<Map>(var));
1033         if (it == vars.end()) {
1034           return std::nullopt;
1035         }
1036         return ValueView(it->second);
1037       });
1038   return absl::MakeCleanup([this] { var_lookups_.pop_back(); });
1039 }
1040 
1041 template <typename Map>
1042 auto Printer::WithAnnotations(const Map* vars) {
1043   annotation_lookups_.emplace_back(
1044       [vars](absl::string_view var) -> std::optional<AnnotationRecord> {
1045         auto it = vars->find(ToStringKey<Map>(var));
1046         if (it == vars->end()) {
1047           return std::nullopt;
1048         }
1049         return AnnotationRecord(it->second);
1050       });
1051   return absl::MakeCleanup([this] { annotation_lookups_.pop_back(); });
1052 }
1053 
1054 template <typename Map>
1055 auto Printer::WithAnnotations(Map&& vars) {
1056   annotation_lookups_.emplace_back(
1057       [vars = std::forward<Map>(vars)](
1058           absl::string_view var) -> std::optional<AnnotationRecord> {
1059         auto it = vars.find(ToStringKey<Map>(var));
1060         if (it == vars.end()) {
1061           return std::nullopt;
1062         }
1063         return AnnotationRecord(it->second);
1064       });
1065   return absl::MakeCleanup([this] { annotation_lookups_.pop_back(); });
1066 }
1067 
1068 inline void Printer::Emit(absl::string_view format, SourceLocation loc) {
1069   Emit({}, format, loc);
1070 }
1071 
1072 template <typename Map>
1073 void Printer::Print(const Map& vars, absl::string_view text) {
1074   PrintOptions opts;
1075   opts.checks_are_debug_only = true;
1076   opts.use_substitution_map = true;
1077   opts.allow_digit_substitutions = false;
1078 
1079   auto pop = WithVars(&vars);
1080   PrintImpl(text, {}, opts);
1081 }
1082 
1083 template <typename... Args>
1084 void Printer::Print(absl::string_view text, const Args&... args) {
1085   static_assert(sizeof...(args) % 2 == 0, "");
1086 
1087   // Include an extra arg, since a zero-length array is ill-formed, and
1088   // MSVC complains.
1089   absl::string_view vars[] = {args..., ""};
1090   absl::flat_hash_map<absl::string_view, absl::string_view> map;
1091   map.reserve(sizeof...(args) / 2);
1092   for (size_t i = 0; i < sizeof...(args); i += 2) {
1093     map.emplace(vars[i], vars[i + 1]);
1094   }
1095 
1096   Print(map, text);
1097 }
1098 
1099 template <typename Desc>
1100 void Printer::Annotate(absl::string_view begin_varname,
1101                        absl::string_view end_varname, const Desc* descriptor,
1102                        std::optional<AnnotationCollector::Semantic> semantic) {
1103   if (options_.annotation_collector == nullptr) {
1104     return;
1105   }
1106 
1107   std::vector<int> path;
1108   descriptor->GetLocationPath(&path);
1109   Annotate(begin_varname, end_varname, descriptor->file()->name(), path,
1110            semantic);
1111 }
1112 
1113 template <typename Map>
1114 void Printer::FormatInternal(absl::Span<const std::string> args,
1115                              const Map& vars, absl::string_view format) {
1116   PrintOptions opts;
1117   opts.use_curly_brace_substitutions = true;
1118   opts.strip_spaces_around_vars = true;
1119 
1120   auto pop = WithVars(&vars);
1121   PrintImpl(format, args, opts);
1122 }
1123 
1124 inline auto Printer::WithDefs(absl::Span<const Sub> vars,
1125                               bool allow_callbacks) {
1126   absl::flat_hash_map<std::string, Value> var_map;
1127   var_map.reserve(vars.size());
1128 
1129   absl::flat_hash_map<std::string, AnnotationRecord> annotation_map;
1130 
1131   for (const auto& var : vars) {
1132     ABSL_CHECK(allow_callbacks || var.value_.AsCallback() == nullptr)
1133         << "callback arguments are not permitted in this position";
1134     auto result = var_map.insert({var.key_, var.value_});
1135     ABSL_CHECK(result.second)
1136         << "repeated variable in Emit() or WithVars() call: \"" << var.key_
1137         << "\"";
1138     if (var.annotation_.has_value()) {
1139       annotation_map.insert({var.key_, *var.annotation_});
1140     }
1141   }
1142 
1143   var_lookups_.emplace_back([map = std::move(var_map)](absl::string_view var)
1144                                 -> std::optional<ValueView> {
1145     auto it = map.find(var);
1146     if (it == map.end()) {
1147       return std::nullopt;
1148     }
1149     return ValueView(it->second);
1150   });
1151 
1152   bool has_annotations = !annotation_map.empty();
1153   if (has_annotations) {
1154     annotation_lookups_.emplace_back(
1155         [map = std::move(annotation_map)](
1156             absl::string_view var) -> std::optional<AnnotationRecord> {
1157           auto it = map.find(var);
1158           if (it == map.end()) {
1159             return std::nullopt;
1160           }
1161           return it->second;
1162         });
1163   }
1164 
1165   return absl::MakeCleanup([this, has_annotations] {
1166     var_lookups_.pop_back();
1167     if (has_annotations) {
1168       annotation_lookups_.pop_back();
1169     }
1170   });
1171 }
1172 
1173 inline auto Printer::WithVars(absl::Span<const Sub> vars) {
1174   return WithDefs(vars, /*allow_callbacks=*/false);
1175 }
1176 }  // namespace io
1177 }  // namespace protobuf
1178 }  // namespace google
1179 
1180 #include "google/protobuf/port_undef.inc"
1181 
1182 #endif  // GOOGLE_PROTOBUF_IO_PRINTER_H__