2323#include " absl/strings/match.h"
2424#include " absl/strings/str_cat.h"
2525#include " absl/strings/str_join.h"
26+ #include " absl/strings/str_replace.h"
2627#include " absl/strings/string_view.h"
2728#include " clang/AST/ASTContext.h"
2829#include " clang/AST/Decl.h"
@@ -57,8 +58,10 @@ bool IsProtoBuf(const clang::RecordDecl* decl) {
5758//
5859// This function handles some special cases, such as function pointers and
5960// enums. In case of enums it preserves the enum keyword in the name.
60- std::string GetQualTypeName (const clang::ASTContext& context,
61- clang::QualType qual) {
61+ std::string GetFullyQualifiedName (const clang::ASTContext& context,
62+ clang::QualType qual,
63+ absl::string_view ns_to_strip = " " ,
64+ bool suppress_enum_keyword = true ) {
6265 // Remove any "const", "volatile", etc. except for those added via typedefs.
6366 clang::QualType unqual = qual.getLocalUnqualifiedType ();
6467
@@ -68,19 +71,24 @@ std::string GetQualTypeName(const clang::ASTContext& context,
6871 unqual = unqual->getPointeeType ();
6972 }
7073
71- if (unqual->isEnumeralType ()) {
72- auto decl = unqual->getAsTagDecl ();
73- if (decl) {
74- // Keep the "enum" keyword in the type name.
75- clang::PrintingPolicy policy = context.getPrintingPolicy ();
76- policy.SuppressTagKeyword = false ;
77- return clang::TypeName::getFullyQualifiedName (unqual, context, policy);
78- }
74+ clang::PrintingPolicy policy = context.getPrintingPolicy ();
75+ if (!suppress_enum_keyword && unqual->isEnumeralType () &&
76+ unqual->getAsTagDecl () != nullptr ) {
77+ // Keep the "enum" keyword in the type name.
78+ policy.SuppressTagKeyword = false ;
79+ }
80+
81+ // Get the fully qualified name without the "struct" or "class" keyword.
82+ std::string qual_name =
83+ clang::TypeName::getFullyQualifiedName (unqual, context, policy);
84+
85+ if (!ns_to_strip.empty ()) {
86+ // Remove the namespace prefix if requested. This is using a textual
87+ // replacement for ease of implementation. A fully generic solution would
88+ // require to implement a custom printer for the QualType.
89+ absl::StrReplaceAll ({{absl::StrCat (ns_to_strip, " ::" ), " " }}, &qual_name);
7990 }
80- // Return the fully qualified name without the "enum", "struct" or "class"
81- // keyword.
82- return clang::TypeName::getFullyQualifiedName (unqual, context,
83- context.getPrintingPolicy ());
91+ return qual_name;
8492}
8593
8694// Returns the namespace components of a declaration's qualified name.
@@ -216,7 +224,8 @@ std::vector<NamespacedTypeDecl> TypeCollector::GetTypeDeclarations() {
216224 // only emit type declarations of required types.
217225 absl::flat_hash_set<std::string> collected_names;
218226 for (clang::QualType qual : collected_) {
219- const std::string qual_name = GetQualTypeName (context, qual);
227+ const std::string qual_name = GetFullyQualifiedName (
228+ context, qual, /* ns_to_strip=*/ " " , /* suppress_enum_keyword=*/ false );
220229 collected_names.insert (qual_name);
221230 }
222231
@@ -245,7 +254,9 @@ std::vector<NamespacedTypeDecl> TypeCollector::GetTypeDeclarations() {
245254 // different Type pointers, even when referring to one of the same types
246255 // from the set and thus will not be found. Instead, work around the issue
247256 // by always using the fully qualified name of the type.
248- const std::string qual_name = GetQualTypeName (context, type_decl_type);
257+ const std::string qual_name =
258+ GetFullyQualifiedName (context, type_decl_type, /* ns_to_strip=*/ " " ,
259+ /* suppress_enum_keyword=*/ false );
249260 if (!collected_names.contains (qual_name)) {
250261 continue ;
251262 }
@@ -381,28 +392,28 @@ std::string TypeMapper::MapQualType(clang::QualType qual) const {
381392 }
382393 } else if (const auto * enum_type = qual->getAs <clang::EnumType>()) {
383394 clang::EnumDecl* enum_decl = enum_type->getDecl ();
384- std::string name;
385- if (auto * typedef_name = enum_decl->getTypedefNameForAnonDecl ()) {
386- name = typedef_name->getQualifiedNameAsString ();
387- } else {
388- name = enum_decl->getQualifiedNameAsString ();
395+ if (auto * typedef_decl = enum_decl->getTypedefNameForAnonDecl ()) {
396+ qual = typedef_decl->getUnderlyingType ().getDesugaredType (context_);
389397 }
390- return absl::StrCat (" ::sapi::v::IntBase<" , name, " >" );
398+ return absl::StrCat (" ::sapi::v::IntBase<" ,
399+ GetFullyQualifiedName (context_, qual, ns_to_strip_),
400+ " >" );
391401 } else if (IsPointerOrReference (qual)) {
392402 // Remove "const" qualifier from a pointer or reference type's pointee, as
393403 // e.g. const pointers do not work well with SAPI.
394- return absl::StrCat (" ::sapi::v::Reg< " ,
395- clang::TypeName::getFullyQualifiedName (
396- MaybeRemoveConst (context_, qual), context_ ,
397- context_. getPrintingPolicy () ),
398- " >" );
404+ return absl::StrCat (
405+ " ::sapi::v::Reg< " ,
406+ GetFullyQualifiedName (context_, MaybeRemoveConst (context_, qual),
407+ ns_to_strip_ ),
408+ " >" );
399409 }
410+
400411 // Best-effort mapping to "int", leave a comment.
401- return absl::StrCat (" ::sapi::v::Int /* aka ' " ,
402- clang::TypeName::getFullyQualifiedName (
403- MaybeRemoveConst (context_, qual), context_ ,
404- context_. getPrintingPolicy () ),
405- " ' */" );
412+ return absl::StrCat (
413+ " ::sapi::v::Int /* aka ' " ,
414+ GetFullyQualifiedName (context_, MaybeRemoveConst (context_, qual),
415+ ns_to_strip_ ),
416+ " ' */" );
406417}
407418
408419std::string TypeMapper::MapQualTypeParameterForCxx (clang::QualType qual) const {
@@ -414,8 +425,7 @@ std::string TypeMapper::MapQualTypeParameterForCxx(clang::QualType qual) const {
414425 // - long long -> uint64_t
415426 // - ...
416427 }
417- return clang::TypeName::getFullyQualifiedName (qual, context_,
418- context_.getPrintingPolicy ());
428+ return GetFullyQualifiedName (context_, qual, ns_to_strip_);
419429}
420430
421431std::string TypeMapper::MapQualTypeParameter (clang::QualType qual) const {
0 commit comments