blob: 7401f6289f21484e2390a1cda8a424baaff039ee [file] [log] [blame]
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +00001// Part of the Crubit project, under the Apache License v2.0 with LLVM
2// Exceptions. See /LICENSE for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
Michael Forster500b4762022-01-27 12:30:17 +00005#include "rs_bindings_from_cc/importer.h"
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +00006
Marcel Hlopko9c150da2021-11-12 10:30:03 +00007#include <stdint.h>
8
Googler4e1bc132021-12-06 10:10:42 +00009#include <algorithm>
Martin Brænne83bda992023-07-10 12:03:12 -070010#include <cassert>
Devin Jeanpierre56777022022-02-03 01:57:15 +000011#include <cstddef>
Devin Jeanpierre257f0f62023-05-08 11:52:01 -070012#include <iterator>
13#include <map>
Marcel Hlopko7d739792021-08-12 07:52:47 +000014#include <memory>
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000015#include <optional>
Devin Jeanpierre257f0f62023-05-08 11:52:01 -070016#include <set>
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000017#include <string>
Michael Forster365bba12022-01-24 16:56:06 +000018#include <tuple>
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000019#include <utility>
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +000020#include <variant>
Marcel Hlopko7d739792021-08-12 07:52:47 +000021#include <vector>
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000022
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070023#include "absl/container/flat_hash_map.h"
24#include "absl/container/flat_hash_set.h"
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -070025#include "absl/log/check.h"
26#include "absl/log/log.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070027#include "absl/status/status.h"
28#include "absl/status/statusor.h"
29#include "absl/strings/cord.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070030#include "absl/strings/str_cat.h"
Googler442733c2023-01-23 01:05:35 -080031#include "absl/strings/str_format.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070032#include "absl/strings/str_join.h"
33#include "absl/strings/string_view.h"
34#include "absl/strings/substitute.h"
Marco Polettic61bcc42022-04-08 12:54:30 -070035#include "common/status_macros.h"
Luca Versari95ce68f2022-03-24 14:44:19 +000036#include "lifetime_annotations/type_lifetimes.h"
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -070037#include "rs_bindings_from_cc/ast_util.h"
Marcel Hlopko3b254b32022-03-09 14:10:49 +000038#include "rs_bindings_from_cc/bazel_types.h"
39#include "rs_bindings_from_cc/ir.h"
Devin Jeanpierre12b7b572023-05-03 15:40:55 -070040#include "rs_bindings_from_cc/type_map.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070041#include "clang/AST/ASTContext.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070042#include "clang/AST/Decl.h"
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -070043#include "clang/AST/DeclBase.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070044#include "clang/AST/DeclCXX.h"
Michael VanBemmel7a4d4c02022-07-27 13:21:47 -070045#include "clang/AST/DeclFriend.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070046#include "clang/AST/Mangle.h"
47#include "clang/AST/RawCommentList.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070048#include "clang/AST/Type.h"
49#include "clang/Basic/FileManager.h"
Rosica Dejanovska93aeafb2022-06-01 07:05:31 -070050#include "clang/Basic/LLVM.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070051#include "clang/Basic/OperatorKinds.h"
52#include "clang/Basic/SourceLocation.h"
53#include "clang/Basic/SourceManager.h"
54#include "clang/Basic/Specifiers.h"
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -070055#include "clang/Sema/Sema.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070056#include "llvm/ADT/STLExtras.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070057#include "llvm/Support/Casting.h"
Devin Jeanpierre1bcd7262022-10-04 20:07:59 -070058#include "llvm/Support/FormatVariadic.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070059#include "llvm/Support/Regex.h"
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000060
Marcel Hlopkof15e8ce2022-04-08 08:46:09 -070061namespace crubit {
Devin Jeanpierre56777022022-02-03 01:57:15 +000062namespace {
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000063
Michael Forsterb836c582022-01-21 11:20:22 +000064constexpr absl::string_view kTypeStatusPayloadUrl =
Michael Forsterdc683af2021-09-17 08:51:28 +000065 "type.googleapis.com/devtools.rust.cc_interop.rs_binding_from_cc.type";
66
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -070067// Checks if the return value from `GetDeclItem` indicates that the import was
68// successful.
69absl::Status CheckImportStatus(const std::optional<IR::Item>& item) {
70 if (!item.has_value()) {
71 return absl::InvalidArgumentError("The import has been skipped");
72 }
73 if (auto* unsupported = std::get_if<UnsupportedItem>(&*item)) {
74 return absl::InvalidArgumentError(unsupported->message);
75 }
76 return absl::OkStatus();
77}
Devin Jeanpierree971ed72022-08-09 05:07:04 -070078} // namespace
Michael Forster64217b42022-04-22 05:48:54 -070079
Michael Forster64217b42022-04-22 05:48:54 -070080namespace {
81
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +000082// Converts clang::CallingConv enum [1] into an equivalent Rust Abi [2, 3, 4].
83// [1]
84// https://github.com/llvm/llvm-project/blob/c6a3225bb03b6afc2b63fbf13db3c100406b32ce/clang/include/clang/Basic/Specifiers.h#L262-L283
85// [2] https://doc.rust-lang.org/reference/types/function-pointer.html
86// [3]
87// https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
88// [4]
89// https://github.com/rust-lang/rust/blob/b27ccbc7e1e6a04d749e244a3c13f72ca38e80e7/compiler/rustc_target/src/spec/abi.rs#L49
90absl::StatusOr<absl::string_view> ConvertCcCallConvIntoRsAbi(
91 clang::CallingConv cc_call_conv) {
92 switch (cc_call_conv) {
93 case clang::CC_C: // __attribute__((cdecl))
94 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
95 // that:
96 // - `extern "C"` [...] whatever the default your C compiler supports.
97 // - `extern "cdecl"` -- The default for x86_32 C code.
98 //
99 // We don't support C++ exceptions and therefore we use "C" (rather than
100 // "C-unwind") - we have no need for unwinding across the FFI boundary -
101 // e.g. from C++ into Rust frames (or vice versa).
102 return "C";
103 case clang::CC_X86FastCall: // __attribute__((fastcall))
104 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
105 // that the fastcall ABI -- corresponds to MSVC's __fastcall and GCC and
106 // clang's __attribute__((fastcall)).
107 return "fastcall";
108 case clang::CC_X86VectorCall: // __attribute__((vectorcall))
109 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
110 // that the vectorcall ABI -- corresponds to MSVC's __vectorcall and
111 // clang's __attribute__((vectorcall)).
112 return "vectorcall";
113 case clang::CC_X86ThisCall: // __attribute__((thiscall))
114 // We don't support C++ exceptions and therefore we use "thiscall" (rather
115 // than "thiscall-unwind") - we have no need for unwinding across the FFI
116 // boundary - e.g. from C++ into Rust frames (or vice versa).
117 return "thiscall";
118 case clang::CC_X86StdCall: // __attribute__((stdcall))
119 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
120 // extern "stdcall" -- The default for the Win32 API on x86_32.
121 //
122 // We don't support C++ exceptions and therefore we use "stdcall" (rather
123 // than "stdcall-unwind") - we have no need for unwinding across the FFI
124 // boundary - e.g. from C++ into Rust frames (or vice versa).
125 return "stdcall";
126 case clang::CC_Win64: // __attribute__((ms_abi))
127 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
128 // extern "win64" -- The default for C code on x86_64 Windows.
129 return "win64";
130 case clang::CC_AAPCS: // __attribute__((pcs("aapcs")))
131 case clang::CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp")))
132 // TODO(lukasza): Should both map to "aapcs"?
133 break;
134 case clang::CC_X86_64SysV: // __attribute__((sysv_abi))
135 // TODO(lukasza): Maybe this is "sysv64"?
136 break;
137 case clang::CC_X86Pascal: // __attribute__((pascal))
138 case clang::CC_X86RegCall: // __attribute__((regcall))
139 case clang::CC_IntelOclBicc: // __attribute__((intel_ocl_bicc))
140 case clang::CC_SpirFunction: // default for OpenCL functions on SPIR target
141 case clang::CC_OpenCLKernel: // inferred for OpenCL kernels
142 case clang::CC_Swift: // __attribute__((swiftcall))
143 case clang::CC_SwiftAsync: // __attribute__((swiftasynccall))
144 case clang::CC_PreserveMost: // __attribute__((preserve_most))
145 case clang::CC_PreserveAll: // __attribute__((preserve_all))
146 case clang::CC_AArch64VectorCall: // __attribute__((aarch64_vector_pcs))
Marcel Hlopkof80bf512022-05-12 01:20:33 -0700147 // TODO(hlopko): Uncomment once we integrate the upstream change that
148 // introduced it:
149 // case clang::CC_AArch64SVEPCS: __attribute__((aarch64_sve_pcs))
150
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000151 // These don't seem to have any Rust equivalents.
152 break;
Marcel Hlopkof80bf512022-05-12 01:20:33 -0700153 default:
Googler75c7ad02022-05-23 13:27:49 -0700154 break;
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000155 }
156 return absl::UnimplementedError(
157 absl::StrCat("Unsupported calling convention: ",
158 absl::string_view(
159 clang::FunctionType::getNameForCallConv(cc_call_conv))));
160}
161
Devin Jeanpierre56777022022-02-03 01:57:15 +0000162} // namespace
163
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000164// Multiple IR items can be associated with the same source location (e.g. the
165// implicitly defined constructors and assignment operators). To produce
166// deterministic output, we order such items based on GetDeclOrder. The order
167// is somewhat arbitrary, but we still try to make it aesthetically pleasing
168// (e.g. constructors go before assignment operators; default constructor goes
169// first, etc.).
170static int GetDeclOrder(const clang::Decl* decl) {
171 if (clang::isa<clang::RecordDecl>(decl)) {
172 return decl->getDeclContext()->isRecord() ? 101 : 100;
173 }
174
175 if (auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
176 return ctor->isDefaultConstructor() ? 202
177 : ctor->isCopyConstructor() ? 203
178 : ctor->isMoveConstructor() ? 204
179 : 299;
180 }
181
182 if (clang::isa<clang::CXXDestructorDecl>(decl)) {
183 return 306;
184 }
185
186 if (auto* method = clang::dyn_cast<clang::CXXMethodDecl>(decl)) {
187 return method->isCopyAssignmentOperator() ? 401
188 : method->isMoveAssignmentOperator() ? 402
189 : 499;
190 }
191
192 return 999;
193}
194
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700195class Importer::SourceOrderKey {
196 public:
Devin Jeanpierre257f0f62023-05-08 11:52:01 -0700197 explicit SourceOrderKey(clang::SourceRange source_range, int decl_order = 0,
198 std::string name = "")
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700199 : source_range_(source_range), decl_order_(decl_order), name_(name) {}
200
201 SourceOrderKey(const SourceOrderKey&) = default;
202 SourceOrderKey& operator=(const SourceOrderKey&) = default;
203
204 bool isBefore(const SourceOrderKey& other,
205 const clang::SourceManager& sm) const {
206 if (!source_range_.isValid() || !other.source_range_.isValid()) {
207 if (source_range_.isValid() != other.source_range_.isValid())
208 return !source_range_.isValid() && other.source_range_.isValid();
209 } else {
210 if (source_range_.getBegin() != other.source_range_.getBegin()) {
211 return sm.isBeforeInTranslationUnit(source_range_.getBegin(),
212 other.source_range_.getBegin());
213 }
214 if (source_range_.getEnd() != other.source_range_.getEnd()) {
215 return sm.isBeforeInTranslationUnit(source_range_.getEnd(),
216 other.source_range_.getEnd());
217 }
218 }
219
220 if (decl_order_ < other.decl_order_) {
221 return true;
222 } else if (decl_order_ > other.decl_order_) {
223 return false;
224 }
225 return name_ < other.name_;
226 }
227
228 private:
229 clang::SourceRange source_range_;
230 int decl_order_;
231 std::string name_;
232};
233
234Importer::SourceOrderKey Importer::GetSourceOrderKey(
235 const clang::Decl* decl) const {
236 return SourceOrderKey(decl->getSourceRange(), GetDeclOrder(decl),
237 GetNameForSourceOrder(decl));
238}
239
240Importer::SourceOrderKey Importer::GetSourceOrderKey(
241 const clang::RawComment* comment) const {
242 return SourceOrderKey(comment->getSourceRange());
243}
244
245class Importer::SourceLocationComparator {
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700246 public:
Devin Jeanpierre0d8e34b2023-05-08 11:43:44 -0700247 bool operator()(const clang::SourceLocation& a,
248 const clang::SourceLocation& b) const {
Devin Jeanpierre8f8049c2023-05-08 11:53:16 -0700249 return b.isValid() && a.isValid() && sm_.isBeforeInTranslationUnit(a, b);
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700250 }
Devin Jeanpierre0d8e34b2023-05-08 11:43:44 -0700251 bool operator()(const clang::RawComment* a,
252 const clang::SourceLocation& b) const {
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700253 return this->operator()(a->getBeginLoc(), b);
254 }
Devin Jeanpierre0d8e34b2023-05-08 11:43:44 -0700255 bool operator()(const clang::SourceLocation& a,
256 const clang::RawComment* b) const {
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700257 return this->operator()(a, b->getBeginLoc());
258 }
Devin Jeanpierre0d8e34b2023-05-08 11:43:44 -0700259 bool operator()(const clang::RawComment* a,
260 const clang::RawComment* b) const {
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700261 return this->operator()(a->getBeginLoc(), b->getBeginLoc());
262 }
Michael Forstera49d2e62022-01-28 07:26:40 +0000263
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700264 using OrderedItemId = std::pair<SourceOrderKey, ItemId>;
265 using OrderedItem = std::pair<SourceOrderKey, IR::Item>;
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700266
267 template <typename OrderedItemOrId>
268 bool operator()(const OrderedItemOrId& a, const OrderedItemOrId& b) const {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700269 auto a_source_order = a.first;
270 auto b_source_order = b.first;
Devin Jeanpierre8f8049c2023-05-08 11:53:16 -0700271 return a_source_order.isBefore(b_source_order, sm_);
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700272 }
Devin Jeanpierre8f8049c2023-05-08 11:53:16 -0700273 explicit SourceLocationComparator(const clang::SourceManager& sm) : sm_(sm) {}
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700274
275 private:
Devin Jeanpierre8f8049c2023-05-08 11:53:16 -0700276 const clang::SourceManager& sm_;
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700277};
278
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700279static std::vector<clang::Decl*> GetCanonicalChildren(
280 const clang::DeclContext* decl_context) {
281 std::vector<clang::Decl*> result;
282 for (clang::Decl* decl : decl_context->decls()) {
283 if (const auto* linkage_spec_decl =
284 llvm::dyn_cast<clang::LinkageSpecDecl>(decl)) {
285 llvm::move(GetCanonicalChildren(linkage_spec_decl),
286 std::back_inserter(result));
287 continue;
288 }
289
Lukasz Anforowicz38310f32022-09-09 11:17:52 -0700290 // `CXXRecordDeclImporter::Import` supports class template specializations
291 // but such import should only be triggered when
292 // `Importer::ConvertTemplateSpecializationType` is called (which means that
293 // the specialization is actually used in an explicit instantiation via
294 // `cc_template!` macro, in a type alias, or as a parameter type of a
295 // function, etc.).
296 if (clang::isa<clang::ClassTemplateSpecializationDecl>(decl)) continue;
297
Lukasz Anforowicz02ce0f72022-09-02 12:10:26 -0700298 // In general we only import (and include as children) canonical decls.
299 // Namespaces are exempted to ensure that we process every one of
300 // (potential) multiple namespace blocks with the same name.
301 if (decl == decl->getCanonicalDecl() ||
302 clang::isa<clang::NamespaceDecl>(decl)) {
303 result.push_back(decl);
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700304 }
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700305 }
306
307 return result;
308}
309
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700310std::vector<ItemId> Importer::GetItemIdsInSourceOrder(
311 clang::Decl* parent_decl) {
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700312 clang::SourceManager& sm = ctx_.getSourceManager();
313 std::vector<SourceLocationComparator::OrderedItemId> items;
314 auto compare_locations = SourceLocationComparator(sm);
315
316 // We are only interested in comments within this decl context.
317 std::vector<const clang::RawComment*> comments_in_range(
318 llvm::lower_bound(comments_, parent_decl->getBeginLoc(),
319 compare_locations),
320 llvm::upper_bound(comments_, parent_decl->getEndLoc(),
321 compare_locations));
322
323 std::map<clang::SourceLocation, const clang::RawComment*,
324 SourceLocationComparator>
325 ordered_comments(compare_locations);
326 for (auto& comment : comments_in_range) {
327 ordered_comments.insert({comment->getBeginLoc(), comment});
328 }
329
330 absl::flat_hash_set<ItemId> visited_item_ids;
Marcel Hlopkod4678de2022-05-25 01:38:13 -0700331
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700332 auto* decl_context = clang::cast<clang::DeclContext>(parent_decl);
333 for (auto decl : GetCanonicalChildren(decl_context)) {
Rosica Dejanovska001852d2022-06-07 14:19:41 -0700334 auto item = GetDeclItem(decl);
335 // We generated IR for top level items coming from different targets,
336 // however we shouldn't generate bindings for them, so we don't add them
337 // to ir.top_level_item_ids.
Devin Jeanpierre1bcd7262022-10-04 20:07:59 -0700338 if (decl_context->isTranslationUnit() && !IsFromCurrentTarget(decl)) {
Rosica Dejanovska001852d2022-06-07 14:19:41 -0700339 continue;
Devin Jeanpierre1bcd7262022-10-04 20:07:59 -0700340 }
Rosica Dejanovska001852d2022-06-07 14:19:41 -0700341 // Only add item ids for decls that can be successfully imported.
342 if (item.has_value()) {
343 auto item_id = GenerateItemId(decl);
344 // TODO(rosica): Drop this check when we start importing also other
345 // redecls, not just the canonical
346 if (visited_item_ids.find(item_id) == visited_item_ids.end()) {
347 visited_item_ids.insert(item_id);
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700348 items.push_back({GetSourceOrderKey(decl), item_id});
Rosica Dejanovska001852d2022-06-07 14:19:41 -0700349 }
350 }
351
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700352 // We remove comments attached to a child decl or that are within a child
353 // decl.
354 if (auto raw_comment = ctx_.getRawCommentForDeclNoCache(decl)) {
355 ordered_comments.erase(raw_comment->getBeginLoc());
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000356 }
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700357 ordered_comments.erase(ordered_comments.lower_bound(decl->getBeginLoc()),
358 ordered_comments.upper_bound(decl->getEndLoc()));
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700359 }
Michael Forster365bba12022-01-24 16:56:06 +0000360
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700361 for (auto& [_, comment] : ordered_comments) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700362 items.push_back({GetSourceOrderKey(comment), GenerateItemId(comment)});
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700363 }
Dmitri Gribenko620bc912022-04-22 03:38:04 -0700364 llvm::sort(items, compare_locations);
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700365
366 std::vector<ItemId> ordered_item_ids;
367 ordered_item_ids.reserve(items.size());
368 for (auto& ordered_item : items) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700369 ordered_item_ids.push_back(ordered_item.second);
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700370 }
371 return ordered_item_ids;
372}
373
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700374std::vector<ItemId> Importer::GetOrderedItemIdsOfTemplateInstantiations()
375 const {
376 std::vector<SourceLocationComparator::OrderedItemId> items;
Lukasz Anforowiczc72a9d82022-09-22 16:25:32 -0700377 items.reserve(class_template_instantiations_.size());
378 for (const auto* decl : class_template_instantiations_) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700379 items.push_back({GetSourceOrderKey(decl), GenerateItemId(decl)});
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700380 }
381
382 clang::SourceManager& sm = ctx_.getSourceManager();
383 auto compare_locations = SourceLocationComparator(sm);
384 llvm::sort(items, compare_locations);
385
386 std::vector<ItemId> ordered_item_ids;
387 ordered_item_ids.reserve(items.size());
388 for (const auto& ordered_item : items) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700389 ordered_item_ids.push_back(ordered_item.second);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700390 }
391 return ordered_item_ids;
392}
393
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700394void Importer::ImportFreeComments() {
395 clang::SourceManager& sm = ctx_.getSourceManager();
Lukasz Anforowicz121338a2022-11-01 14:28:32 -0700396 for (const auto& header : invocation_.public_headers_) {
Googlerfbc97652023-10-05 16:49:32 -0700397 if (auto file = sm.getFileManager().getFileRef(header.IncludePath())) {
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700398 if (auto comments_in_file = ctx_.Comments.getCommentsInFile(
399 sm.getOrCreateFileID(*file, clang::SrcMgr::C_User))) {
400 for (const auto& [_, comment] : *comments_in_file) {
401 comments_.push_back(comment);
402 }
403 }
404 }
405 }
Dmitri Gribenko620bc912022-04-22 03:38:04 -0700406 llvm::sort(comments_, SourceLocationComparator(sm));
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700407}
408
409void Importer::Import(clang::TranslationUnitDecl* translation_unit_decl) {
410 ImportFreeComments();
411 clang::SourceManager& sm = ctx_.getSourceManager();
412 std::vector<SourceLocationComparator::OrderedItem> ordered_items;
413
Devin Jeanpierre0d8e34b2023-05-08 11:43:44 -0700414 ordered_items.reserve(comments_.size());
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700415 for (auto& comment : comments_) {
416 ordered_items.push_back(
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700417 {GetSourceOrderKey(comment),
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700418 Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics()),
419 .id = GenerateItemId(comment)}});
420 }
421
422 ImportDeclsFromDeclContext(translation_unit_decl);
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000423 for (const auto& [decl, item] : import_cache_) {
424 if (item.has_value()) {
425 if (std::holds_alternative<UnsupportedItem>(*item) &&
426 !IsFromCurrentTarget(decl)) {
427 continue;
428 }
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700429 ordered_items.push_back({GetSourceOrderKey(decl), *item});
Michael Forster500b4762022-01-27 12:30:17 +0000430 }
Michael Forster365bba12022-01-24 16:56:06 +0000431 }
Michael Forster500b4762022-01-27 12:30:17 +0000432
Dmitri Gribenko620bc912022-04-22 03:38:04 -0700433 llvm::sort(ordered_items, SourceLocationComparator(sm));
Michael Forster365bba12022-01-24 16:56:06 +0000434
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700435 invocation_.ir_.items.reserve(ordered_items.size());
436 for (auto& ordered_item : ordered_items) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700437 invocation_.ir_.items.push_back(ordered_item.second);
Michael Forster365bba12022-01-24 16:56:06 +0000438 }
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700439 invocation_.ir_.top_level_item_ids =
440 GetItemIdsInSourceOrder(translation_unit_decl);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700441
Lukasz Anforowicza6f96252022-11-03 13:49:08 -0700442 // TODO(b/257302656): Consider placing the generated template instantiations
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700443 // into a separate namespace (maybe `crubit::instantiated_templates` ?).
444 llvm::copy(GetOrderedItemIdsOfTemplateInstantiations(),
445 std::back_inserter(invocation_.ir_.top_level_item_ids));
Michael Forster365bba12022-01-24 16:56:06 +0000446}
447
Michael Forster500b4762022-01-27 12:30:17 +0000448void Importer::ImportDeclsFromDeclContext(
449 const clang::DeclContext* decl_context) {
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700450 for (auto decl : GetCanonicalChildren(decl_context)) {
451 GetDeclItem(decl);
Michael Forster500b4762022-01-27 12:30:17 +0000452 }
453}
454
Michael Forster1b506372022-04-12 11:31:54 -0700455std::optional<IR::Item> Importer::GetDeclItem(clang::Decl* decl) {
Devin Jeanpierre257f0f62023-05-08 11:52:01 -0700456 // TODO(jeanpierreda): Move `decl->getCanonicalDecl()` from callers into here.
Devin Jeanpierre1bcd7262022-10-04 20:07:59 -0700457 if (auto it = import_cache_.find(decl); it != import_cache_.end()) {
458 return it->second;
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000459 }
Devin Jeanpierre1bcd7262022-10-04 20:07:59 -0700460 // Here, we need to be careful. Recursive imports break cycles as follows:
461 // an item which may, in the process of being imported, then import itself,
462 // will mark itself as being successfully imported in the future via
463 // `MarkAsSuccessfullyImported()` during its own import process. Then later
464 // attempts to import it will, instead of trying to import it again (causing
465 // an infinite loop), short-circuit and return a null item at that time.
466 //
467 // This means that import_cache_ can change *during the call to ImportDecl*,
468 // and in particular, because `GetDeclItem` caches, and because recursive
469 // calls return null, it might specifically have been changed to have a
470 // null entry for the decl we are currently importing.
471 //
472 // For example, consider the following type:
473 //
474 // ```c++
475 // struct Foo{ Foo* x; }
476 // ```
477 //
478 // 1. First, we call `GetDeclItem(mystruct)`
479 // 2. If importing `x` itself attempts an import of `Foo*`, then that would
480 // call `GetDeclItem(mystruct)` inside of an existing call to
481 // `GetDeclItem(mystruct)`.
482 // 3. The nested call returns early, returning null (because this is a
483 // cyclic invocation), and `GetDeclItem` **caches the null entry**.
484 // 4. finally, the original `GetDeclItem` call finishes its call to
485 // `ImportDecl`. It must now overwrite the nulled cache entry from the
486 // earlier import to instead use the real entry.
487 //
488 // TODO(jeanpierreda): find and eliminate all re-entrant imports, and replace with
489 // a CHECK(inserted).
490
491 // Note: insert_or_assign, not insert, in case a record, so as to overwrite
492 // any null entries introduced by cycles.
493
494 std::optional<IR::Item> result = ImportDecl(decl);
495 auto [it, inserted] = import_cache_.try_emplace(decl, result);
496 if (!inserted) {
497 // TODO(jeanpierreda): Fix and promote to CHECK.
498 // At least one cycle occurs with Typedef, where a typedef will import
499 // itself during its own import. This isn't an infinite loop, because the
500 // recursive cycle gets broken between the two by CXXRecordDecl, but the
501 // result is that we get this typedef inserted while we were attempting to
502 // insert it.
503 //
504 // Alternatively, maybe it's sufficient to check that they're _equal_.
505 // It's not a bug at all to import it twice if it has no effect.
506 LOG_IF(INFO, !it->second.has_value())
507 << "re-entrant import discovered, where the re-entrant import had a "
508 "non-null value."
509 << "\n trying to import a " << decl->getDeclKindName()
510 << "\n present entry: " << ItemToString(it->second)
511 << "\n was going to be inserted: " << ItemToString(result);
512 it->second = result;
513 }
514 if (auto* record_decl = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
515 // TODO(forster): Should we even visit the nested decl if we couldn't
516 // import the parent? For now we have tests that check that we generate
517 // error messages for those decls, so we're visiting.
518 ImportDeclsFromDeclContext(record_decl);
519 }
Devin Jeanpierre61804f72022-10-04 20:26:13 -0700520 if (auto* specialization_decl =
521 llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
522 // Store `specialization_decl`s so that they will get included in
523 // IR::top_level_item_ids.
524 class_template_instantiations_.insert(specialization_decl);
525 }
Devin Jeanpierre1bcd7262022-10-04 20:07:59 -0700526 return result;
Michael Forster500b4762022-01-27 12:30:17 +0000527}
528
Devin Jeanpierre42238592022-10-04 20:27:44 -0700529/// Returns true if a decl is inside a private section, or is inside a
530/// RecordDecl which is IsTransitivelyInPrivate.
531bool IsTransitivelyInPrivate(clang::Decl* decl_to_check) {
532 while (true) {
533 auto* parent =
534 llvm::dyn_cast<clang::CXXRecordDecl>(decl_to_check->getDeclContext());
535 if (parent == nullptr) {
536 return false;
537 }
538 switch (decl_to_check->getAccess()) {
539 case clang::AccessSpecifier::AS_public:
540 break;
541 case clang::AccessSpecifier::AS_none:
542 if (!parent->isClass()) {
543 break;
544 }
545 [[fallthrough]];
546 case clang::AccessSpecifier::AS_private:
547 case clang::AccessSpecifier::AS_protected:
548 return true;
549 }
550
551 decl_to_check = parent;
552 }
553}
554
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000555std::optional<IR::Item> Importer::ImportDecl(clang::Decl* decl) {
Devin Jeanpierre42238592022-10-04 20:27:44 -0700556 if (IsTransitivelyInPrivate(decl)) return std::nullopt;
Michael Forster64217b42022-04-22 05:48:54 -0700557 for (auto& importer : decl_importers_) {
Devin Jeanpierrec2c39ff2023-05-08 11:42:21 -0700558 std::optional<IR::Item> result = importer->ImportDecl(decl);
559 if (result.has_value()) {
560 return result;
Michael Forster64217b42022-04-22 05:48:54 -0700561 }
562 }
Devin Jeanpierrec2c39ff2023-05-08 11:42:21 -0700563 return std::nullopt;
Michael Forster500b4762022-01-27 12:30:17 +0000564}
565
Kinuko Yasuda6ff59f12022-08-11 08:41:45 -0700566std::optional<IR::Item> Importer::GetImportedItem(const clang::Decl* decl) {
567 auto it = import_cache_.find(decl);
568 if (it != import_cache_.end()) {
569 return it->second;
570 }
571 return std::nullopt;
572}
573
Googler6c3de122022-03-28 11:40:41 +0000574BazelLabel Importer::GetOwningTarget(const clang::Decl* decl) const {
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700575 // Template instantiations need to be generated in the target that triggered
576 // the instantiation (not in the target where the template is defined).
577 if (IsFullClassTemplateSpecializationOrChild(decl)) {
578 return invocation_.target_;
579 }
580
Michael Forstera49d2e62022-01-28 07:26:40 +0000581 clang::SourceManager& source_manager = ctx_.getSourceManager();
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000582 auto source_location = decl->getLocation();
Marcel Hlopko80441c12021-11-12 10:43:18 +0000583
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000584 // If the header this decl comes from is not associated with a target we
585 // consider it a textual header. In that case we go up the include stack
586 // until we find a header that has an owning target.
587
Rosica Dejanovska381d1032022-02-03 22:19:54 +0000588 while (source_location.isValid()) {
Rosica Dejanovska503d7dd2022-02-01 20:37:49 +0000589 if (source_location.isMacroID()) {
590 source_location = source_manager.getExpansionLoc(source_location);
591 }
592 auto id = source_manager.getFileID(source_location);
Googler261c5312023-03-01 08:50:58 -0800593 std::optional<llvm::StringRef> filename =
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000594 source_manager.getNonBuiltinFilenameForID(id);
595 if (!filename) {
Marcel Hlopko457bdef2022-05-18 06:01:49 -0700596 return BazelLabel("//:_nothing_should_depend_on_private_builtin_hdrs");
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000597 }
598 if (filename->startswith("./")) {
599 filename = filename->substr(2);
600 }
Michael Forstera49d2e62022-01-28 07:26:40 +0000601
602 if (auto target = invocation_.header_target(HeaderName(filename->str()))) {
603 return *target;
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000604 }
605 source_location = source_manager.getIncludeLoc(id);
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000606 }
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000607
Googler6c3de122022-03-28 11:40:41 +0000608 return BazelLabel("//:virtual_clang_resource_dir_target");
Marcel Hlopko80441c12021-11-12 10:43:18 +0000609}
610
Michael Forster500b4762022-01-27 12:30:17 +0000611bool Importer::IsFromCurrentTarget(const clang::Decl* decl) const {
Michael Forstera49d2e62022-01-28 07:26:40 +0000612 return invocation_.target_ == GetOwningTarget(decl);
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000613}
614
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000615IR::Item Importer::ImportUnsupportedItem(const clang::Decl* decl,
616 std::string error) {
617 std::string name = "unnamed";
618 if (const auto* named_decl = clang::dyn_cast<clang::NamedDecl>(decl)) {
619 name = named_decl->getQualifiedNameAsString();
620 }
Googler442733c2023-01-23 01:05:35 -0800621 std::string source_loc = ConvertSourceLocation(decl->getBeginLoc());
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000622 return UnsupportedItem{.name = name,
623 .message = error,
624 .source_loc = source_loc,
625 .id = GenerateItemId(decl)};
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000626}
627
628IR::Item Importer::ImportUnsupportedItem(const clang::Decl* decl,
629 std::set<std::string> errors) {
630 return ImportUnsupportedItem(decl, absl::StrJoin(errors, "\n\n"));
631}
632
Lukasz Anforowiczc4ceb4f2022-01-28 19:29:19 +0000633static bool ShouldKeepCommentLine(absl::string_view line) {
634 // Based on https://clang.llvm.org/extra/clang-tidy/:
635 llvm::Regex patterns_to_ignore(
636 "^[[:space:]/]*" // Whitespace, or extra //
637 "(NOLINT|NOLINTNEXTLINE|NOLINTBEGIN|NOLINTEND)"
638 "(\\([^)[:space:]]*\\)?)?" // Optional (...)
639 "[[:space:]]*$"); // Whitespace
640 return !patterns_to_ignore.match(line);
641}
642
Googlera6c60bb2022-12-20 07:32:17 -0800643std::optional<std::string> Importer::GetComment(const clang::Decl* decl) const {
Michael Forster409d9412021-10-07 08:35:29 +0000644 // This does currently not distinguish between different types of comments.
645 // In general it is not possible in C++ to reliably only extract doc comments.
646 // This is going to be a heuristic that needs to be tuned over time.
647
Michael Forstera49d2e62022-01-28 07:26:40 +0000648 clang::SourceManager& sm = ctx_.getSourceManager();
649 clang::RawComment* raw_comment = ctx_.getRawCommentForDeclNoCache(decl);
Michael Forstercc5941a2021-10-07 07:12:24 +0000650
651 if (raw_comment == nullptr) {
652 return {};
Michael Forstercc5941a2021-10-07 07:12:24 +0000653 }
Lukasz Anforowiczc4ceb4f2022-01-28 19:29:19 +0000654
655 std::string raw_comment_text =
656 raw_comment->getFormattedText(sm, sm.getDiagnostics());
657 std::string cleaned_comment_text = absl::StrJoin(
658 absl::StrSplit(raw_comment_text, '\n', ShouldKeepCommentLine), "\n");
Lukasz Anforowicz3b4be122022-03-16 00:09:35 +0000659 if (cleaned_comment_text.empty()) return {};
660 return cleaned_comment_text;
Michael Forstercc5941a2021-10-07 07:12:24 +0000661}
662
Googler442733c2023-01-23 01:05:35 -0800663std::string Importer::ConvertSourceLocation(clang::SourceLocation loc) const {
Michael Forstera49d2e62022-01-28 07:26:40 +0000664 auto& sm = ctx_.getSourceManager();
Googler31910372023-01-25 12:47:16 -0800665 // For macros: https://clang.llvm.org/doxygen/SourceManager_8h.html:
666 // Spelling location: where the macro is originally defined.
667 // Expansion location: where the macro is expanded.
668 const clang::SourceLocation& spelling_loc = sm.getSpellingLoc(loc);
669 // TODO(b/261185414): The "google3" prefix should probably come from a command
670 // line argument.
671 // TODO(b/261185414): Consider linking to the symbol instead of to the line
672 // number to avoid wrong links while generated files have not caught up.
Googlerba8c50c2023-01-25 13:07:31 -0800673 constexpr absl::string_view kGeneratedFrom = "Generated from";
674 constexpr absl::string_view kExpandedAt = "Expanded at";
675 constexpr auto kSourceLocationFunc =
676 [](absl::string_view origin, absl::string_view filename, uint32_t line) {
677 return absl::Substitute("$0: google3/$1;l=$2", origin, filename, line);
678 };
Googler31910372023-01-25 12:47:16 -0800679 constexpr absl::string_view kSourceLocUnknown = "<unknown location>";
680 std::string spelling_loc_str;
681 if (absl::string_view spelling_filename = sm.getFilename(spelling_loc);
682 spelling_filename.empty()) {
683 spelling_loc_str = kSourceLocUnknown;
Googler442733c2023-01-23 01:05:35 -0800684 } else {
Googler31910372023-01-25 12:47:16 -0800685 uint32_t spelling_line = sm.getSpellingLineNumber(loc);
686 if (absl::StartsWith(spelling_filename, "./")) {
687 spelling_filename = spelling_filename.substr(2);
688 }
Googlerba8c50c2023-01-25 13:07:31 -0800689 spelling_loc_str =
690 kSourceLocationFunc(kGeneratedFrom, spelling_filename, spelling_line);
Googler442733c2023-01-23 01:05:35 -0800691 }
Googler31910372023-01-25 12:47:16 -0800692 if (!loc.isMacroID()) {
693 return spelling_loc_str;
694 }
695 const clang::SourceLocation& expansion_loc = sm.getExpansionLoc(loc);
696 std::string expansion_loc_str;
697 if (absl::string_view expansion_filename = sm.getFilename(expansion_loc);
698 expansion_filename.empty()) {
699 expansion_loc_str = kSourceLocUnknown;
700 } else {
701 uint32_t expansion_line = sm.getExpansionLineNumber(loc);
702 if (absl::StartsWith(expansion_filename, "./")) {
703 expansion_filename = expansion_filename.substr(2);
704 }
Googlerba8c50c2023-01-25 13:07:31 -0800705 expansion_loc_str =
706 kSourceLocationFunc(kExpandedAt, expansion_filename, expansion_line);
Googler31910372023-01-25 12:47:16 -0800707 }
Googlerba8c50c2023-01-25 13:07:31 -0800708 return absl::StrCat(spelling_loc_str, "\n", expansion_loc_str);
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000709}
710
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700711absl::StatusOr<MappedType> Importer::ConvertTemplateSpecializationType(
712 const clang::TemplateSpecializationType* type) {
713 // Qualifiers are handled separately in TypeMapper::ConvertQualType().
714 std::string type_string = clang::QualType(type, 0).getAsString();
715
716 auto* specialization_decl =
717 clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
718 type->getAsCXXRecordDecl());
719 if (!specialization_decl) {
720 return absl::InvalidArgumentError(absl::Substitute(
721 "Template specialization '$0' without an associated record decl "
722 "is not supported.",
723 type_string));
724 }
725
Lukasz Anforowicz3a2026b2022-06-09 09:08:42 -0700726 if (HasBeenAlreadySuccessfullyImported(specialization_decl))
727 return ConvertTypeDecl(specialization_decl);
728
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700729 // `Sema::isCompleteType` will try to instantiate the class template as a
730 // side-effect and we rely on this here. `decl->getDefinition()` can
731 // return nullptr before the call to sema and return its definition
732 // afterwards.
Lukasz Anforowicz38310f32022-09-09 11:17:52 -0700733 (void)sema_.isCompleteType(specialization_decl->getLocation(),
734 ctx_.getRecordType(specialization_decl));
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700735
736 // TODO(lukasza): Limit specialization depth? (e.g. using
737 // `isSpecializationDepthGreaterThan` from earlier prototypes).
738
739 absl::Status import_status =
740 CheckImportStatus(GetDeclItem(specialization_decl));
741 if (!import_status.ok()) {
742 return absl::InvalidArgumentError(absl::Substitute(
743 "Failed to create bindings for template specialization type $0: $1",
744 type_string, import_status.message()));
745 }
746
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700747 return ConvertTypeDecl(specialization_decl);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700748}
749
Devin Jeanpierre3c4354b2023-05-26 16:01:49 -0700750absl::StatusOr<MappedType> Importer::ConvertTypeDecl(clang::NamedDecl* decl) {
Devin Jeanpierre61804f72022-10-04 20:26:13 -0700751 if (!EnsureSuccessfullyImported(decl)) {
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000752 return absl::NotFoundError(absl::Substitute(
753 "No generated bindings found for '$0'", decl->getNameAsString()));
754 }
755
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000756 ItemId decl_id = GenerateItemId(decl);
Lukasz Anforowicz58f27112022-03-15 17:51:03 +0000757 return MappedType::WithDeclId(decl_id);
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000758}
759
Martin Brænne83bda992023-07-10 12:03:12 -0700760static bool IsSameCanonicalUnqualifiedType(clang::QualType type1,
761 clang::QualType type2) {
762 type1 = type1.getCanonicalType().getUnqualifiedType();
763 type2 = type2.getCanonicalType().getUnqualifiedType();
764
765 // `DeducedType::getDeducedType()` can return null, in which case we don't
766 // have a more canonical representation. If this happens, optimistically
767 // assume the types are equal.
768 if (clang::isa<clang::DeducedType>(type1) ||
769 clang::isa<clang::DeducedType>(type2))
770 return true;
771
772 return type1 == type2;
773}
774
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700775absl::StatusOr<MappedType> Importer::ConvertType(
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000776 const clang::Type* type,
Martin Brænne390ffa22023-07-10 12:26:53 -0700777 const clang::tidy::lifetimes::ValueLifetimes* lifetimes,
Googler1bff6372023-03-24 10:06:29 -0700778 std::optional<clang::RefQualifierKind> ref_qualifier_kind, bool nullable) {
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000779 // Qualifiers are handled separately in ConvertQualType().
780 std::string type_string = clang::QualType(type, 0).getAsString();
Michael Forsterdc683af2021-09-17 08:51:28 +0000781
Martin Brænne390ffa22023-07-10 12:26:53 -0700782 assert(!lifetimes || IsSameCanonicalUnqualifiedType(
783 lifetimes->Type(), clang::QualType(type, 0)));
Martin Brænne83bda992023-07-10 12:03:12 -0700784
Devin Jeanpierreb7f8e282023-05-26 16:03:12 -0700785 if (auto override_type = GetTypeMapOverride(*type);
786 override_type.has_value()) {
Devin Jeanpierre12b7b572023-05-03 15:40:55 -0700787 return *std::move(override_type);
Devin Jeanpierredeea7892022-03-29 02:13:31 -0700788 } else if (type->isPointerType() || type->isLValueReferenceType() ||
789 type->isRValueReferenceType()) {
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000790 clang::QualType pointee_type = type->getPointeeType();
Lukasz Anforowicz92c81c32022-03-04 19:03:56 +0000791 std::optional<LifetimeId> lifetime;
Martin Brænne390ffa22023-07-10 12:26:53 -0700792 const clang::tidy::lifetimes::ValueLifetimes* pointee_lifetimes = nullptr;
793 if (lifetimes) {
Luca Versari95ce68f2022-03-24 14:44:19 +0000794 lifetime =
795 LifetimeId(lifetimes->GetPointeeLifetimes().GetLifetime().Id());
Martin Brænne390ffa22023-07-10 12:26:53 -0700796 pointee_lifetimes = &lifetimes->GetPointeeLifetimes().GetValueLifetimes();
Lukasz Anforowicz92c81c32022-03-04 19:03:56 +0000797 }
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000798 if (const auto* func_type =
Lukasz Anforowicz92c81c32022-03-04 19:03:56 +0000799 pointee_type->getAs<clang::FunctionProtoType>()) {
Lukasz Anforowicz5087e1f2023-04-03 08:41:29 -0700800 // Assert that the function pointers/references always either 1) have no
801 // lifetime or 2) have `'static` lifetime (no other lifetime is allowed).
802 CHECK(!lifetime.has_value() ||
803 (lifetime->value() ==
804 clang::tidy::lifetimes::Lifetime::Static().Id()));
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000805
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000806 clang::StringRef cc_call_conv =
807 clang::FunctionType::getNameForCallConv(func_type->getCallConv());
Lukasz Anforowiczd41a4e92022-03-17 17:08:57 +0000808 CRUBIT_ASSIGN_OR_RETURN(
809 absl::string_view rs_abi,
810 ConvertCcCallConvIntoRsAbi(func_type->getCallConv()));
Martin Brænne390ffa22023-07-10 12:26:53 -0700811 const clang::tidy::lifetimes::ValueLifetimes* return_lifetimes = nullptr;
812 if (pointee_lifetimes) {
813 return_lifetimes =
814 &pointee_lifetimes->GetFuncLifetimes().GetReturnLifetimes();
815 }
Martin Brænne83bda992023-07-10 12:03:12 -0700816 CRUBIT_ASSIGN_OR_RETURN(
817 MappedType mapped_return_type,
818 ConvertQualType(func_type->getReturnType(), return_lifetimes,
819 ref_qualifier_kind));
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000820
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000821 std::vector<MappedType> mapped_param_types;
Martin Brænne83bda992023-07-10 12:03:12 -0700822 for (unsigned i = 0; i < func_type->getNumParams(); ++i) {
Martin Brænne390ffa22023-07-10 12:26:53 -0700823 const clang::tidy::lifetimes::ValueLifetimes* param_lifetimes = nullptr;
824 if (pointee_lifetimes) {
825 param_lifetimes =
826 &pointee_lifetimes->GetFuncLifetimes().GetParamLifetimes(i);
827 }
Googler1bff6372023-03-24 10:06:29 -0700828 CRUBIT_ASSIGN_OR_RETURN(
829 MappedType mapped_param_type,
Martin Brænne83bda992023-07-10 12:03:12 -0700830 ConvertQualType(func_type->getParamType(i), param_lifetimes,
831 ref_qualifier_kind));
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000832 mapped_param_types.push_back(std::move(mapped_param_type));
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000833 }
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000834
835 if (type->isPointerType()) {
836 return MappedType::FuncPtr(cc_call_conv, rs_abi, lifetime,
837 std::move(mapped_return_type),
838 std::move(mapped_param_types));
839 } else {
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700840 CHECK(type->isLValueReferenceType());
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000841 return MappedType::FuncRef(cc_call_conv, rs_abi, lifetime,
842 std::move(mapped_return_type),
843 std::move(mapped_param_types));
844 }
845 }
846
Googler1bff6372023-03-24 10:06:29 -0700847 CRUBIT_ASSIGN_OR_RETURN(
848 MappedType mapped_pointee_type,
Martin Brænne390ffa22023-07-10 12:26:53 -0700849 ConvertQualType(pointee_type, pointee_lifetimes, ref_qualifier_kind));
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000850 if (type->isPointerType()) {
851 return MappedType::PointerTo(std::move(mapped_pointee_type), lifetime,
Googler1bff6372023-03-24 10:06:29 -0700852 ref_qualifier_kind, nullable);
Devin Jeanpierredeea7892022-03-29 02:13:31 -0700853 } else if (type->isLValueReferenceType()) {
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000854 return MappedType::LValueReferenceTo(std::move(mapped_pointee_type),
855 lifetime);
Devin Jeanpierredeea7892022-03-29 02:13:31 -0700856 } else {
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700857 CHECK(type->isRValueReferenceType());
Devin Jeanpierredeea7892022-03-29 02:13:31 -0700858 if (!lifetime.has_value()) {
859 return absl::UnimplementedError(
860 "Unsupported type: && without lifetime");
861 }
862 return MappedType::RValueReferenceTo(std::move(mapped_pointee_type),
863 *lifetime);
Googler61dce3b2021-12-02 09:16:32 +0000864 }
Googlerb6c0fe02021-12-01 10:55:31 +0000865 } else if (const auto* builtin_type =
Googler06f2c9a2022-01-05 12:00:47 +0000866 // Use getAsAdjusted instead of getAs so we don't desugar
867 // typedefs.
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000868 type->getAsAdjusted<clang::BuiltinType>()) {
Michael Forster51da81a2021-09-20 07:14:23 +0000869 switch (builtin_type->getKind()) {
870 case clang::BuiltinType::Bool:
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000871 return MappedType::Simple("bool", "bool");
Michael Forster51da81a2021-09-20 07:14:23 +0000872 case clang::BuiltinType::Void:
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000873 return MappedType::Void();
Lukasz Anforowicz460e4272023-05-18 16:11:46 -0700874
875 // Floating-point numbers
876 //
877 // TODO(b/255768062): Generated bindings should explicitly check if
878 // `math.h` defines the `__STDC_IEC_559__` macro.
879 case clang::BuiltinType::Float:
880 return MappedType::Simple("f32", "float");
881 case clang::BuiltinType::Double:
882 return MappedType::Simple("f64", "double");
883
884 // `char`
885 case clang::BuiltinType::Char_S: // 'char' in targets where it's signed
886 // TODO(b/276790180, b/276931370): use `::core::ffi::c_char` instead.
887 return MappedType::Simple("i8", "char");
888 case clang::BuiltinType::Char_U: // 'char' in targets where it's unsigned
889 // TODO(b/276790180, b/276931370): use `::core::ffi::c_char` instead.
890 return MappedType::Simple("u8", "char");
891 case clang::BuiltinType::SChar: // 'signed char', explicitly qualified
892 return MappedType::Simple("::core::ffi::c_schar", "signed char");
893 case clang::BuiltinType::UChar: // 'unsigned char', explicitly qualified
894 return MappedType::Simple("::core::ffi::c_uchar", "unsigned char");
895
896 // Signed integers
897 case clang::BuiltinType::Short:
898 return MappedType::Simple("::core::ffi::c_short", "short");
899 case clang::BuiltinType::Int:
900 return MappedType::Simple("::core::ffi::c_int", "int");
901 case clang::BuiltinType::Long:
902 return MappedType::Simple("::core::ffi::c_long", "long");
903 case clang::BuiltinType::LongLong:
904 return MappedType::Simple("::core::ffi::c_longlong", "long long");
905
906 // Unsigned integers
907 case clang::BuiltinType::UShort:
908 return MappedType::Simple("::core::ffi::c_ushort", "unsigned short");
909 case clang::BuiltinType::UInt:
910 return MappedType::Simple("::core::ffi::c_uint", "unsigned int");
911 case clang::BuiltinType::ULong:
912 return MappedType::Simple("::core::ffi::c_ulong", "unsigned long");
913 case clang::BuiltinType::ULongLong:
914 return MappedType::Simple("::core::ffi::c_ulonglong",
915 "unsigned long long");
Michael Forster51da81a2021-09-20 07:14:23 +0000916 default:
Lukasz Anforowicz4d014612023-05-18 16:27:36 -0700917 return absl::UnimplementedError("Unsupported builtin type");
Marcel Hlopko7d739792021-08-12 07:52:47 +0000918 }
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000919 } else if (const auto* tag_type = type->getAsAdjusted<clang::TagType>()) {
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000920 return ConvertTypeDecl(tag_type->getDecl());
Michael Forster365bba12022-01-24 16:56:06 +0000921 } else if (const auto* typedef_type =
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000922 type->getAsAdjusted<clang::TypedefType>()) {
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000923 return ConvertTypeDecl(typedef_type->getDecl());
Devin Jeanpierre3c4354b2023-05-26 16:01:49 -0700924 } else if (const auto* using_type = type->getAs<clang::UsingType>()) {
925 return ConvertTypeDecl(using_type->getFoundDecl());
Lukasz Anforowicz14732b22022-06-02 09:11:08 -0700926 } else if (const auto* tst_type =
927 type->getAs<clang::TemplateSpecializationType>()) {
928 return ConvertTemplateSpecializationType(tst_type);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700929 } else if (const auto* subst_type =
930 type->getAs<clang::SubstTemplateTypeParmType>()) {
Googler1bff6372023-03-24 10:06:29 -0700931 return ConvertQualType(subst_type->getReplacementType(), lifetimes,
932 ref_qualifier_kind);
Lukasz Anforowicz8f590682022-05-17 12:39:20 -0700933 } else if (const auto* deduced_type = type->getAs<clang::DeducedType>()) {
934 // Deduction should have taken place earlier (e.g. via DeduceReturnType
935 // called from FunctionDeclImporter::Import).
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700936 CHECK(deduced_type->isDeduced());
Googler1bff6372023-03-24 10:06:29 -0700937 return ConvertQualType(deduced_type->getDeducedType(), lifetimes,
938 ref_qualifier_kind);
Marcel Hlopko7d739792021-08-12 07:52:47 +0000939 }
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000940
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000941 return absl::UnimplementedError(absl::StrCat(
942 "Unsupported clang::Type class '", type->getTypeClassName(), "'"));
943}
944
Devin Jeanpierree971ed72022-08-09 05:07:04 -0700945// Returns a QualType with leading ElaboratedType nodes removed.
946//
947// This is analogous to getDesugaredType but *only* removes ElaboratedType
948// sugar.
949static clang::QualType GetUnelaboratedType(clang::QualType qual_type,
950 clang::ASTContext& ast_context) {
951 clang::QualifierCollector qualifiers;
952 while (true) {
953 const clang::Type* type = qualifiers.strip(qual_type);
954 if (const auto* elaborated = llvm::dyn_cast<clang::ElaboratedType>(type)) {
955 qual_type = elaborated->getNamedType();
956 continue;
957 }
958
959 return ast_context.getQualifiedType(type, qualifiers);
960 }
961}
962
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700963absl::StatusOr<MappedType> Importer::ConvertQualType(
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000964 clang::QualType qual_type,
Martin Brænne390ffa22023-07-10 12:26:53 -0700965 const clang::tidy::lifetimes::ValueLifetimes* lifetimes,
Googler1bff6372023-03-24 10:06:29 -0700966 std::optional<clang::RefQualifierKind> ref_qualifier_kind, bool nullable) {
Devin Jeanpierree971ed72022-08-09 05:07:04 -0700967 qual_type = GetUnelaboratedType(std::move(qual_type), ctx_);
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000968 std::string type_string = qual_type.getAsString();
Googler1bff6372023-03-24 10:06:29 -0700969 absl::StatusOr<MappedType> type = ConvertType(
970 qual_type.getTypePtr(), lifetimes, ref_qualifier_kind, nullable);
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000971 if (!type.ok()) {
972 absl::Status error = absl::UnimplementedError(absl::Substitute(
973 "Unsupported type '$0': $1", type_string, type.status().message()));
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000974 error.SetPayload(kTypeStatusPayloadUrl, absl::Cord(type_string));
975 return error;
976 }
977
Lukasz Anforowicz0c3f8b22022-02-15 14:56:40 +0000978 // Handle cv-qualification.
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000979 type->cc_type.is_const = qual_type.isConstQualified();
Lukasz Anforowicz0c3f8b22022-02-15 14:56:40 +0000980 if (qual_type.isVolatileQualified()) {
981 return absl::UnimplementedError(
982 absl::StrCat("Unsupported `volatile` qualifier: ", type_string));
983 }
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000984
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000985 return type;
Marcel Hlopko7d739792021-08-12 07:52:47 +0000986}
987
Michael Forster500b4762022-01-27 12:30:17 +0000988std::string Importer::GetMangledName(const clang::NamedDecl* named_decl) const {
Lukasz Anforowicz3f133972022-09-01 09:01:02 -0700989 if (auto record_decl = clang::dyn_cast<clang::RecordDecl>(named_decl)) {
990 // Mangled record names are used to 1) provide valid Rust identifiers for
991 // C++ template specializations, and 2) help build unique names for virtual
992 // upcast thunks.
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700993 llvm::SmallString<128> storage;
994 llvm::raw_svector_ostream buffer(storage);
Googler05175972023-10-04 15:19:16 -0700995 mangler_->mangleCanonicalTypeName(ctx_.getRecordType(record_decl), buffer);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700996
997 // The Itanium mangler does not provide a way to get the mangled
998 // representation of a type. Instead, we call mangleTypeName() that
999 // returns the name of the RTTI typeinfo symbol, and remove the _ZTS
Lukasz Anforowicz3f133972022-09-01 09:01:02 -07001000 // prefix.
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -07001001 constexpr llvm::StringRef kZtsPrefix = "_ZTS";
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -07001002 CHECK(buffer.str().take_front(4) == kZtsPrefix);
Lukasz Anforowicz3f133972022-09-01 09:01:02 -07001003 llvm::StringRef mangled_record_name =
1004 buffer.str().drop_front(kZtsPrefix.size());
1005
1006 if (clang::isa<clang::ClassTemplateSpecializationDecl>(named_decl)) {
1007 // We prepend __CcTemplateInst to reduce chances of conflict
1008 // with regular C and C++ structs.
1009 constexpr llvm::StringRef kCcTemplatePrefix = "__CcTemplateInst";
1010 return llvm::formatv("{0}{1}", kCcTemplatePrefix, mangled_record_name);
1011 }
1012 return std::string(mangled_record_name);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -07001013 }
1014
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001015 clang::GlobalDecl decl;
1016
1017 // There are only three named decl types that don't work with the GlobalDecl
1018 // unary constructor: GPU kernels (which do not exist in standard C++, so we
1019 // ignore), constructors, and destructors. GlobalDecl does not support
1020 // constructors and destructors from the unary constructor because there is
1021 // more than one global declaration for a given constructor or destructor!
1022 //
1023 // * (Ctor|Dtor)_Complete is a function which constructs / destroys the
1024 // entire object. This is what we want. :)
1025 // * Dtor_Deleting is a function which additionally calls operator delete.
1026 // * (Ctor|Dtor)_Base is a function which constructs/destroys the object but
1027 // NOT including virtual base class subobjects.
1028 // * (Ctor|Dtor)_Comdat: I *believe* this is the identifier used to
1029 // deduplicate inline functions, and is not callable.
1030 // * Dtor_(Copying|Default)Closure: These only exist in the MSVC++ ABI,
1031 // which we don't support for now. I don't know when they are used.
1032 //
1033 // It was hard to piece this together, so writing it down here to explain why
1034 // we magically picked the *_Complete variants.
Michael Forster500b4762022-01-27 12:30:17 +00001035 if (auto dtor = clang::dyn_cast<clang::CXXDestructorDecl>(named_decl)) {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001036 decl = clang::GlobalDecl(dtor, clang::CXXDtorType::Dtor_Complete);
1037 } else if (auto ctor =
Michael Forster500b4762022-01-27 12:30:17 +00001038 clang::dyn_cast<clang::CXXConstructorDecl>(named_decl)) {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001039 decl = clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete);
1040 } else {
1041 decl = clang::GlobalDecl(named_decl);
1042 }
1043
Marcel Hlopko7d739792021-08-12 07:52:47 +00001044 std::string name;
1045 llvm::raw_string_ostream stream(name);
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001046 mangler_->mangleName(decl, stream);
Marcel Hlopko7d739792021-08-12 07:52:47 +00001047 stream.flush();
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +00001048 return name;
Marcel Hlopko7d739792021-08-12 07:52:47 +00001049}
1050
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -07001051std::string Importer::GetNameForSourceOrder(const clang::Decl* decl) const {
1052 // Implicit class template specializations and their methods all have the
1053 // same source location. In order to provide deterministic order of the
1054 // respective items in generated source code, we additionally use the
1055 // mangled names when sorting the items.
1056 if (auto* class_template_specialization_decl =
1057 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
1058 return GetMangledName(class_template_specialization_decl);
1059 } else if (auto* func_decl = clang::dyn_cast<clang::FunctionDecl>(decl)) {
1060 return GetMangledName(func_decl);
Michael VanBemmel7a4d4c02022-07-27 13:21:47 -07001061 } else if (auto* friend_decl = clang::dyn_cast<clang::FriendDecl>(decl)) {
1062 if (auto* named_decl = friend_decl->getFriendDecl()) {
1063 if (auto function_template_decl =
1064 clang::dyn_cast<clang::FunctionTemplateDecl>(named_decl)) {
1065 // Reach through the function template declaration for a function that
1066 // can be mangled.
1067 named_decl = function_template_decl->getTemplatedDecl();
1068 }
1069 return GetMangledName(named_decl);
1070 } else {
1071 // This FriendDecl names a type. We don't import those, so we don't have
1072 // to assign a name.
1073 return "";
1074 }
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -07001075 } else {
1076 return "";
1077 }
1078}
1079
Lukasz Anforowicz5837b7d2023-02-23 16:39:02 -08001080absl::StatusOr<UnqualifiedIdentifier> Importer::GetTranslatedName(
Marcel Hlopko7d739792021-08-12 07:52:47 +00001081 const clang::NamedDecl* named_decl) const {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001082 switch (named_decl->getDeclName().getNameKind()) {
1083 case clang::DeclarationName::Identifier: {
1084 auto name = std::string(named_decl->getName());
Lukasz Anforowiczab03e562022-05-16 11:18:02 -07001085 if (name.empty()) {
Lukasz Anforowicz5837b7d2023-02-23 16:39:02 -08001086 return absl::InvalidArgumentError("Missing identifier");
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001087 }
Lukasz Anforowicz5837b7d2023-02-23 16:39:02 -08001088
1089 // `r#foo` syntax in Rust can't be used to escape `crate`, `self`,
1090 // `super`, not `Self` identifiers - see
1091 // https://doc.rust-lang.org/reference/identifiers.html#identifiers
1092 if (name == "crate" || name == "self" || name == "super" ||
1093 name == "Self") {
1094 return absl::InvalidArgumentError(
1095 absl::StrCat("Unescapable identifier: ", name));
1096 }
1097
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001098 return {Identifier(std::move(name))};
1099 }
1100 case clang::DeclarationName::CXXConstructorName:
1101 return {SpecialName::kConstructor};
1102 case clang::DeclarationName::CXXDestructorName:
1103 return {SpecialName::kDestructor};
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +00001104 case clang::DeclarationName::CXXOperatorName:
1105 switch (named_decl->getDeclName().getCXXOverloadedOperator()) {
1106 case clang::OO_None:
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -07001107 LOG(FATAL) << "No OO_None expected under CXXOperatorName branch";
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +00001108 case clang::NUM_OVERLOADED_OPERATORS:
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -07001109 LOG(FATAL) << "No NUM_OVERLOADED_OPERATORS expected at runtime";
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +00001110 // clang-format off
1111 #define OVERLOADED_OPERATOR(name, spelling, ...) \
1112 case clang::OO_##name: { \
Lukasz Anforowicz9c663ca2022-02-09 01:33:31 +00001113 return {Operator(spelling)}; \
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +00001114 }
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -07001115 #include "clang/Basic/OperatorKinds.def"
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +00001116 #undef OVERLOADED_OPERATOR
1117 // clang-format on
1118 }
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -07001119 LOG(FATAL) << "The `switch` above should handle all cases";
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001120 default:
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +00001121 // To be implemented later: CXXConversionFunctionName.
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001122 // There are also e.g. literal operators, deduction guides, etc., but
1123 // we might not need to implement them at all. Full list at:
1124 // https://clang.llvm.org/doxygen/classclang_1_1DeclarationName.html#a9ab322d434446b43379d39e41af5cbe3
Lukasz Anforowiczf1acde72023-02-23 16:53:43 -08001125 return absl::UnimplementedError(
1126 absl::StrCat("Unsupported name: ", named_decl->getNameAsString()));
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +00001127 }
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +00001128}
1129
Devin Jeanpierre3c4354b2023-05-26 16:01:49 -07001130void Importer::MarkAsSuccessfullyImported(const clang::NamedDecl* decl) {
Lukasz Anforowicz23fdfad2022-05-27 16:43:43 -07001131 known_type_decls_.insert(
1132 clang::cast<clang::TypeDecl>(decl->getCanonicalDecl()));
Lukasz Anforowicz0233f982022-05-27 16:38:20 -07001133}
1134
Lukasz Anforowicz5258f762022-05-27 16:14:46 -07001135bool Importer::HasBeenAlreadySuccessfullyImported(
Devin Jeanpierre3c4354b2023-05-26 16:01:49 -07001136 const clang::NamedDecl* decl) const {
Lukasz Anforowicz23fdfad2022-05-27 16:43:43 -07001137 return known_type_decls_.contains(
1138 clang::cast<clang::TypeDecl>(decl->getCanonicalDecl()));
Lukasz Anforowicz5258f762022-05-27 16:14:46 -07001139}
1140
Marcel Hlopkof15e8ce2022-04-08 08:46:09 -07001141} // namespace crubit