-
Notifications
You must be signed in to change notification settings - Fork 15.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an RAII ifndef helper for C++ codegen.
This can be used in headers to automatically generate ifdef guards. PiperOrigin-RevId: 618204633
- Loading branch information
1 parent
eef5564
commit 1087274
Showing
5 changed files
with
283 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Utilities for generating C++ code | ||
|
||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") | ||
load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix") | ||
load("//build_defs:cpp_opts.bzl", "COPTS") | ||
|
||
package( | ||
default_visibility = ["//visibility:public"], | ||
) | ||
|
||
cc_library( | ||
name = "ifndef_guard", | ||
srcs = ["ifndef_guard.cc"], | ||
hdrs = ["ifndef_guard.h"], | ||
copts = COPTS, | ||
strip_include_prefix = "/src", | ||
deps = [ | ||
"//src/google/protobuf/io:printer", | ||
"@com_google_absl//absl/functional:any_invocable", | ||
"@com_google_absl//absl/log:die_if_null", | ||
"@com_google_absl//absl/strings", | ||
"@com_google_absl//absl/strings:string_view", | ||
], | ||
) | ||
|
||
cc_test( | ||
name = "ifndef_guard_unittest", | ||
srcs = ["ifndef_guard_unittest.cc"], | ||
deps = [ | ||
":ifndef_guard", | ||
"//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 | ||
################################################################################ | ||
|
||
pkg_files( | ||
name = "dist_files", | ||
srcs = glob(["**/*"]), | ||
strip_prefix = strip_prefix.from_root(""), | ||
visibility = ["//src:__pkg__"], | ||
) | ||
|
||
filegroup( | ||
name = "test_srcs", | ||
srcs = glob([ | ||
"*unittest.cc", | ||
]), | ||
visibility = ["//pkg:__pkg__"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Protocol Buffers - Google's data interchange format | ||
// Copyright 2024 Google LLC. 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 | ||
|
||
#include "google/protobuf/io/cpp_utils/ifndef_guard.h" | ||
|
||
#include <string> | ||
|
||
#include "absl/functional/any_invocable.h" | ||
#include "absl/log/die_if_null.h" | ||
#include "absl/strings/ascii.h" | ||
#include "absl/strings/str_cat.h" | ||
#include "absl/strings/str_replace.h" | ||
#include "absl/strings/string_view.h" | ||
#include "absl/strings/substitute.h" | ||
#include "google/protobuf/io/printer.h" | ||
|
||
namespace google { | ||
namespace protobuf { | ||
namespace io { | ||
namespace cpp { | ||
|
||
namespace { | ||
|
||
std::string MakeIfdefGuardIdentifier(const absl::string_view header_path) { | ||
return absl::StrCat(absl::AsciiStrToUpper(absl::StrReplaceAll(header_path, | ||
{ | ||
{"/", "_"}, | ||
{".", "_"}, | ||
})), | ||
"_"); | ||
} | ||
|
||
} // namespace | ||
|
||
IfdefGuardPrinter::IfdefGuardPrinter(google::protobuf::io::Printer* const p, | ||
const absl::string_view filename) | ||
: IfdefGuardPrinter(p, filename, MakeIfdefGuardIdentifier) {} | ||
|
||
IfdefGuardPrinter::IfdefGuardPrinter( | ||
google::protobuf::io::Printer* const p, const absl::string_view filename, | ||
absl::AnyInvocable<std::string(absl::string_view)> make_ifdef_identifier) | ||
: p_(ABSL_DIE_IF_NULL(p)), | ||
ifdef_identifier_(make_ifdef_identifier(filename)) { | ||
// We can't use variable substitution, because we don't know what delimiter | ||
// to use. | ||
p->Print(absl::Substitute( | ||
R"(#ifndef $0 | ||
#define $0 | ||
)", | ||
ifdef_identifier_)); | ||
} | ||
|
||
IfdefGuardPrinter::~IfdefGuardPrinter() { | ||
// We can't use variable substitution, because we don't know what delimiter | ||
// to use. | ||
p_->Print(absl::Substitute( | ||
R"( | ||
#endif // $0 | ||
)", | ||
ifdef_identifier_)); | ||
} | ||
|
||
} // namespace cpp | ||
} // namespace io | ||
} // namespace protobuf | ||
} // namespace google |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// 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 an ifdef guard. | ||
// | ||
// This can be used to ensure that appropriate ifdef guards are applied in | ||
// a generated header file. | ||
// | ||
// Example: | ||
// { | ||
// Printer printer(output_stream.get(), '$'); | ||
// const IfdefGuardPrinter ifdef_guard(&printer, output_path); | ||
// // #ifdef guard will be emitted here | ||
// ... | ||
// // #endif 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_IO_CPP_UTILS_IFNDEF_GUARD_H__ | ||
#define GOOGLE_PROTOBUF_IO_CPP_UTILS_IFNDEF_GUARD_H__ | ||
|
||
#include <string> | ||
|
||
#include "absl/functional/any_invocable.h" | ||
#include "absl/strings/string_view.h" | ||
#include "google/protobuf/io/printer.h" | ||
|
||
namespace google { | ||
namespace protobuf { | ||
namespace io { | ||
namespace cpp { | ||
|
||
class IfdefGuardPrinter final { | ||
public: | ||
explicit IfdefGuardPrinter(google::protobuf::io::Printer* p, | ||
absl::string_view filename); | ||
|
||
explicit IfdefGuardPrinter( | ||
google::protobuf::io::Printer* p, absl::string_view filename, | ||
absl::AnyInvocable<std::string(absl::string_view)> make_ifdef_identifier); | ||
|
||
~IfdefGuardPrinter(); | ||
|
||
private: | ||
google::protobuf::io::Printer* const p_; | ||
const std::string ifdef_identifier_; | ||
}; | ||
|
||
} // namespace cpp | ||
} // namespace io | ||
} // namespace protobuf | ||
} // namespace google | ||
|
||
#endif // GOOGLE_PROTOBUF_IO_CPP_UTILS_IFNDEF_GUARD_H__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#include "google/protobuf/io/cpp_utils/ifndef_guard.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 io { | ||
namespace cpp { | ||
|
||
namespace { | ||
|
||
class IfnDefGuardTest : public testing::Test { | ||
protected: | ||
ZeroCopyOutputStream* output() { | ||
ABSL_CHECK(stream_.has_value()); | ||
return &*stream_; | ||
} | ||
absl::string_view written() { | ||
stream_.reset(); | ||
return out_; | ||
} | ||
|
||
std::string out_; | ||
absl::optional<StringOutputStream> stream_{&out_}; | ||
}; | ||
|
||
TEST_F(IfnDefGuardTest, Basic) { | ||
{ | ||
Printer printer(output(), '$'); | ||
|
||
const IfdefGuardPrinter ifdef_guard(&printer, "A/B/E/alpha"); | ||
|
||
EXPECT_FALSE(printer.failed()); | ||
} | ||
|
||
EXPECT_EQ(written(), | ||
"#ifndef A_B_E_ALPHA_\n" | ||
"#define A_B_E_ALPHA_\n" | ||
"\n" | ||
"\n" | ||
"#endif // A_B_E_ALPHA_\n"); | ||
} | ||
|
||
TEST_F(IfnDefGuardTest, DifferentDelim) { | ||
{ | ||
Printer printer(output(), '\0'); | ||
|
||
const IfdefGuardPrinter ifdef_guard(&printer, "A/B/E/alpha"); | ||
|
||
EXPECT_FALSE(printer.failed()); | ||
} | ||
|
||
EXPECT_EQ(written(), | ||
"#ifndef A_B_E_ALPHA_\n" | ||
"#define A_B_E_ALPHA_\n" | ||
"\n" | ||
"\n" | ||
"#endif // A_B_E_ALPHA_\n"); | ||
} | ||
|
||
TEST_F(IfnDefGuardTest, DifferentSubstitutionFunction) { | ||
{ | ||
Printer printer(output(), '$'); | ||
|
||
const IfdefGuardPrinter ifdef_guard( | ||
&printer, "A/B/E/alpha", [](absl::string_view) { return "FOO_BAR_"; }); | ||
|
||
EXPECT_FALSE(printer.failed()); | ||
} | ||
|
||
EXPECT_EQ(written(), | ||
"#ifndef FOO_BAR_\n" | ||
"#define FOO_BAR_\n" | ||
"\n" | ||
"\n" | ||
"#endif // FOO_BAR_\n"); | ||
} | ||
|
||
} // namespace | ||
} // namespace cpp | ||
} // namespace io | ||
|
||
} // namespace protobuf | ||
} // namespace google |