29 static frxml::dom dom = frxml::dom::element(
"assembly");
34 clang::CompilerInstance& ci,
37 return std::make_unique<LilacASTConsumer>(
GetDOMRoot());
52 visitor.TraverseDecl(context.getTranslationUnitDecl());
55 frxml::dom* LilacASTVisitor::GetNamespaceDOM(clang::NamedDecl* decl)
const
57 const auto ctx = decl->getDeclContext();
59 if (
const auto parent = ctx;
61 parent->getDeclKind() != clang::Decl::Namespace &&
62 parent->getDeclKind() != clang::Decl::TranslationUnit)
64 static auto err = m_Diag.getCustomDiagID(
66 "Couldn't handle a nested declaration");
68 m_Sema.Diag(decl->getLocation(), err);
73 std::stack<clang::NamespaceDecl*> stk;
76 cur !=
nullptr && cur->getDeclKind() == clang::Decl::Namespace;
77 cur = cur->getParent())
79 stk.emplace(clang::cast<clang::NamespaceDecl>(cur));
82 frxml::dom* cur = &m_Root;
83 for (; !stk.empty(); stk.pop())
85 frxml::dom* node =
nullptr;
87 auto ns = stk.top()->getNameAsString();
88 for (
auto& child: cur->children())
90 if (child.tag().view() !=
"namespace")
92 if (child.attr()[
"name"].view() == ns)
97 node = &cur->children().emplace_back(frxml::dom::element(
110 m_Diag(m_Sema.getDiagnostics()),
117 auto exported =
false;
119 if (clang::isa<clang::TagDecl>(decl))
121 for (
const auto attr: decl->attrs())
123 if (
const auto anot = clang::dyn_cast<clang::AnnotateTypeAttr>(attr);
133 for (
const auto attr: decl->attrs())
135 if (
const auto anot = clang::dyn_cast<clang::AnnotateAttr>(attr);
147 bool LilacASTVisitor::IsDuplicated(clang::NamedDecl* decl,
const std::string& tag)
149 const auto ns = GetNamespaceDOM(decl);
150 if (!ns)
return true;
153 for (
auto& child: ns->children())
155 const auto name = clang::isa<clang::FunctionDecl>(decl)
156 ? clang::ASTNameGenerator(decl->getASTContext()).getName(decl)
157 : decl->getNameAsString();
159 if (child.tag().view() != tag ||
160 child.attr()[
"name"].view() != name)
174 if (IsDuplicated(decl,
"enum"))
177 std::vector<frxml::dom> children;
180 [&](
const clang::EnumConstantDecl* constant)
182 const auto value = constant->getValue();
183 const auto valueStr = decl->getIntegerType()->isSignedIntegerType()
184 ? std::to_string(value.getSExtValue())
185 : std::to_string(value.getZExtValue());
187 children.push_back(frxml::dom::element(
190 {
"name", constant->getNameAsString() },
191 {
"value", valueStr }
195 visitor.TraverseDecl(decl);
197 auto kind = clang::BuiltinType::Kind::Int;
199 if (
const auto underlyingT = decl->getIntegerType(); !underlyingT.isNull())
201 const auto type = underlyingT->getUnqualifiedDesugaredType();
202 if (!type->isBuiltinType())
204 static auto err = m_Diag.getCustomDiagID(
206 "Couldn't use non-builtin type as enumeration type");
207 m_Sema.Diag(decl->getLocation(), err);
212 kind = clang::cast<clang::BuiltinType>(type)->getKind();
215 const auto ns = GetNamespaceDOM(decl);
216 if (!ns)
return true;
217 ns->children().push_back(frxml::dom::element(
220 {
"name", decl->getNameAsString() },
230 const clang::SourceLocation loc,
231 const clang::Type* type,
234 type = type->getUnqualifiedDesugaredType();
236 for (nRef = 0; type->isPointerOrReferenceType(); ++nRef)
237 type = type->getPointeeType()->getUnqualifiedDesugaredType();
239 if (type->isBuiltinType())
241 name =
GetBuiltinTypeName(clang::cast<clang::BuiltinType>(type)->getKind()) + std::string(nRef,
'*');
245 if (type->isFunctionType())
247 static auto err = sema.getDiagnostics().getCustomDiagID(
248 clang::DiagnosticsEngine::Error,
249 "Function types cannot be exported");
255 if (!type->getAsRecordDecl())
257 static auto err = sema.getDiagnostics().getCustomDiagID(
258 clang::DiagnosticsEngine::Error,
259 "Exported types must be built-in or convertible to record declaration");
265 if (
const auto parent = type->getAsRecordDecl()->getParent();
267 parent->getDeclKind() != clang::Decl::Namespace &&
268 parent->getDeclKind() != clang::Decl::TranslationUnit)
270 static auto err = sema.getDiagnostics().getCustomDiagID(
271 clang::DiagnosticsEngine::Error,
272 "Exported types must be in namespace or global");
278 std::stack<std::string> stk;
280 auto decl = type->getAsRecordDecl()->getParent();
281 decl !=
nullptr && decl->getDeclKind() == clang::Decl::Namespace;
282 decl = decl->getParent())
284 stk.push(clang::cast<clang::NamespaceDecl>(decl)->getNameAsString());
287 std::stringstream ss;
288 for (; !stk.empty(); stk.pop())
290 ss << stk.top() <<
'/';
292 ss << type->getAsRecordDecl()->getNameAsString();
293 ss << std::string(nRef,
'*');
301 for (
const auto parameter: fn->parameters())
306 parameter->getLocation(),
307 parameter->getType()->getUnqualifiedDesugaredType(),
313 dom.children().push_back(frxml::dom::element(
316 {
"name", parameter->getNameAsString() },
327 clang::FunctionDecl* fn)
329 static std::map<clang::Decl::Kind, std::string> tagMap = {
330 { clang::Decl::CXXMethod,
"method" },
331 { clang::Decl::CXXConstructor,
"ctor" },
332 { clang::Decl::CXXDestructor,
"dtor" }
334 std::string tag =
"function";
335 if (!fn->isStatic() && tagMap.contains(fn->getKind()))
336 tag = tagMap[fn->getKind()];
339 std::string virtuality =
"none";
340 if (
const auto method = clang::dyn_cast<clang::CXXMethodDecl>(fn); method && method->isVirtual())
342 virtuality =
"virtual";
343 for (
const auto attr: method->attrs())
344 if (attr->getKind() == clang::attr::Final)
345 virtuality =
"final";
349 const auto proto = fn->getType()->getAs<clang::FunctionProtoType>();
350 const auto callconv = clang::FunctionType::getNameForCallConv(proto->getCallConv());
352 clang::ASTNameGenerator ang(fn->getASTContext());
354 auto dom = frxml::dom::element(
357 {
"mangle", ang.getName(fn) },
358 {
"callconv", callconv.str() },
359 {
"virtual", virtuality }
362 if (fn->getKind() != clang::Decl::CXXConstructor &&
363 fn->getKind() != clang::Decl::CXXDestructor)
366 if (!
GetTypeName(sema, fn->getLocation(), fn->getReturnType().getTypePtr(), ret))
369 dom.attr().emplace(
"name", fn->getNameAsString());
370 dom.attr().emplace(
"return", ret);
384 if (IsDuplicated(decl,
"record"))
387 std::vector<frxml::dom> children;
389 static auto recordErr = m_Sema.getDiagnostics().getCustomDiagID(
391 "CXXMethod cannot be exported");
395 [&](clang::CXXMethodDecl* method)
403 m_Sema.Diag(method->getLocation(), recordErr);
407 children.push_back(dom.value());
410 visitor.TraverseDecl(decl);
413 if (
const auto dtor = decl->getDestructor())
418 m_Sema.Diag(dtor->getLocation(), recordErr);
422 children.push_back(dom.value());
425 const auto ns = GetNamespaceDOM(decl);
426 if (!ns)
return true;
428 const auto typeInfo = decl->getASTContext().getTypeInfo(decl->getTypeForDecl());
430 const auto size = typeInfo.Width;
431 const auto align = typeInfo.Align;
432 if (size % 8 || align % 8)
434 static auto err = m_Diag.getCustomDiagID(
436 "A size and alignment of record must be multiple of bytes");
437 m_Sema.Diag(decl->getLocation(), err);
440 ns->children().push_back(frxml::dom::element(
443 {
"name", decl->getNameAsString() },
444 {
"size", std::to_string(size / 8) },
445 {
"align", std::to_string(align / 8) }
457 if (clang::isa<clang::CXXMethodDecl>(decl))
460 if (IsDuplicated(decl,
"function"))
466 static auto err = m_Sema.getDiagnostics().getCustomDiagID(
468 "FunctionDecl cannot be exported");
469 m_Sema.Diag(decl->getLocation(), err);
473 const auto ns = GetNamespaceDOM(decl);
474 if (!ns)
return true;
476 ns->children().push_back(dom.value());
481 : m_Delegate(std::move(delegate))
493 : m_Delegate(std::move(delegate))
static constexpr std::string AttrMangling
void InitializeSema(clang::Sema &sema) override
LilacASTConsumer(frxml::dom &dom)
void HandleTranslationUnit(clang::ASTContext &context) override
A recursive AST visitor that traverses AST of an enumeration.
bool TraverseCXXMethodDecl(clang::CXXMethodDecl *decl)
CXXRecordVisitor(std::function< void(clang::CXXMethodDecl *)> delegate)
A recursive AST visitor that traverses AST of an enumeration.
EnumVisitor(std::function< void(clang::EnumConstantDecl *constant)>)
bool TraverseEnumConstantDecl(clang::EnumConstantDecl *decl)
A recursive AST visitor that serializes C/C++ interface data into DOM object.
bool TraverseCXXRecordDecl(clang::CXXRecordDecl *decl)
bool TraverseEnumDecl(clang::EnumDecl *decl)
LilacASTVisitor(clang::Sema &sema, frxml::dom &dom)
bool TraverseFunctionDecl(clang::FunctionDecl *decl)
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(clang::CompilerInstance &, llvm::StringRef) override
frxml::dom & GetDOMRoot()
bool ShouldBeExported(clang::NamedDecl *decl)
bool GetTypeName(clang::Sema &sema, const clang::SourceLocation loc, const clang::Type *type, std::string &name)
std::optional< frxml::dom > RecordFunction(clang::Sema &sema, clang::FunctionDecl *fn)
constexpr std::string GetBuiltinTypeName(clang::BuiltinType::Kind kind)
bool RecordParameters(clang::Sema &sema, frxml::dom &dom, clang::FunctionDecl *fn)