Add an RAII namespace printer helper for C++ codegen.

This can be used to open and close namespace automatically within generated C++ code.

PiperOrigin-RevId: 618930720
pull/16273/head
Protobuf Team Bot 8 months ago committed by Copybara-Service
parent 6f1ef6f5b4
commit 8599ab5a59
  1. 18
      src/google/protobuf/compiler/cpp/BUILD.bazel
  2. 37
      src/google/protobuf/compiler/cpp/namespace_printer.cc
  3. 58
      src/google/protobuf/compiler/cpp/namespace_printer.h
  4. 78
      src/google/protobuf/compiler/cpp/namespace_printer_unittest.cc

@ -71,6 +71,7 @@ cc_library(
"generator.cc", "generator.cc",
"ifndef_guard.cc", "ifndef_guard.cc",
"message.cc", "message.cc",
"namespace_printer.cc",
"padding_optimizer.cc", "padding_optimizer.cc",
"parse_function_generator.cc", "parse_function_generator.cc",
"service.cc", "service.cc",
@ -86,6 +87,7 @@ cc_library(
"ifndef_guard.h", "ifndef_guard.h",
"message.h", "message.h",
"message_layout_helper.h", "message_layout_helper.h",
"namespace_printer.h",
"padding_optimizer.h", "padding_optimizer.h",
"parse_function_generator.h", "parse_function_generator.h",
"service.h", "service.h",
@ -359,6 +361,22 @@ cc_test(
], ],
) )
cc_test(
name = "namespace_printer_unittest",
srcs = ["namespace_printer_unittest.cc"],
deps = [
":cpp",
"//:protobuf",
"//src/google/protobuf/io",
"//src/google/protobuf/io:printer",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings:string_view",
"@com_google_absl//absl/types:optional",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
],
)
################################################################################ ################################################################################
# Distribution packaging # Distribution packaging
################################################################################ ################################################################################

@ -0,0 +1,37 @@
#include "google/protobuf/compiler/cpp/namespace_printer.h"
#include <string>
#include <utility>
#include <vector>
#include "absl/log/die_if_null.h"
#include "absl/strings/substitute.h"
#include "google/protobuf/io/printer.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
NamespacePrinter::NamespacePrinter(
google::protobuf::io::Printer* const p, std::vector<std::string> namespace_components)
: p_(ABSL_DIE_IF_NULL(p)),
namespace_components_(std::move(namespace_components)) {
// Open the namespace.
for (const std::string& ns : namespace_components_) {
p_->Print(absl::Substitute("namespace $0 {\n", ns));
}
p_->Print("\n");
}
NamespacePrinter::~NamespacePrinter() {
// Close the namespace.
for (const std::string& ns : namespace_components_) {
p_->Print(absl::Substitute("} // namespace $0\n", ns));
}
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google

@ -0,0 +1,58 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
// An RAII type for printing a namespace.
//
// Example:
// {
// Printer printer(output_stream.get(), '$');
// const NamespacePrinter namespace_printer(&printer, {"a", "b", "c"});
// // namespace opening will be opened here
// ...
// // namespace closing will be emitted here
// }
//
// By default, the filename will be converted to a macro by substituting '/' and
// '.' characters with '_'. If a different transformation is required, an
// optional transformation function can be provided.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_NAMESPACE_PRINTER_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_NAMESPACE_PRINTER_H__
#include <string>
#include <vector>
#include "google/protobuf/io/printer.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
// An RAII type for printing a namespace.
class PROTOC_EXPORT NamespacePrinter final {
public:
explicit NamespacePrinter(google::protobuf::io::Printer* p,
std::vector<std::string> namespace_components);
~NamespacePrinter();
private:
google::protobuf::io::Printer* const p_;
const std::vector<std::string> namespace_components_;
};
#include "google/protobuf/port_undef.inc"
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_NAMESPACE_PRINTER_H__

@ -0,0 +1,78 @@
#include "google/protobuf/compiler/cpp/namespace_printer.h"
#include <string>
#include <gtest/gtest.h>
#include "absl/log/absl_check.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "google/protobuf/io/printer.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
class NamespacePrinterTest : public testing::Test {
protected:
io::ZeroCopyOutputStream* output() {
ABSL_CHECK(stream_.has_value());
return &*stream_;
}
absl::string_view written() {
stream_.reset();
return out_;
}
std::string out_;
absl::optional<io::StringOutputStream> stream_{&out_};
};
TEST_F(NamespacePrinterTest, Basic) {
{
io::Printer printer(output(), '$');
const NamespacePrinter namespace_printer(&printer, {"A", "B", "E"});
EXPECT_FALSE(printer.failed());
}
EXPECT_EQ(written(),
"namespace A {\n"
"namespace B {\n"
"namespace E {\n"
"\n"
"} // namespace A\n"
"} // namespace B\n"
"} // namespace E\n");
}
TEST_F(NamespacePrinterTest, DifferentDelim) {
{
io::Printer printer(output(), '\0');
const NamespacePrinter namespace_printer(&printer, {"A", "B", "E"});
EXPECT_FALSE(printer.failed());
}
EXPECT_EQ(written(),
"namespace A {\n"
"namespace B {\n"
"namespace E {\n"
"\n"
"} // namespace A\n"
"} // namespace B\n"
"} // namespace E\n");
}
} // namespace
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google
Loading…
Cancel
Save