Emit non-type template args as part of forward decls

This change allows us to emit forward declarations to classes that are
templated. For headers generated by the proto compiler this is sometimes
necessary.

Note:
- This will only emit types for a single level of template instantiations.
  That is, template template arguments are not supported.
- Typedefs only occurring in template arguments will be fully desugared
  and thus will not be available under their aliased name in the generated
  API code. This is consistent with the Python based generator (which
  does not emit these at all and relies on text extraction).

Signed-off-by: Christian Blichmann <cblichmann@google.com>
This commit is contained in:
Christian Blichmann 2020-10-23 19:21:55 +02:00
parent ea379ef4d6
commit 728355da87

View File

@ -26,6 +26,7 @@
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/strings/strip.h" #include "absl/strings/strip.h"
#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/Format/Format.h" #include "clang/Format/Format.h"
#include "sandboxed_api/tools/clang_generator/diagnostics.h" #include "sandboxed_api/tools/clang_generator/diagnostics.h"
@ -180,6 +181,37 @@ std::vector<std::string> GetNamespacePath(const clang::TypeDecl* decl) {
return comps; return comps;
} }
std::string PrintRecordTemplateArguments(const clang::CXXRecordDecl* record) {
const auto* template_inst_decl = record->getTemplateInstantiationPattern();
if (!template_inst_decl) {
return "";
}
const auto* template_decl = template_inst_decl->getDescribedClassTemplate();
if (!template_decl) {
return "";
}
const auto* template_params = template_decl->getTemplateParameters();
if (!template_params) {
return "";
}
std::vector<std::string> params;
params.reserve(template_params->size());
for (const auto& template_param : *template_params) {
if (const auto* p =
llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(template_param)) {
// TODO(cblichmann): These types should be included by
// CollectRelatedTypes().
params.push_back(
p->getType().getDesugaredType(record->getASTContext()).getAsString());
} else { // Also covers template template parameters
params.push_back("typename");
}
absl::StrAppend(&params.back(), " /*",
std::string(template_param->getName()), "*/");
}
return absl::StrCat("template <", absl::StrJoin(params, ", "), ">");
}
// Serializes the given Clang AST declaration back into compilable source code. // Serializes the given Clang AST declaration back into compilable source code.
std::string PrintAstDecl(const clang::Decl* decl) { std::string PrintAstDecl(const clang::Decl* decl) {
// TODO(cblichmann): Make types nicer // TODO(cblichmann): Make types nicer
@ -188,7 +220,8 @@ std::string PrintAstDecl(const clang::Decl* decl) {
if (const auto* record = llvm::dyn_cast<clang::CXXRecordDecl>(decl)) { if (const auto* record = llvm::dyn_cast<clang::CXXRecordDecl>(decl)) {
// For C++ classes/structs, only emit a forward declaration. // For C++ classes/structs, only emit a forward declaration.
return absl::StrCat(record->isClass() ? "class " : "struct ", return absl::StrCat(PrintRecordTemplateArguments(record),
record->isClass() ? "class " : "struct ",
std::string(record->getName())); std::string(record->getName()));
} }
std::string pretty; std::string pretty;