| // 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 |
| |
| #ifndef CRUBIT_RS_BINDINGS_FROM_CC_IMPORTER_H_ |
| #define CRUBIT_RS_BINDINGS_FROM_CC_IMPORTER_H_ |
| |
| #include <memory> |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <variant> |
| #include <vector> |
| |
| #include "absl/container/flat_hash_map.h" |
| #include "absl/container/flat_hash_set.h" |
| #include "absl/log/check.h" |
| #include "absl/log/die_if_null.h" |
| #include "absl/status/statusor.h" |
| #include "common/status_macros.h" |
| #include "lifetime_annotations/type_lifetimes.h" |
| #include "rs_bindings_from_cc/bazel_types.h" |
| #include "rs_bindings_from_cc/decl_importer.h" |
| #include "rs_bindings_from_cc/importers/class_template.h" |
| #include "rs_bindings_from_cc/importers/cxx_record.h" |
| #include "rs_bindings_from_cc/importers/enum.h" |
| #include "rs_bindings_from_cc/importers/friend.h" |
| #include "rs_bindings_from_cc/importers/function.h" |
| #include "rs_bindings_from_cc/importers/function_template.h" |
| #include "rs_bindings_from_cc/importers/namespace.h" |
| #include "rs_bindings_from_cc/importers/type_alias.h" |
| #include "rs_bindings_from_cc/importers/type_map_override.h" |
| #include "rs_bindings_from_cc/ir.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/DeclCXX.h" |
| #include "clang/AST/Mangle.h" |
| #include "clang/AST/RawCommentList.h" |
| #include "clang/AST/Type.h" |
| #include "clang/Basic/SourceLocation.h" |
| #include "clang/Sema/Sema.h" |
| |
| namespace crubit { |
| |
| // Iterates over the AST created from the invocation's entry headers and |
| // creates an intermediate representation of the import (`IR`) into the |
| // invocation object. |
| class Importer final : public ImportContext { |
| public: |
| explicit Importer(Invocation& invocation, clang::ASTContext& ctx, |
| clang::Sema& sema) |
| : ImportContext(invocation, ctx, sema), |
| mangler_(ABSL_DIE_IF_NULL(ctx_.createMangleContext())) { |
| decl_importers_.push_back(std::make_unique<TypeMapOverrideImporter>(*this)); |
| decl_importers_.push_back( |
| std::make_unique<ClassTemplateDeclImporter>(*this)); |
| decl_importers_.push_back(std::make_unique<CXXRecordDeclImporter>(*this)); |
| decl_importers_.push_back(std::make_unique<EnumDeclImporter>(*this)); |
| decl_importers_.push_back(std::make_unique<FriendDeclImporter>(*this)); |
| decl_importers_.push_back(std::make_unique<FunctionDeclImporter>(*this)); |
| decl_importers_.push_back( |
| std::make_unique<FunctionTemplateDeclImporter>(*this)); |
| decl_importers_.push_back(std::make_unique<NamespaceDeclImporter>(*this)); |
| decl_importers_.push_back(std::make_unique<TypeAliasImporter>(*this)); |
| } |
| |
| // Import all visible declarations from a translation unit. |
| void Import(clang::TranslationUnitDecl* decl); |
| |
| protected: |
| // Implementation of `ImportContext` |
| void ImportDeclsFromDeclContext( |
| const clang::DeclContext* decl_context) override; |
| IR::Item ImportUnsupportedItem(const clang::Decl* decl, |
| FormattedError error) override; |
| IR::Item ImportUnsupportedItem(const clang::Decl* decl, |
| std::vector<FormattedError> error) override; |
| IR::Item ImportUnsupportedItem(const clang::Decl* decl, |
| std::string message) override; |
| IR::Item ImportUnsupportedItem(const clang::Decl* decl, |
| std::set<std::string> messages) override; |
| std::optional<IR::Item> ImportDecl(clang::Decl* decl) override; |
| std::optional<IR::Item> GetImportedItem( |
| const clang::Decl* decl) const override; |
| |
| ItemId GenerateItemId(const clang::Decl* decl) const override; |
| ItemId GenerateItemId(const clang::RawComment* comment) const override; |
| bool IsUnsupportedAndAlien(ItemId item_id) const override; |
| absl::StatusOr<std::optional<ItemId>> GetEnclosingItemId( |
| clang::Decl* decl) override; |
| |
| std::vector<ItemId> GetItemIdsInSourceOrder(clang::Decl* decl) override; |
| std::string GetMangledName(const clang::NamedDecl* named_decl) const override; |
| BazelLabel GetOwningTarget(const clang::Decl* decl) const override; |
| bool IsFromCurrentTarget(const clang::Decl* decl) const override; |
| absl::StatusOr<UnqualifiedIdentifier> GetTranslatedName( |
| const clang::NamedDecl* named_decl) const override; |
| absl::StatusOr<Identifier> GetTranslatedIdentifier( |
| const clang::NamedDecl* named_decl) const override { |
| CRUBIT_ASSIGN_OR_RETURN(UnqualifiedIdentifier unqualified, |
| GetTranslatedName(named_decl)); |
| Identifier* identifier = std::get_if<Identifier>(&unqualified); |
| CHECK(identifier) << "Incorrectly called with a special name"; |
| return *identifier; |
| } |
| std::optional<std::string> GetComment(const clang::Decl* decl) const override; |
| std::string ConvertSourceLocation(clang::SourceLocation loc) const override; |
| absl::StatusOr<MappedType> ConvertQualType( |
| clang::QualType qual_type, |
| const clang::tidy::lifetimes::ValueLifetimes* lifetimes, |
| std::optional<clang::RefQualifierKind> ref_qualifier_kind, |
| bool nullable = true) override; |
| |
| void MarkAsSuccessfullyImported(const clang::NamedDecl* decl) override; |
| bool HasBeenAlreadySuccessfullyImported( |
| const clang::NamedDecl* decl) const override; |
| bool EnsureSuccessfullyImported(clang::NamedDecl* decl) override { |
| // First, return early so that we avoid re-entrant imports. |
| if (HasBeenAlreadySuccessfullyImported(decl)) return true; |
| (void)GetDeclItem(CanonicalizeDecl(decl)); |
| return HasBeenAlreadySuccessfullyImported(decl); |
| } |
| |
| private: |
| class SourceOrderKey; |
| class SourceLocationComparator; |
| |
| // Returns a SourceOrderKey for the given `decl` that should be used for |
| // ordering Items. |
| SourceOrderKey GetSourceOrderKey(const clang::Decl* decl) const; |
| // Returns a SourceOrderKey for the given `comment` that should be used for |
| // ordering Items. |
| SourceOrderKey GetSourceOrderKey(const clang::RawComment* comment) const; |
| |
| // Returns a name for `decl` that should be used for ordering declarations. |
| std::string GetNameForSourceOrder(const clang::Decl* decl) const; |
| |
| // Returns the item ids of template instantiations that have been triggered |
| // from the current target. The returned items are in an arbitrary, |
| // deterministic/reproducible order. |
| std::vector<ItemId> GetOrderedItemIdsOfTemplateInstantiations() const; |
| |
| std::optional<IR::Item> GetDeclItem(clang::Decl* decl) override; |
| // Stores the comments of this target in source order. |
| void ImportFreeComments(); |
| |
| clang::Decl* CanonicalizeDecl(clang::Decl* decl) const; |
| const clang::Decl* CanonicalizeDecl(const clang::Decl* decl) const; |
| |
| std::vector<clang::Decl*> GetCanonicalChildren( |
| const clang::DeclContext* decl_context) const; |
| // Converts a type to a MappedType. |
| // |
| // ref_qualifier_kind is the member function reference qualifier, e.g., `&` |
| // means Lvalue-reference-qualified, `&&` means Rvalue-reference-qualified. |
| // This is only meaningful and hence populated when converting the type of |
| // the `this` pointer. |
| absl::StatusOr<MappedType> ConvertType( |
| const clang::Type* type, |
| const clang::tidy::lifetimes::ValueLifetimes* lifetimes, |
| std::optional<clang::RefQualifierKind> ref_qualifier_kind, bool nullable); |
| // Converts a type, without processing attributes. |
| absl::StatusOr<MappedType> ConvertUnattributedType( |
| const clang::Type* type, |
| const clang::tidy::lifetimes::ValueLifetimes* lifetimes, |
| std::optional<clang::RefQualifierKind> ref_qualifier_kind, bool nullable); |
| absl::StatusOr<MappedType> ConvertTypeDecl(clang::NamedDecl* decl); |
| |
| // Converts `type` into a MappedType, after first importing the Record behind |
| // the template instantiation. |
| absl::StatusOr<MappedType> ConvertTemplateSpecializationType( |
| const clang::TemplateSpecializationType* type); |
| |
| // The different decl importers. Note that order matters: the first importer |
| // to successfully match a decl "wins", and no other importers are tried. |
| std::vector<std::unique_ptr<DeclImporter>> decl_importers_; |
| std::unique_ptr<clang::MangleContext> mangler_; |
| absl::flat_hash_map<const clang::Decl*, std::optional<IR::Item>> |
| import_cache_; |
| absl::flat_hash_set<const clang::ClassTemplateSpecializationDecl*> |
| class_template_instantiations_; |
| std::vector<const clang::RawComment*> comments_; |
| |
| // Set of decls that have been successfully imported (i.e. that will be |
| // present in the IR output / that will not produce dangling ItemIds in the IR |
| // output). |
| // |
| // Note that this includes non-TypeDecls in the form of using decls. |
| absl::flat_hash_set<const clang::NamedDecl*> known_type_decls_; |
| }; // class Importer |
| |
| } // namespace crubit |
| |
| #endif // CRUBIT_RS_BINDINGS_FROM_CC_IMPORTER_H_ |