blob: d0712fbff9c9984c3eb3090426806ae359f34d16 [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
#include "rs_bindings_from_cc/importers/type_alias.h"
#include <optional>
#include <string>
#include <utility>
#include "absl/log/check.h"
#include "absl/strings/str_cat.h"
#include "lifetime_annotations/type_lifetimes.h"
#include "rs_bindings_from_cc/ast_util.h"
#include "rs_bindings_from_cc/ir.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Type.h"
#include "clang/Basic/LLVM.h"
namespace crubit {
std::optional<IR::Item> crubit::TypeAliasImporter::Import(
clang::NamedDecl* decl) {
clang::DeclContext* decl_context = decl->getDeclContext();
clang::QualType underlying_qualtype;
if (auto* typedef_name_decl = clang::dyn_cast<clang::TypedefNameDecl>(decl)) {
if (typedef_name_decl->getAnonDeclWithTypedefName()) {
// Anonymous declarations with typedefs just incorporate the typedef name
// into their item, instead of having a separate TypeAlias item in
// addition.
return std::nullopt;
}
underlying_qualtype = typedef_name_decl->getUnderlyingType();
clang::QualType type =
decl->getASTContext().getTypedefType(typedef_name_decl);
if (const auto* tag_decl = type->getAsTagDecl();
tag_decl && tag_decl->getDeclContext() == decl_context &&
tag_decl->getName() == decl->getName()) {
return ictx_.ImportUnsupportedItem(
decl, "Typedef only used to introduce a name in C. Not importing.");
}
} else if (auto* using_decl = clang::dyn_cast<clang::UsingShadowDecl>(decl)) {
clang::NamedDecl* target = using_decl->getTargetDecl();
auto* target_type = clang::dyn_cast<clang::TypeDecl>(target);
if (target_type == nullptr) {
// Not a type.
return std::nullopt;
}
underlying_qualtype =
target_type->getASTContext().getTypeDeclType(target_type);
decl = using_decl;
} else {
// Neither a typedef nor a using decl.
return std::nullopt;
}
absl::StatusOr<Identifier> identifier = ictx_.GetTranslatedIdentifier(decl);
if (!identifier.ok()) {
return ictx_.ImportUnsupportedItem(
decl, absl::StrCat("Type alias name is not supported: ",
identifier.status().message()));
}
clang::tidy::lifetimes::ValueLifetimes* no_lifetimes = nullptr;
// TODO(mboehme): Once lifetime_annotations supports retrieving lifetimes in
// type aliases, pass these to ConvertQualType().
absl::StatusOr<MappedType> underlying_type =
ictx_.ConvertQualType(underlying_qualtype, no_lifetimes, std::nullopt);
if (!underlying_type.ok()) {
return ictx_.ImportUnsupportedItem(
decl, std::string(underlying_type.status().message()));
}
auto enclosing_item_id = ictx_.GetEnclosingItemId(decl);
if (!enclosing_item_id.ok()) {
return ictx_.ImportUnsupportedItem(
decl, std::string(enclosing_item_id.status().message()));
}
ictx_.MarkAsSuccessfullyImported(decl);
return TypeAlias{
.identifier = *identifier,
.id = ictx_.GenerateItemId(decl),
.owning_target = ictx_.GetOwningTarget(decl),
.doc_comment = ictx_.GetComment(decl),
.unknown_attr = CollectUnknownAttrs(*decl),
.underlying_type = *underlying_type,
.source_loc = ictx_.ConvertSourceLocation(decl->getBeginLoc()),
.enclosing_item_id = *std::move(enclosing_item_id),
};
}
} // namespace crubit