Skip to content

Commit 8c2c6d5

Browse files
cblichmanncopybara-github
authored andcommitted
Clang generator: Strip same namespace prefixes
This addresses cases where the requested namespace of the SAPI sandbox and the one of the type(s) to be emitted are the same. For example assumer the header contains a type ```c++ namespace apps::pdf::sandboxed { struct PageInfo; } ``` and the tequested namespace `apps::pdf::sandboxed`. Before this chage: ```c++ namespace apps::pdf::sandboxed { namespace apps::pdf::sandboxed { struct PageInfo; } } ``` After: ```c++ namespace apps::pdf::sandboxed { struct PageInfo; } ``` PiperOrigin-RevId: 785840598 Change-Id: I34a0e4a17d067ff9eee1e7bca188eaf2b70103ea
1 parent 175a082 commit 8c2c6d5

2 files changed

Lines changed: 104 additions & 10 deletions

File tree

sandboxed_api/tools/clang_generator/emitter.cc

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -275,24 +275,30 @@ absl::StatusOr<std::string> Emitter::DoEmitHeader() {
275275
// Emit type dependencies
276276
if (!rendered_types_ordered_.empty()) {
277277
absl::StrAppend(&out, "// Types this API depends on\n");
278-
std::string last_ns_name = options_.namespace_name;
278+
absl::string_view last_ns_name;
279+
const std::string ns_prefix = absl::StrCat(options_.namespace_name, "::");
279280
for (const RenderedType* rt : rendered_types_ordered_) {
280-
const auto& [ns_name, spelling] = *rt;
281-
if (last_ns_name != ns_name) {
282-
if (!last_ns_name.empty() && last_ns_name != options_.namespace_name) {
283-
absl::StrAppend(&out, "} // namespace ", last_ns_name, "\n\n");
284-
}
281+
absl::string_view ns_name = rt->ns_name;
282+
if (ns_name == options_.namespace_name) {
283+
ns_name = "";
284+
} else {
285+
absl::ConsumePrefix(&ns_name, ns_prefix);
286+
}
285287

286-
if (!ns_name.empty() && ns_name != options_.namespace_name) {
288+
if (ns_name != last_ns_name) {
289+
if (!last_ns_name.empty()) {
290+
absl::StrAppend(&out, "\n} // namespace ", last_ns_name, "\n");
291+
}
292+
if (!ns_name.empty()) {
287293
absl::StrAppend(&out, "namespace ", ns_name, " {\n");
288294
}
289295
last_ns_name = ns_name;
290296
}
291297

292-
absl::StrAppend(&out, spelling, ";\n");
298+
absl::StrAppend(&out, rt->spelling, ";\n");
293299
}
294-
if (!last_ns_name.empty() && last_ns_name != options_.namespace_name) {
295-
absl::StrAppend(&out, "} // namespace ", last_ns_name, "\n\n");
300+
if (!last_ns_name.empty()) {
301+
absl::StrAppend(&out, "\n} // namespace ", last_ns_name, "\n");
296302
}
297303
}
298304

sandboxed_api/tools/clang_generator/emitter_test.cc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "absl/status/statusor.h"
2727
#include "absl/strings/str_cat.h"
2828
#include "absl/strings/string_view.h"
29+
#include "sandboxed_api/testing.h"
2930
#include "sandboxed_api/tools/clang_generator/emitter_base.h"
3031
#include "sandboxed_api/tools/clang_generator/frontend_action_test_util.h"
3132
#include "sandboxed_api/tools/clang_generator/generator.h"
@@ -525,6 +526,93 @@ TEST_F(EmitterTest, SkipProtobufMessagesInternals) {
525526
ElementsAre("class MyMessage"));
526527
}
527528

529+
TEST_F(EmitterTest, Namespaced) {
530+
GeneratorOptions options;
531+
EmitterForTesting emitter(&options);
532+
EXPECT_THAT(
533+
RunFrontendAction(R"(namespace sandboxed {
534+
struct S { int member; };
535+
} // namespace sandboxed
536+
extern "C" sandboxed::S* Structize();)",
537+
std::make_unique<GeneratorAction>(&emitter, &options)),
538+
IsOk());
539+
EXPECT_THAT(emitter.GetRenderedFunctions(), SizeIs(1));
540+
541+
EXPECT_THAT(UglifyAll(emitter.SpellingsForNS("sandboxed")),
542+
ElementsAre("struct S { int member; }"));
543+
544+
SAPI_ASSERT_OK_AND_ASSIGN(std::string header, emitter.EmitHeader());
545+
// Expect the namespace to be preserved.
546+
EXPECT_THAT(header, HasSubstr("::absl::StatusOr<sandboxed::S*> Structize()"));
547+
}
548+
549+
TEST_F(EmitterTest, StripNamespacePrefix) {
550+
GeneratorOptions options;
551+
options.namespace_name = "sandboxed";
552+
EmitterForTesting emitter(&options);
553+
EXPECT_THAT(
554+
RunFrontendAction(R"(namespace sandboxed {
555+
struct S { int member; };
556+
} // namespace sandboxed
557+
extern "C" sandboxed::S* Structize();)",
558+
std::make_unique<GeneratorAction>(&emitter, &options)),
559+
IsOk());
560+
EXPECT_THAT(emitter.GetRenderedFunctions(), SizeIs(1));
561+
562+
EXPECT_THAT(UglifyAll(emitter.SpellingsForNS("sandboxed")),
563+
ElementsAre("struct S { int member; }"));
564+
565+
SAPI_ASSERT_OK_AND_ASSIGN(std::string header, emitter.EmitHeader());
566+
// Expect the namespace prefix to be stripped, as `Structize` will also be
567+
// emitted in the `sandboxed` namespace.
568+
EXPECT_THAT(header, HasSubstr("::absl::StatusOr<S*> Structize()"));
569+
}
570+
571+
TEST_F(EmitterTest, KeepTextualNamespacePrefix) {
572+
GeneratorOptions options;
573+
options.namespace_name = "sandboxed";
574+
EmitterForTesting emitter(&options);
575+
EXPECT_THAT(
576+
RunFrontendAction(R"(namespace sandboxed_ns {
577+
struct S { int member; };
578+
} // namespace sandboxed_ns
579+
extern "C" sandboxed_ns::S* Structize();)",
580+
std::make_unique<GeneratorAction>(&emitter, &options)),
581+
IsOk());
582+
EXPECT_THAT(emitter.GetRenderedFunctions(), SizeIs(1));
583+
584+
EXPECT_THAT(UglifyAll(emitter.SpellingsForNS("sandboxed_ns")),
585+
ElementsAre("struct S { int member; }"));
586+
587+
SAPI_ASSERT_OK_AND_ASSIGN(std::string header, emitter.EmitHeader());
588+
// Keep the namespace prefix, `sandboxed` and `sandboxed_ns` are different
589+
// namespaces.
590+
EXPECT_THAT(header,
591+
HasSubstr("::absl::StatusOr<sandboxed_ns::S*> Structize()"));
592+
}
593+
594+
TEST_F(EmitterTest, StripNamespacePrefixNested) {
595+
GeneratorOptions options;
596+
options.namespace_name = "sandboxed";
597+
EmitterForTesting emitter(&options);
598+
EXPECT_THAT(
599+
RunFrontendAction(R"(namespace sandboxed::nested {
600+
struct S { int member; };
601+
} // namespace sandboxed::nested
602+
extern "C" sandboxed::nested::S* Structize();)",
603+
std::make_unique<GeneratorAction>(&emitter, &options)),
604+
IsOk());
605+
EXPECT_THAT(emitter.GetRenderedFunctions(), SizeIs(1));
606+
607+
EXPECT_THAT(UglifyAll(emitter.SpellingsForNS("sandboxed::nested")),
608+
ElementsAre("struct S { int member; }"));
609+
610+
SAPI_ASSERT_OK_AND_ASSIGN(std::string header, emitter.EmitHeader());
611+
// Expect the namespace prefix to be stripped, similar to the
612+
// StripNamespacePrefix test.
613+
EXPECT_THAT(header, HasSubstr("::absl::StatusOr<nested::S*> Structize()"));
614+
}
615+
528616
TEST_F(EmitterTest, SymbolListTest) {
529617
constexpr absl::string_view kInputFile = "simple_functions.cc";
530618
GeneratorOptions options;

0 commit comments

Comments
 (0)