blob: 00a4e5ea96fbbc42397eb773d974fc31621593fc [file] [log] [blame]
// 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 <utility>
#include <vector>
#include "absl/log/die_if_null.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/typedef_name.h"
#include "rs_bindings_from_cc/ir.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RawCommentList.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<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<TypedefNameDeclImporter>(*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,
std::string error) override;
IR::Item ImportUnsupportedItem(const clang::Decl* decl,
std::set<std::string> errors) override;
std::optional<IR::Item> ImportDecl(clang::Decl* decl) override;
std::optional<IR::Item> GetImportedItem(const 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;
std::optional<UnqualifiedIdentifier> GetTranslatedName(
const clang::NamedDecl* named_decl) const override;
std::optional<Identifier> GetTranslatedIdentifier(
const clang::NamedDecl* named_decl) const override {
if (std::optional<UnqualifiedIdentifier> name =
GetTranslatedName(named_decl)) {
return std::move(*std::get_if<Identifier>(&*name));
}
return std::nullopt;
}
llvm::Optional<std::string> GetComment(
const clang::Decl* decl) const override;
SourceLoc ConvertSourceLocation(clang::SourceLocation loc) const override;
absl::StatusOr<MappedType> ConvertQualType(
clang::QualType qual_type,
std::optional<clang::tidy::lifetimes::ValueLifetimes>& lifetimes,
bool nullable = true) override;
void MarkAsSuccessfullyImported(const clang::TypeDecl* decl) override;
bool HasBeenAlreadySuccessfullyImported(
const clang::TypeDecl* decl) const override;
bool EnsureSuccessfullyImported(clang::TypeDecl* decl) override {
// First, return early so that we avoid re-entrant imports.
if (HasBeenAlreadySuccessfullyImported(decl)) return true;
(void)GetDeclItem(decl->getCanonicalDecl());
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();
absl::StatusOr<MappedType> ConvertType(
const clang::Type* type,
std::optional<clang::tidy::lifetimes::ValueLifetimes>& lifetimes,
bool nullable);
absl::StatusOr<MappedType> ConvertTypeDecl(clang::TypeDecl* decl);
// Converts `type` into a MappedType, after first importing the Record behind
// the template instantiation.
absl::StatusOr<MappedType> ConvertTemplateSpecializationType(
const clang::TemplateSpecializationType* type);
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).
absl::flat_hash_set<const clang::TypeDecl*> known_type_decls_;
}; // class Importer
} // namespace crubit
#endif // CRUBIT_RS_BINDINGS_FROM_CC_IMPORTER_H_