| // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| // Exceptions. See /LICENSE for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| |
| #include "rs_bindings_from_cc/ast_visitor.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "rs_bindings_from_cc/ir.h" |
| #include "third_party/absl/container/flat_hash_set.h" |
| #include "third_party/absl/strings/cord.h" |
| #include "third_party/llvm/llvm-project/clang/include/clang/AST/ASTContext.h" |
| #include "third_party/llvm/llvm-project/clang/include/clang/AST/Decl.h" |
| #include "third_party/llvm/llvm-project/clang/include/clang/AST/Mangle.h" |
| #include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h" |
| |
| namespace rs_bindings_from_cc { |
| |
| bool AstVisitor::TraverseDecl(clang::Decl* decl) { |
| if (seen_decls_.insert(decl->getCanonicalDecl()).second) { |
| return Base::TraverseDecl(decl); |
| } |
| return false; |
| } |
| |
| bool AstVisitor::TraverseTranslationUnitDecl( |
| clang::TranslationUnitDecl* translation_unit_decl) { |
| mangler_.reset(translation_unit_decl->getASTContext().createMangleContext()); |
| |
| // TODO(hlopko): Make the generated C++ code include-what-you-use clean. |
| // Currently we pass public headers of the library to the src_code_gen. |
| // Through those Clang has access to all declarations needed by the public API |
| // of the library. However the code violates IWYU - it will not directly |
| // include all the headers declaring names used in the generated source. This |
| // could be fixed by passing not only public headers of the library to the |
| // tool, but also all public headers of the direct dependencies of the |
| // library. This way if the library was IWYU clean, the generated code will be |
| // too. |
| for (const std::string& header : public_headers_) { |
| ir_.UsedHeaders().emplace_back(HeaderName(absl::Cord(header))); |
| } |
| |
| return Base::TraverseTranslationUnitDecl(translation_unit_decl); |
| } |
| |
| bool AstVisitor::VisitFunctionDecl(clang::FunctionDecl* function_decl) { |
| // TODO(hlopko): Skip decls from other headers |
| // TODO(hlopko): Generate thunks + C++ impls for inline functions |
| // TODO(hlopko): Handle lowercased snakecased conflicts |
| // TODO(hlopko): Convert primitive types (bool -> bool, int -> i64 (?) and |
| // so on) |
| // TODO(hlopko): Import return type properly |
| // TODO(hlopko): Import parameter types properly |
| // TODO(hlopko): Import clang doc comment |
| // TODO(hlopko): Handle member functions |
| // TODO(hlopko): Handle static member functions |
| // TODO(hlopko): Handle constructors/operators/special members |
| // TODO(hlopko): Handle destructors |
| // TODO(hlopko): Do not import deleted members |
| // TODO(hlopko): Handle function templates |
| // TODO(hlopko): Do not import private/protected members |
| // TODO(hlopko): Handle (?) variadic functions |
| // TODO(hlopko): Fail when exceptions enabled? |
| std::vector<FuncParam> params; |
| for (const clang::ParmVarDecl* param : function_decl->parameters()) { |
| params.emplace_back(ConvertType(param->getType()), |
| GetTranslatedName(param)); |
| } |
| |
| ir_.Functions().emplace_back( |
| GetTranslatedName(function_decl), GetMangledName(function_decl), |
| ConvertType(function_decl->getReturnType()), params); |
| return true; |
| } |
| |
| Type AstVisitor::ConvertType(clang::QualType qual_type) const { |
| // TODO(hlopko): Handle all builtin types |
| // TODO(hlopko): Handle user-defined types |
| // TODO(hlopko): Handle user-defined types defined elsewhere (with fully |
| // qualified paths) |
| if (const clang::BuiltinType* builtin_type = |
| qual_type->getAs<clang::BuiltinType>()) { |
| if (builtin_type->isIntegerType()) { |
| // TODO(hlopko): look at the actual width of the type. |
| return Type(absl::Cord("i32")); |
| } |
| if (builtin_type->isVoidType()) { |
| return Type::Void(); |
| } |
| } |
| LOG(FATAL) << "Unsupported type " << qual_type.getAsString() << "\n"; |
| } |
| |
| absl::Cord AstVisitor::GetMangledName( |
| const clang::NamedDecl* named_decl) const { |
| std::string name; |
| llvm::raw_string_ostream stream(name); |
| mangler_->mangleName(named_decl, stream); |
| stream.flush(); |
| return absl::Cord(std::move(name)); |
| } |
| |
| Identifier AstVisitor::GetTranslatedName( |
| const clang::NamedDecl* named_decl) const { |
| // TODO(hlopko): handle the case where the name is not a simple identifier. |
| return Identifier(absl::Cord(named_decl->getName())); |
| } |
| |
| } // namespace rs_bindings_from_cc |