blob: d0874ea2db8c6c1eb3d5f573fd245dad49e7332d [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>
Devin Jeanpierre56777022022-02-03 01:57:15 +000010#include <cstddef>
Marcel Hlopko7d739792021-08-12 07:52:47 +000011#include <memory>
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000012#include <optional>
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000013#include <string>
Michael Forster365bba12022-01-24 16:56:06 +000014#include <tuple>
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000015#include <utility>
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +000016#include <variant>
Marcel Hlopko7d739792021-08-12 07:52:47 +000017#include <vector>
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000018
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070019#include "absl/container/flat_hash_map.h"
20#include "absl/container/flat_hash_set.h"
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -070021#include "absl/log/check.h"
22#include "absl/log/log.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070023#include "absl/status/status.h"
24#include "absl/status/statusor.h"
25#include "absl/strings/cord.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070026#include "absl/strings/str_cat.h"
27#include "absl/strings/str_join.h"
28#include "absl/strings/string_view.h"
29#include "absl/strings/substitute.h"
Marco Polettic61bcc42022-04-08 12:54:30 -070030#include "common/status_macros.h"
Luca Versari95ce68f2022-03-24 14:44:19 +000031#include "lifetime_annotations/type_lifetimes.h"
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -070032#include "rs_bindings_from_cc/ast_util.h"
Marcel Hlopko3b254b32022-03-09 14:10:49 +000033#include "rs_bindings_from_cc/bazel_types.h"
34#include "rs_bindings_from_cc/ir.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070035#include "clang/AST/ASTContext.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070036#include "clang/AST/Decl.h"
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -070037#include "clang/AST/DeclBase.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070038#include "clang/AST/DeclCXX.h"
Michael VanBemmel7a4d4c02022-07-27 13:21:47 -070039#include "clang/AST/DeclFriend.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070040#include "clang/AST/Mangle.h"
41#include "clang/AST/RawCommentList.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070042#include "clang/AST/Type.h"
43#include "clang/Basic/FileManager.h"
Rosica Dejanovska93aeafb2022-06-01 07:05:31 -070044#include "clang/Basic/LLVM.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070045#include "clang/Basic/OperatorKinds.h"
46#include "clang/Basic/SourceLocation.h"
47#include "clang/Basic/SourceManager.h"
48#include "clang/Basic/Specifiers.h"
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -070049#include "clang/Sema/Sema.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070050#include "llvm/ADT/Optional.h"
51#include "llvm/ADT/STLExtras.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070052#include "llvm/Support/Casting.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070053#include "llvm/Support/Regex.h"
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000054
Marcel Hlopkof15e8ce2022-04-08 08:46:09 -070055namespace crubit {
Devin Jeanpierre56777022022-02-03 01:57:15 +000056namespace {
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000057
Michael Forsterb836c582022-01-21 11:20:22 +000058constexpr absl::string_view kTypeStatusPayloadUrl =
Michael Forsterdc683af2021-09-17 08:51:28 +000059 "type.googleapis.com/devtools.rust.cc_interop.rs_binding_from_cc.type";
60
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -070061// Checks if the return value from `GetDeclItem` indicates that the import was
62// successful.
63absl::Status CheckImportStatus(const std::optional<IR::Item>& item) {
64 if (!item.has_value()) {
65 return absl::InvalidArgumentError("The import has been skipped");
66 }
67 if (auto* unsupported = std::get_if<UnsupportedItem>(&*item)) {
68 return absl::InvalidArgumentError(unsupported->message);
69 }
70 return absl::OkStatus();
71}
Devin Jeanpierree971ed72022-08-09 05:07:04 -070072} // namespace
Michael Forster64217b42022-04-22 05:48:54 -070073
Googler44e3fbc2022-01-11 10:19:26 +000074// A mapping of C++ standard types to their equivalent Rust types.
75// To produce more idiomatic results, these types receive special handling
76// instead of using the generic type mapping mechanism.
Lukasz Anforowiczff16f642022-05-27 16:56:50 -070077std::optional<absl::string_view> MapKnownCcTypeToRsType(
78 absl::string_view cc_type) {
Lukasz Anforowiczb22917e2022-02-16 23:49:59 +000079 static const auto* const kWellKnownTypes =
80 new absl::flat_hash_map<absl::string_view, absl::string_view>({
81 {"ptrdiff_t", "isize"},
82 {"intptr_t", "isize"},
83 {"size_t", "usize"},
84 {"uintptr_t", "usize"},
85 {"std::ptrdiff_t", "isize"},
86 {"std::intptr_t", "isize"},
87 {"std::size_t", "usize"},
88 {"std::uintptr_t", "usize"},
Googler4e504882022-01-13 10:03:19 +000089
Lukasz Anforowiczb22917e2022-02-16 23:49:59 +000090 {"int8_t", "i8"},
91 {"int16_t", "i16"},
92 {"int32_t", "i32"},
93 {"int64_t", "i64"},
94 {"std::int8_t", "i8"},
95 {"std::int16_t", "i16"},
96 {"std::int32_t", "i32"},
97 {"std::int64_t", "i64"},
Googler4e504882022-01-13 10:03:19 +000098
Lukasz Anforowiczb22917e2022-02-16 23:49:59 +000099 {"uint8_t", "u8"},
100 {"uint16_t", "u16"},
101 {"uint32_t", "u32"},
Devin Jeanpierre56777022022-02-03 01:57:15 +0000102
Lukasz Anforowiczb22917e2022-02-16 23:49:59 +0000103 {"uint64_t", "u64"},
104 {"std::uint8_t", "u8"},
105 {"std::uint16_t", "u16"},
106 {"std::uint32_t", "u32"},
107 {"std::uint64_t", "u64"},
Googler4e504882022-01-13 10:03:19 +0000108
Lukasz Anforowiczb22917e2022-02-16 23:49:59 +0000109 {"char16_t", "u16"},
110 {"char32_t", "u32"},
111 {"wchar_t", "i32"},
112 });
113 auto it = kWellKnownTypes->find(cc_type);
114 if (it == kWellKnownTypes->end()) return std::nullopt;
115 return it->second;
116}
Googler44e3fbc2022-01-11 10:19:26 +0000117
Michael Forster64217b42022-04-22 05:48:54 -0700118namespace {
119
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000120// Converts clang::CallingConv enum [1] into an equivalent Rust Abi [2, 3, 4].
121// [1]
122// https://github.com/llvm/llvm-project/blob/c6a3225bb03b6afc2b63fbf13db3c100406b32ce/clang/include/clang/Basic/Specifiers.h#L262-L283
123// [2] https://doc.rust-lang.org/reference/types/function-pointer.html
124// [3]
125// https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
126// [4]
127// https://github.com/rust-lang/rust/blob/b27ccbc7e1e6a04d749e244a3c13f72ca38e80e7/compiler/rustc_target/src/spec/abi.rs#L49
128absl::StatusOr<absl::string_view> ConvertCcCallConvIntoRsAbi(
129 clang::CallingConv cc_call_conv) {
130 switch (cc_call_conv) {
131 case clang::CC_C: // __attribute__((cdecl))
132 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
133 // that:
134 // - `extern "C"` [...] whatever the default your C compiler supports.
135 // - `extern "cdecl"` -- The default for x86_32 C code.
136 //
137 // We don't support C++ exceptions and therefore we use "C" (rather than
138 // "C-unwind") - we have no need for unwinding across the FFI boundary -
139 // e.g. from C++ into Rust frames (or vice versa).
140 return "C";
141 case clang::CC_X86FastCall: // __attribute__((fastcall))
142 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
143 // that the fastcall ABI -- corresponds to MSVC's __fastcall and GCC and
144 // clang's __attribute__((fastcall)).
145 return "fastcall";
146 case clang::CC_X86VectorCall: // __attribute__((vectorcall))
147 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
148 // that the vectorcall ABI -- corresponds to MSVC's __vectorcall and
149 // clang's __attribute__((vectorcall)).
150 return "vectorcall";
151 case clang::CC_X86ThisCall: // __attribute__((thiscall))
152 // We don't support C++ exceptions and therefore we use "thiscall" (rather
153 // than "thiscall-unwind") - we have no need for unwinding across the FFI
154 // boundary - e.g. from C++ into Rust frames (or vice versa).
155 return "thiscall";
156 case clang::CC_X86StdCall: // __attribute__((stdcall))
157 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
158 // extern "stdcall" -- The default for the Win32 API on x86_32.
159 //
160 // We don't support C++ exceptions and therefore we use "stdcall" (rather
161 // than "stdcall-unwind") - we have no need for unwinding across the FFI
162 // boundary - e.g. from C++ into Rust frames (or vice versa).
163 return "stdcall";
164 case clang::CC_Win64: // __attribute__((ms_abi))
165 // https://doc.rust-lang.org/reference/items/external-blocks.html#abi says
166 // extern "win64" -- The default for C code on x86_64 Windows.
167 return "win64";
168 case clang::CC_AAPCS: // __attribute__((pcs("aapcs")))
169 case clang::CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp")))
170 // TODO(lukasza): Should both map to "aapcs"?
171 break;
172 case clang::CC_X86_64SysV: // __attribute__((sysv_abi))
173 // TODO(lukasza): Maybe this is "sysv64"?
174 break;
175 case clang::CC_X86Pascal: // __attribute__((pascal))
176 case clang::CC_X86RegCall: // __attribute__((regcall))
177 case clang::CC_IntelOclBicc: // __attribute__((intel_ocl_bicc))
178 case clang::CC_SpirFunction: // default for OpenCL functions on SPIR target
179 case clang::CC_OpenCLKernel: // inferred for OpenCL kernels
180 case clang::CC_Swift: // __attribute__((swiftcall))
181 case clang::CC_SwiftAsync: // __attribute__((swiftasynccall))
182 case clang::CC_PreserveMost: // __attribute__((preserve_most))
183 case clang::CC_PreserveAll: // __attribute__((preserve_all))
184 case clang::CC_AArch64VectorCall: // __attribute__((aarch64_vector_pcs))
Marcel Hlopkof80bf512022-05-12 01:20:33 -0700185 // TODO(hlopko): Uncomment once we integrate the upstream change that
186 // introduced it:
187 // case clang::CC_AArch64SVEPCS: __attribute__((aarch64_sve_pcs))
188
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000189 // These don't seem to have any Rust equivalents.
190 break;
Marcel Hlopkof80bf512022-05-12 01:20:33 -0700191 default:
Googler75c7ad02022-05-23 13:27:49 -0700192 break;
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000193 }
194 return absl::UnimplementedError(
195 absl::StrCat("Unsupported calling convention: ",
196 absl::string_view(
197 clang::FunctionType::getNameForCallConv(cc_call_conv))));
198}
199
Devin Jeanpierre56777022022-02-03 01:57:15 +0000200} // namespace
201
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000202// Multiple IR items can be associated with the same source location (e.g. the
203// implicitly defined constructors and assignment operators). To produce
204// deterministic output, we order such items based on GetDeclOrder. The order
205// is somewhat arbitrary, but we still try to make it aesthetically pleasing
206// (e.g. constructors go before assignment operators; default constructor goes
207// first, etc.).
208static int GetDeclOrder(const clang::Decl* decl) {
209 if (clang::isa<clang::RecordDecl>(decl)) {
210 return decl->getDeclContext()->isRecord() ? 101 : 100;
211 }
212
213 if (auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
214 return ctor->isDefaultConstructor() ? 202
215 : ctor->isCopyConstructor() ? 203
216 : ctor->isMoveConstructor() ? 204
217 : 299;
218 }
219
220 if (clang::isa<clang::CXXDestructorDecl>(decl)) {
221 return 306;
222 }
223
224 if (auto* method = clang::dyn_cast<clang::CXXMethodDecl>(decl)) {
225 return method->isCopyAssignmentOperator() ? 401
226 : method->isMoveAssignmentOperator() ? 402
227 : 499;
228 }
229
230 return 999;
231}
232
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700233class Importer::SourceOrderKey {
234 public:
235 SourceOrderKey(clang::SourceRange source_range, int decl_order = 0,
236 std::string name = "")
237 : source_range_(source_range), decl_order_(decl_order), name_(name) {}
238
239 SourceOrderKey(const SourceOrderKey&) = default;
240 SourceOrderKey& operator=(const SourceOrderKey&) = default;
241
242 bool isBefore(const SourceOrderKey& other,
243 const clang::SourceManager& sm) const {
244 if (!source_range_.isValid() || !other.source_range_.isValid()) {
245 if (source_range_.isValid() != other.source_range_.isValid())
246 return !source_range_.isValid() && other.source_range_.isValid();
247 } else {
248 if (source_range_.getBegin() != other.source_range_.getBegin()) {
249 return sm.isBeforeInTranslationUnit(source_range_.getBegin(),
250 other.source_range_.getBegin());
251 }
252 if (source_range_.getEnd() != other.source_range_.getEnd()) {
253 return sm.isBeforeInTranslationUnit(source_range_.getEnd(),
254 other.source_range_.getEnd());
255 }
256 }
257
258 if (decl_order_ < other.decl_order_) {
259 return true;
260 } else if (decl_order_ > other.decl_order_) {
261 return false;
262 }
263 return name_ < other.name_;
264 }
265
266 private:
267 clang::SourceRange source_range_;
268 int decl_order_;
269 std::string name_;
270};
271
272Importer::SourceOrderKey Importer::GetSourceOrderKey(
273 const clang::Decl* decl) const {
274 return SourceOrderKey(decl->getSourceRange(), GetDeclOrder(decl),
275 GetNameForSourceOrder(decl));
276}
277
278Importer::SourceOrderKey Importer::GetSourceOrderKey(
279 const clang::RawComment* comment) const {
280 return SourceOrderKey(comment->getSourceRange());
281}
282
283class Importer::SourceLocationComparator {
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700284 public:
285 const bool operator()(const clang::SourceLocation& a,
286 const clang::SourceLocation& b) const {
287 return b.isValid() && a.isValid() && sm.isBeforeInTranslationUnit(a, b);
288 }
289 const bool operator()(const clang::RawComment* a,
290 const clang::SourceLocation& b) const {
291 return this->operator()(a->getBeginLoc(), b);
292 }
293 const bool operator()(const clang::SourceLocation& a,
294 const clang::RawComment* b) const {
295 return this->operator()(a, b->getBeginLoc());
296 }
297 const bool operator()(const clang::RawComment* a,
298 const clang::RawComment* b) const {
299 return this->operator()(a->getBeginLoc(), b->getBeginLoc());
300 }
Michael Forstera49d2e62022-01-28 07:26:40 +0000301
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700302 using OrderedItemId = std::pair<SourceOrderKey, ItemId>;
303 using OrderedItem = std::pair<SourceOrderKey, IR::Item>;
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700304
305 template <typename OrderedItemOrId>
306 bool operator()(const OrderedItemOrId& a, const OrderedItemOrId& b) const {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700307 auto a_source_order = a.first;
308 auto b_source_order = b.first;
309 return a_source_order.isBefore(b_source_order, sm);
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700310 }
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700311 SourceLocationComparator(const clang::SourceManager& sm) : sm(sm) {}
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700312
313 private:
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700314 const clang::SourceManager& sm;
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700315};
316
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700317static std::vector<clang::Decl*> GetCanonicalChildren(
318 const clang::DeclContext* decl_context) {
319 std::vector<clang::Decl*> result;
320 for (clang::Decl* decl : decl_context->decls()) {
321 if (const auto* linkage_spec_decl =
322 llvm::dyn_cast<clang::LinkageSpecDecl>(decl)) {
323 llvm::move(GetCanonicalChildren(linkage_spec_decl),
324 std::back_inserter(result));
325 continue;
326 }
327
Lukasz Anforowicz38310f32022-09-09 11:17:52 -0700328 // `CXXRecordDeclImporter::Import` supports class template specializations
329 // but such import should only be triggered when
330 // `Importer::ConvertTemplateSpecializationType` is called (which means that
331 // the specialization is actually used in an explicit instantiation via
332 // `cc_template!` macro, in a type alias, or as a parameter type of a
333 // function, etc.).
334 if (clang::isa<clang::ClassTemplateSpecializationDecl>(decl)) continue;
335
Lukasz Anforowicz02ce0f72022-09-02 12:10:26 -0700336 // In general we only import (and include as children) canonical decls.
337 // Namespaces are exempted to ensure that we process every one of
338 // (potential) multiple namespace blocks with the same name.
339 if (decl == decl->getCanonicalDecl() ||
340 clang::isa<clang::NamespaceDecl>(decl)) {
341 result.push_back(decl);
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700342 }
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700343 }
344
345 return result;
346}
347
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700348std::vector<ItemId> Importer::GetItemIdsInSourceOrder(
349 clang::Decl* parent_decl) {
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700350 clang::SourceManager& sm = ctx_.getSourceManager();
351 std::vector<SourceLocationComparator::OrderedItemId> items;
352 auto compare_locations = SourceLocationComparator(sm);
353
354 // We are only interested in comments within this decl context.
355 std::vector<const clang::RawComment*> comments_in_range(
356 llvm::lower_bound(comments_, parent_decl->getBeginLoc(),
357 compare_locations),
358 llvm::upper_bound(comments_, parent_decl->getEndLoc(),
359 compare_locations));
360
361 std::map<clang::SourceLocation, const clang::RawComment*,
362 SourceLocationComparator>
363 ordered_comments(compare_locations);
364 for (auto& comment : comments_in_range) {
365 ordered_comments.insert({comment->getBeginLoc(), comment});
366 }
367
368 absl::flat_hash_set<ItemId> visited_item_ids;
Marcel Hlopkod4678de2022-05-25 01:38:13 -0700369
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700370 auto* decl_context = clang::cast<clang::DeclContext>(parent_decl);
371 for (auto decl : GetCanonicalChildren(decl_context)) {
Rosica Dejanovska001852d2022-06-07 14:19:41 -0700372 auto item = GetDeclItem(decl);
373 // We generated IR for top level items coming from different targets,
374 // however we shouldn't generate bindings for them, so we don't add them
375 // to ir.top_level_item_ids.
376 if (decl_context->isTranslationUnit() && !IsFromCurrentTarget(decl))
377 continue;
378 // Only add item ids for decls that can be successfully imported.
379 if (item.has_value()) {
380 auto item_id = GenerateItemId(decl);
381 // TODO(rosica): Drop this check when we start importing also other
382 // redecls, not just the canonical
383 if (visited_item_ids.find(item_id) == visited_item_ids.end()) {
384 visited_item_ids.insert(item_id);
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700385 items.push_back({GetSourceOrderKey(decl), item_id});
Rosica Dejanovska001852d2022-06-07 14:19:41 -0700386 }
387 }
388
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700389 // We remove comments attached to a child decl or that are within a child
390 // decl.
391 if (auto raw_comment = ctx_.getRawCommentForDeclNoCache(decl)) {
392 ordered_comments.erase(raw_comment->getBeginLoc());
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000393 }
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700394 ordered_comments.erase(ordered_comments.lower_bound(decl->getBeginLoc()),
395 ordered_comments.upper_bound(decl->getEndLoc()));
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700396 }
Michael Forster365bba12022-01-24 16:56:06 +0000397
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700398 for (auto& [_, comment] : ordered_comments) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700399 items.push_back({GetSourceOrderKey(comment), GenerateItemId(comment)});
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700400 }
Dmitri Gribenko620bc912022-04-22 03:38:04 -0700401 llvm::sort(items, compare_locations);
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700402
403 std::vector<ItemId> ordered_item_ids;
404 ordered_item_ids.reserve(items.size());
405 for (auto& ordered_item : items) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700406 ordered_item_ids.push_back(ordered_item.second);
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700407 }
408 return ordered_item_ids;
409}
410
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700411std::vector<ItemId> Importer::GetOrderedItemIdsOfTemplateInstantiations()
412 const {
413 std::vector<SourceLocationComparator::OrderedItemId> items;
414 items.reserve(class_template_instantiations_for_current_target_.size());
415 for (const auto* decl : class_template_instantiations_for_current_target_) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700416 items.push_back({GetSourceOrderKey(decl), GenerateItemId(decl)});
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700417 }
418
419 clang::SourceManager& sm = ctx_.getSourceManager();
420 auto compare_locations = SourceLocationComparator(sm);
421 llvm::sort(items, compare_locations);
422
423 std::vector<ItemId> ordered_item_ids;
424 ordered_item_ids.reserve(items.size());
425 for (const auto& ordered_item : items) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700426 ordered_item_ids.push_back(ordered_item.second);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700427 }
428 return ordered_item_ids;
429}
430
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700431void Importer::ImportFreeComments() {
432 clang::SourceManager& sm = ctx_.getSourceManager();
433 for (const auto& header : invocation_.entry_headers_) {
434 if (auto file = sm.getFileManager().getFile(header.IncludePath())) {
435 if (auto comments_in_file = ctx_.Comments.getCommentsInFile(
436 sm.getOrCreateFileID(*file, clang::SrcMgr::C_User))) {
437 for (const auto& [_, comment] : *comments_in_file) {
438 comments_.push_back(comment);
439 }
440 }
441 }
442 }
Dmitri Gribenko620bc912022-04-22 03:38:04 -0700443 llvm::sort(comments_, SourceLocationComparator(sm));
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700444}
445
446void Importer::Import(clang::TranslationUnitDecl* translation_unit_decl) {
447 ImportFreeComments();
448 clang::SourceManager& sm = ctx_.getSourceManager();
449 std::vector<SourceLocationComparator::OrderedItem> ordered_items;
450
451 for (auto& comment : comments_) {
452 ordered_items.push_back(
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700453 {GetSourceOrderKey(comment),
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700454 Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics()),
455 .id = GenerateItemId(comment)}});
456 }
457
458 ImportDeclsFromDeclContext(translation_unit_decl);
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000459 for (const auto& [decl, item] : import_cache_) {
460 if (item.has_value()) {
461 if (std::holds_alternative<UnsupportedItem>(*item) &&
462 !IsFromCurrentTarget(decl)) {
463 continue;
464 }
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700465 ordered_items.push_back({GetSourceOrderKey(decl), *item});
Michael Forster500b4762022-01-27 12:30:17 +0000466 }
Michael Forster365bba12022-01-24 16:56:06 +0000467 }
Michael Forster500b4762022-01-27 12:30:17 +0000468
Dmitri Gribenko620bc912022-04-22 03:38:04 -0700469 llvm::sort(ordered_items, SourceLocationComparator(sm));
Michael Forster365bba12022-01-24 16:56:06 +0000470
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700471 invocation_.ir_.items.reserve(ordered_items.size());
472 for (auto& ordered_item : ordered_items) {
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700473 invocation_.ir_.items.push_back(ordered_item.second);
Michael Forster365bba12022-01-24 16:56:06 +0000474 }
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700475 invocation_.ir_.top_level_item_ids =
476 GetItemIdsInSourceOrder(translation_unit_decl);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700477
478 // TODO(b/222001243): Consider placing the generated template instantiations
479 // into a separate namespace (maybe `crubit::instantiated_templates` ?).
480 llvm::copy(GetOrderedItemIdsOfTemplateInstantiations(),
481 std::back_inserter(invocation_.ir_.top_level_item_ids));
Michael Forster365bba12022-01-24 16:56:06 +0000482}
483
Michael Forster500b4762022-01-27 12:30:17 +0000484void Importer::ImportDeclsFromDeclContext(
485 const clang::DeclContext* decl_context) {
Lukasz Anforowiczd1e7cdf2022-09-02 11:09:33 -0700486 for (auto decl : GetCanonicalChildren(decl_context)) {
487 GetDeclItem(decl);
Michael Forster500b4762022-01-27 12:30:17 +0000488 }
489}
490
Michael Forster1b506372022-04-12 11:31:54 -0700491std::optional<IR::Item> Importer::GetDeclItem(clang::Decl* decl) {
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000492 // TODO: Move `decl->getCanonicalDecl()` from callers into here.
Michael Forster1b506372022-04-12 11:31:54 -0700493 auto it = import_cache_.find(decl);
494 if (it == import_cache_.end()) {
495 it = import_cache_.insert({decl, ImportDecl(decl)}).first;
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000496 }
Michael Forster1b506372022-04-12 11:31:54 -0700497 return it->second;
Michael Forster500b4762022-01-27 12:30:17 +0000498}
499
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000500std::optional<IR::Item> Importer::ImportDecl(clang::Decl* decl) {
Michael Forster64217b42022-04-22 05:48:54 -0700501 std::optional<IR::Item> result;
502 for (auto& importer : decl_importers_) {
503 if (importer->CanImport(decl)) {
504 result = importer->ImportDecl(decl);
505 }
506 }
507
508 if (auto* record_decl = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
Michael Forster500b4762022-01-27 12:30:17 +0000509 // TODO(forster): Should we even visit the nested decl if we couldn't
510 // import the parent? For now we have tests that check that we generate
511 // error messages for those decls, so we're visiting.
512 ImportDeclsFromDeclContext(record_decl);
Michael Forster500b4762022-01-27 12:30:17 +0000513 }
Michael Forster64217b42022-04-22 05:48:54 -0700514
515 return result;
Michael Forster500b4762022-01-27 12:30:17 +0000516}
517
Kinuko Yasuda6ff59f12022-08-11 08:41:45 -0700518std::optional<IR::Item> Importer::GetImportedItem(const clang::Decl* decl) {
519 auto it = import_cache_.find(decl);
520 if (it != import_cache_.end()) {
521 return it->second;
522 }
523 return std::nullopt;
524}
525
Googler6c3de122022-03-28 11:40:41 +0000526BazelLabel Importer::GetOwningTarget(const clang::Decl* decl) const {
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700527 // Template instantiations need to be generated in the target that triggered
528 // the instantiation (not in the target where the template is defined).
529 if (IsFullClassTemplateSpecializationOrChild(decl)) {
530 return invocation_.target_;
531 }
532
Michael Forstera49d2e62022-01-28 07:26:40 +0000533 clang::SourceManager& source_manager = ctx_.getSourceManager();
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000534 auto source_location = decl->getLocation();
Marcel Hlopko80441c12021-11-12 10:43:18 +0000535
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000536 // If the header this decl comes from is not associated with a target we
537 // consider it a textual header. In that case we go up the include stack
538 // until we find a header that has an owning target.
539
Rosica Dejanovska381d1032022-02-03 22:19:54 +0000540 while (source_location.isValid()) {
Rosica Dejanovska503d7dd2022-02-01 20:37:49 +0000541 if (source_location.isMacroID()) {
542 source_location = source_manager.getExpansionLoc(source_location);
543 }
544 auto id = source_manager.getFileID(source_location);
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000545 llvm::Optional<llvm::StringRef> filename =
546 source_manager.getNonBuiltinFilenameForID(id);
547 if (!filename) {
Marcel Hlopko457bdef2022-05-18 06:01:49 -0700548 return BazelLabel("//:_nothing_should_depend_on_private_builtin_hdrs");
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000549 }
550 if (filename->startswith("./")) {
551 filename = filename->substr(2);
552 }
Michael Forstera49d2e62022-01-28 07:26:40 +0000553
554 if (auto target = invocation_.header_target(HeaderName(filename->str()))) {
555 return *target;
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000556 }
557 source_location = source_manager.getIncludeLoc(id);
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000558 }
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000559
Googler6c3de122022-03-28 11:40:41 +0000560 return BazelLabel("//:virtual_clang_resource_dir_target");
Marcel Hlopko80441c12021-11-12 10:43:18 +0000561}
562
Michael Forster500b4762022-01-27 12:30:17 +0000563bool Importer::IsFromCurrentTarget(const clang::Decl* decl) const {
Michael Forstera49d2e62022-01-28 07:26:40 +0000564 return invocation_.target_ == GetOwningTarget(decl);
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000565}
566
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000567IR::Item Importer::ImportUnsupportedItem(const clang::Decl* decl,
568 std::string error) {
569 std::string name = "unnamed";
570 if (const auto* named_decl = clang::dyn_cast<clang::NamedDecl>(decl)) {
571 name = named_decl->getQualifiedNameAsString();
572 }
573 SourceLoc source_loc = ConvertSourceLocation(decl->getBeginLoc());
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000574 return UnsupportedItem{.name = name,
575 .message = error,
576 .source_loc = source_loc,
577 .id = GenerateItemId(decl)};
Lukasz Anforowicz06f76b12022-03-23 13:48:39 +0000578}
579
580IR::Item Importer::ImportUnsupportedItem(const clang::Decl* decl,
581 std::set<std::string> errors) {
582 return ImportUnsupportedItem(decl, absl::StrJoin(errors, "\n\n"));
583}
584
Lukasz Anforowiczc4ceb4f2022-01-28 19:29:19 +0000585static bool ShouldKeepCommentLine(absl::string_view line) {
586 // Based on https://clang.llvm.org/extra/clang-tidy/:
587 llvm::Regex patterns_to_ignore(
588 "^[[:space:]/]*" // Whitespace, or extra //
589 "(NOLINT|NOLINTNEXTLINE|NOLINTBEGIN|NOLINTEND)"
590 "(\\([^)[:space:]]*\\)?)?" // Optional (...)
591 "[[:space:]]*$"); // Whitespace
592 return !patterns_to_ignore.match(line);
593}
594
Lukasz Anforowicz3b4be122022-03-16 00:09:35 +0000595llvm::Optional<std::string> Importer::GetComment(
596 const clang::Decl* decl) const {
Michael Forster409d9412021-10-07 08:35:29 +0000597 // This does currently not distinguish between different types of comments.
598 // In general it is not possible in C++ to reliably only extract doc comments.
599 // This is going to be a heuristic that needs to be tuned over time.
600
Michael Forstera49d2e62022-01-28 07:26:40 +0000601 clang::SourceManager& sm = ctx_.getSourceManager();
602 clang::RawComment* raw_comment = ctx_.getRawCommentForDeclNoCache(decl);
Michael Forstercc5941a2021-10-07 07:12:24 +0000603
604 if (raw_comment == nullptr) {
605 return {};
Michael Forstercc5941a2021-10-07 07:12:24 +0000606 }
Lukasz Anforowiczc4ceb4f2022-01-28 19:29:19 +0000607
608 std::string raw_comment_text =
609 raw_comment->getFormattedText(sm, sm.getDiagnostics());
610 std::string cleaned_comment_text = absl::StrJoin(
611 absl::StrSplit(raw_comment_text, '\n', ShouldKeepCommentLine), "\n");
Lukasz Anforowicz3b4be122022-03-16 00:09:35 +0000612 if (cleaned_comment_text.empty()) return {};
613 return cleaned_comment_text;
Michael Forstercc5941a2021-10-07 07:12:24 +0000614}
615
Michael Forster500b4762022-01-27 12:30:17 +0000616SourceLoc Importer::ConvertSourceLocation(clang::SourceLocation loc) const {
Michael Forstera49d2e62022-01-28 07:26:40 +0000617 auto& sm = ctx_.getSourceManager();
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000618
Googlerc8a8e732021-10-19 07:49:24 +0000619 clang::StringRef filename = sm.getFilename(loc);
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000620 if (filename.startswith("./")) {
621 filename = filename.substr(2);
622 }
623
624 return SourceLoc{.filename = filename.str(),
625 .line = sm.getSpellingLineNumber(loc),
626 .column = sm.getSpellingColumnNumber(loc)};
627}
628
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700629absl::StatusOr<MappedType> Importer::ConvertTemplateSpecializationType(
630 const clang::TemplateSpecializationType* type) {
631 // Qualifiers are handled separately in TypeMapper::ConvertQualType().
632 std::string type_string = clang::QualType(type, 0).getAsString();
633
634 auto* specialization_decl =
635 clang::dyn_cast_or_null<clang::ClassTemplateSpecializationDecl>(
636 type->getAsCXXRecordDecl());
637 if (!specialization_decl) {
638 return absl::InvalidArgumentError(absl::Substitute(
639 "Template specialization '$0' without an associated record decl "
640 "is not supported.",
641 type_string));
642 }
643
Lukasz Anforowicz3a2026b2022-06-09 09:08:42 -0700644 if (HasBeenAlreadySuccessfullyImported(specialization_decl))
645 return ConvertTypeDecl(specialization_decl);
646
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700647 // `Sema::isCompleteType` will try to instantiate the class template as a
648 // side-effect and we rely on this here. `decl->getDefinition()` can
649 // return nullptr before the call to sema and return its definition
650 // afterwards.
Lukasz Anforowicz38310f32022-09-09 11:17:52 -0700651 (void)sema_.isCompleteType(specialization_decl->getLocation(),
652 ctx_.getRecordType(specialization_decl));
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700653
654 // TODO(lukasza): Limit specialization depth? (e.g. using
655 // `isSpecializationDepthGreaterThan` from earlier prototypes).
656
657 absl::Status import_status =
658 CheckImportStatus(GetDeclItem(specialization_decl));
659 if (!import_status.ok()) {
660 return absl::InvalidArgumentError(absl::Substitute(
661 "Failed to create bindings for template specialization type $0: $1",
662 type_string, import_status.message()));
663 }
664
Lukasz Anforowicz38310f32022-09-09 11:17:52 -0700665 // Store `specialization_decl`s so that they will get included in
666 // IR::top_level_item_ids.
667 class_template_instantiations_for_current_target_.insert(specialization_decl);
Lukasz Anforowicz42ab93b2022-08-31 11:17:59 -0700668
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700669 return ConvertTypeDecl(specialization_decl);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700670}
671
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700672absl::StatusOr<MappedType> Importer::ConvertTypeDecl(
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000673 const clang::TypeDecl* decl) const {
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700674 if (!HasBeenAlreadySuccessfullyImported(decl)) {
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000675 return absl::NotFoundError(absl::Substitute(
676 "No generated bindings found for '$0'", decl->getNameAsString()));
677 }
678
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000679 ItemId decl_id = GenerateItemId(decl);
Lukasz Anforowicz58f27112022-03-15 17:51:03 +0000680 return MappedType::WithDeclId(decl_id);
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000681}
682
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700683absl::StatusOr<MappedType> Importer::ConvertType(
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000684 const clang::Type* type,
Martin Brænne1a207c52022-04-19 00:05:38 -0700685 std::optional<clang::tidy::lifetimes::ValueLifetimes>& lifetimes,
Lukasz Anforowicz14732b22022-06-02 09:11:08 -0700686 bool nullable) {
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000687 // Qualifiers are handled separately in ConvertQualType().
688 std::string type_string = clang::QualType(type, 0).getAsString();
Michael Forsterdc683af2021-09-17 08:51:28 +0000689
Lukasz Anforowiczff16f642022-05-27 16:56:50 -0700690 if (auto maybe_mapped_type = MapKnownCcTypeToRsType(type_string);
Lukasz Anforowiczb22917e2022-02-16 23:49:59 +0000691 maybe_mapped_type.has_value()) {
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000692 return MappedType::Simple(std::string(*maybe_mapped_type), type_string);
Devin Jeanpierredeea7892022-03-29 02:13:31 -0700693 } else if (type->isPointerType() || type->isLValueReferenceType() ||
694 type->isRValueReferenceType()) {
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000695 clang::QualType pointee_type = type->getPointeeType();
Lukasz Anforowicz92c81c32022-03-04 19:03:56 +0000696 std::optional<LifetimeId> lifetime;
697 if (lifetimes.has_value()) {
Luca Versari95ce68f2022-03-24 14:44:19 +0000698 lifetime =
699 LifetimeId(lifetimes->GetPointeeLifetimes().GetLifetime().Id());
700 lifetimes = lifetimes->GetPointeeLifetimes().GetValueLifetimes();
Lukasz Anforowicz92c81c32022-03-04 19:03:56 +0000701 }
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000702 if (const auto* func_type =
Lukasz Anforowicz92c81c32022-03-04 19:03:56 +0000703 pointee_type->getAs<clang::FunctionProtoType>()) {
704 if (lifetime.has_value() &&
Martin Brænne1a207c52022-04-19 00:05:38 -0700705 lifetime->value() !=
706 clang::tidy::lifetimes::Lifetime::Static().Id()) {
Lukasz Anforowicz92c81c32022-03-04 19:03:56 +0000707 return absl::UnimplementedError(
708 absl::StrCat("Function pointers with non-'static lifetimes are "
709 "not supported: ",
710 type_string));
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000711 }
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000712
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000713 clang::StringRef cc_call_conv =
714 clang::FunctionType::getNameForCallConv(func_type->getCallConv());
Lukasz Anforowiczd41a4e92022-03-17 17:08:57 +0000715 CRUBIT_ASSIGN_OR_RETURN(
716 absl::string_view rs_abi,
717 ConvertCcCallConvIntoRsAbi(func_type->getCallConv()));
718 CRUBIT_ASSIGN_OR_RETURN(
719 MappedType mapped_return_type,
720 ConvertQualType(func_type->getReturnType(), lifetimes));
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000721
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000722 std::vector<MappedType> mapped_param_types;
723 for (const clang::QualType& param_type : func_type->getParamTypes()) {
Lukasz Anforowiczd41a4e92022-03-17 17:08:57 +0000724 CRUBIT_ASSIGN_OR_RETURN(MappedType mapped_param_type,
725 ConvertQualType(param_type, lifetimes));
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000726 mapped_param_types.push_back(std::move(mapped_param_type));
Lukasz Anforowiczcf230fd2022-02-18 19:20:39 +0000727 }
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000728
729 if (type->isPointerType()) {
730 return MappedType::FuncPtr(cc_call_conv, rs_abi, lifetime,
731 std::move(mapped_return_type),
732 std::move(mapped_param_types));
733 } else {
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700734 CHECK(type->isLValueReferenceType());
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000735 return MappedType::FuncRef(cc_call_conv, rs_abi, lifetime,
736 std::move(mapped_return_type),
737 std::move(mapped_param_types));
738 }
739 }
740
Lukasz Anforowiczd41a4e92022-03-17 17:08:57 +0000741 CRUBIT_ASSIGN_OR_RETURN(MappedType mapped_pointee_type,
742 ConvertQualType(pointee_type, lifetimes));
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000743 if (type->isPointerType()) {
744 return MappedType::PointerTo(std::move(mapped_pointee_type), lifetime,
745 nullable);
Devin Jeanpierredeea7892022-03-29 02:13:31 -0700746 } else if (type->isLValueReferenceType()) {
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000747 return MappedType::LValueReferenceTo(std::move(mapped_pointee_type),
748 lifetime);
Devin Jeanpierredeea7892022-03-29 02:13:31 -0700749 } else {
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700750 CHECK(type->isRValueReferenceType());
Devin Jeanpierredeea7892022-03-29 02:13:31 -0700751 if (!lifetime.has_value()) {
752 return absl::UnimplementedError(
753 "Unsupported type: && without lifetime");
754 }
755 return MappedType::RValueReferenceTo(std::move(mapped_pointee_type),
756 *lifetime);
Googler61dce3b2021-12-02 09:16:32 +0000757 }
Googlerb6c0fe02021-12-01 10:55:31 +0000758 } else if (const auto* builtin_type =
Googler06f2c9a2022-01-05 12:00:47 +0000759 // Use getAsAdjusted instead of getAs so we don't desugar
760 // typedefs.
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000761 type->getAsAdjusted<clang::BuiltinType>()) {
Michael Forster51da81a2021-09-20 07:14:23 +0000762 switch (builtin_type->getKind()) {
763 case clang::BuiltinType::Bool:
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000764 return MappedType::Simple("bool", "bool");
Michael Forster51da81a2021-09-20 07:14:23 +0000765 break;
766 case clang::BuiltinType::Float:
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000767 return MappedType::Simple("f32", "float");
Michael Forster51da81a2021-09-20 07:14:23 +0000768 break;
769 case clang::BuiltinType::Double:
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000770 return MappedType::Simple("f64", "double");
Michael Forster51da81a2021-09-20 07:14:23 +0000771 break;
772 case clang::BuiltinType::Void:
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000773 return MappedType::Void();
Michael Forster51da81a2021-09-20 07:14:23 +0000774 break;
775 default:
776 if (builtin_type->isIntegerType()) {
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700777 auto size = ctx_.getTypeSize(builtin_type);
Googler06f2c9a2022-01-05 12:00:47 +0000778 if (size == 8 || size == 16 || size == 32 || size == 64) {
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000779 return MappedType::Simple(
Michael Forster51da81a2021-09-20 07:14:23 +0000780 absl::Substitute(
781 "$0$1", builtin_type->isSignedInteger() ? 'i' : 'u', size),
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000782 type_string);
Michael Forster51da81a2021-09-20 07:14:23 +0000783 }
784 }
Marcel Hlopko7d739792021-08-12 07:52:47 +0000785 }
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000786 } else if (const auto* tag_type = type->getAsAdjusted<clang::TagType>()) {
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000787 return ConvertTypeDecl(tag_type->getDecl());
Michael Forster365bba12022-01-24 16:56:06 +0000788 } else if (const auto* typedef_type =
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000789 type->getAsAdjusted<clang::TypedefType>()) {
Lukasz Anforowiczb6635b02022-03-08 19:13:53 +0000790 return ConvertTypeDecl(typedef_type->getDecl());
Lukasz Anforowicz14732b22022-06-02 09:11:08 -0700791 } else if (const auto* tst_type =
792 type->getAs<clang::TemplateSpecializationType>()) {
793 return ConvertTemplateSpecializationType(tst_type);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700794 } else if (const auto* subst_type =
795 type->getAs<clang::SubstTemplateTypeParmType>()) {
796 return ConvertQualType(subst_type->getReplacementType(), lifetimes);
Lukasz Anforowicz8f590682022-05-17 12:39:20 -0700797 } else if (const auto* deduced_type = type->getAs<clang::DeducedType>()) {
798 // Deduction should have taken place earlier (e.g. via DeduceReturnType
799 // called from FunctionDeclImporter::Import).
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700800 CHECK(deduced_type->isDeduced());
Lukasz Anforowicz8f590682022-05-17 12:39:20 -0700801 return ConvertQualType(deduced_type->getDeducedType(), lifetimes);
Marcel Hlopko7d739792021-08-12 07:52:47 +0000802 }
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000803
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000804 return absl::UnimplementedError(absl::StrCat(
805 "Unsupported clang::Type class '", type->getTypeClassName(), "'"));
806}
807
Devin Jeanpierree971ed72022-08-09 05:07:04 -0700808// Returns a QualType with leading ElaboratedType nodes removed.
809//
810// This is analogous to getDesugaredType but *only* removes ElaboratedType
811// sugar.
812static clang::QualType GetUnelaboratedType(clang::QualType qual_type,
813 clang::ASTContext& ast_context) {
814 clang::QualifierCollector qualifiers;
815 while (true) {
816 const clang::Type* type = qualifiers.strip(qual_type);
817 if (const auto* elaborated = llvm::dyn_cast<clang::ElaboratedType>(type)) {
818 qual_type = elaborated->getNamedType();
819 continue;
820 }
821
822 return ast_context.getQualifiedType(type, qualifiers);
823 }
824}
825
Lukasz Anforowicz63559d32022-05-27 16:42:36 -0700826absl::StatusOr<MappedType> Importer::ConvertQualType(
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000827 clang::QualType qual_type,
Martin Brænne1a207c52022-04-19 00:05:38 -0700828 std::optional<clang::tidy::lifetimes::ValueLifetimes>& lifetimes,
Lukasz Anforowicz14732b22022-06-02 09:11:08 -0700829 bool nullable) {
Devin Jeanpierree971ed72022-08-09 05:07:04 -0700830 qual_type = GetUnelaboratedType(std::move(qual_type), ctx_);
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000831 std::string type_string = qual_type.getAsString();
832 absl::StatusOr<MappedType> type =
833 ConvertType(qual_type.getTypePtr(), lifetimes, nullable);
834 if (!type.ok()) {
835 absl::Status error = absl::UnimplementedError(absl::Substitute(
836 "Unsupported type '$0': $1", type_string, type.status().message()));
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000837 error.SetPayload(kTypeStatusPayloadUrl, absl::Cord(type_string));
838 return error;
839 }
840
Lukasz Anforowicz0c3f8b22022-02-15 14:56:40 +0000841 // Handle cv-qualification.
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000842 type->cc_type.is_const = qual_type.isConstQualified();
Lukasz Anforowicz0c3f8b22022-02-15 14:56:40 +0000843 if (qual_type.isVolatileQualified()) {
844 return absl::UnimplementedError(
845 absl::StrCat("Unsupported `volatile` qualifier: ", type_string));
846 }
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000847
Lukasz Anforowicze9333582022-03-07 15:27:06 +0000848 return type;
Marcel Hlopko7d739792021-08-12 07:52:47 +0000849}
850
Michael Forster500b4762022-01-27 12:30:17 +0000851std::string Importer::GetMangledName(const clang::NamedDecl* named_decl) const {
Lukasz Anforowicz3f133972022-09-01 09:01:02 -0700852 if (auto record_decl = clang::dyn_cast<clang::RecordDecl>(named_decl)) {
853 // Mangled record names are used to 1) provide valid Rust identifiers for
854 // C++ template specializations, and 2) help build unique names for virtual
855 // upcast thunks.
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700856 llvm::SmallString<128> storage;
857 llvm::raw_svector_ostream buffer(storage);
Lukasz Anforowicz3f133972022-09-01 09:01:02 -0700858 mangler_->mangleTypeName(ctx_.getRecordType(record_decl), buffer);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700859
860 // The Itanium mangler does not provide a way to get the mangled
861 // representation of a type. Instead, we call mangleTypeName() that
862 // returns the name of the RTTI typeinfo symbol, and remove the _ZTS
Lukasz Anforowicz3f133972022-09-01 09:01:02 -0700863 // prefix.
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700864 constexpr llvm::StringRef kZtsPrefix = "_ZTS";
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700865 CHECK(buffer.str().take_front(4) == kZtsPrefix);
Lukasz Anforowicz3f133972022-09-01 09:01:02 -0700866 llvm::StringRef mangled_record_name =
867 buffer.str().drop_front(kZtsPrefix.size());
868
869 if (clang::isa<clang::ClassTemplateSpecializationDecl>(named_decl)) {
870 // We prepend __CcTemplateInst to reduce chances of conflict
871 // with regular C and C++ structs.
872 constexpr llvm::StringRef kCcTemplatePrefix = "__CcTemplateInst";
873 return llvm::formatv("{0}{1}", kCcTemplatePrefix, mangled_record_name);
874 }
875 return std::string(mangled_record_name);
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700876 }
877
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000878 clang::GlobalDecl decl;
879
880 // There are only three named decl types that don't work with the GlobalDecl
881 // unary constructor: GPU kernels (which do not exist in standard C++, so we
882 // ignore), constructors, and destructors. GlobalDecl does not support
883 // constructors and destructors from the unary constructor because there is
884 // more than one global declaration for a given constructor or destructor!
885 //
886 // * (Ctor|Dtor)_Complete is a function which constructs / destroys the
887 // entire object. This is what we want. :)
888 // * Dtor_Deleting is a function which additionally calls operator delete.
889 // * (Ctor|Dtor)_Base is a function which constructs/destroys the object but
890 // NOT including virtual base class subobjects.
891 // * (Ctor|Dtor)_Comdat: I *believe* this is the identifier used to
892 // deduplicate inline functions, and is not callable.
893 // * Dtor_(Copying|Default)Closure: These only exist in the MSVC++ ABI,
894 // which we don't support for now. I don't know when they are used.
895 //
896 // It was hard to piece this together, so writing it down here to explain why
897 // we magically picked the *_Complete variants.
Michael Forster500b4762022-01-27 12:30:17 +0000898 if (auto dtor = clang::dyn_cast<clang::CXXDestructorDecl>(named_decl)) {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000899 decl = clang::GlobalDecl(dtor, clang::CXXDtorType::Dtor_Complete);
900 } else if (auto ctor =
Michael Forster500b4762022-01-27 12:30:17 +0000901 clang::dyn_cast<clang::CXXConstructorDecl>(named_decl)) {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000902 decl = clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete);
903 } else {
904 decl = clang::GlobalDecl(named_decl);
905 }
906
Marcel Hlopko7d739792021-08-12 07:52:47 +0000907 std::string name;
908 llvm::raw_string_ostream stream(name);
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000909 mangler_->mangleName(decl, stream);
Marcel Hlopko7d739792021-08-12 07:52:47 +0000910 stream.flush();
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +0000911 return name;
Marcel Hlopko7d739792021-08-12 07:52:47 +0000912}
913
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700914std::string Importer::GetNameForSourceOrder(const clang::Decl* decl) const {
915 // Implicit class template specializations and their methods all have the
916 // same source location. In order to provide deterministic order of the
917 // respective items in generated source code, we additionally use the
918 // mangled names when sorting the items.
919 if (auto* class_template_specialization_decl =
920 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(decl)) {
921 return GetMangledName(class_template_specialization_decl);
922 } else if (auto* func_decl = clang::dyn_cast<clang::FunctionDecl>(decl)) {
923 return GetMangledName(func_decl);
Michael VanBemmel7a4d4c02022-07-27 13:21:47 -0700924 } else if (auto* friend_decl = clang::dyn_cast<clang::FriendDecl>(decl)) {
925 if (auto* named_decl = friend_decl->getFriendDecl()) {
926 if (auto function_template_decl =
927 clang::dyn_cast<clang::FunctionTemplateDecl>(named_decl)) {
928 // Reach through the function template declaration for a function that
929 // can be mangled.
930 named_decl = function_template_decl->getTemplatedDecl();
931 }
932 return GetMangledName(named_decl);
933 } else {
934 // This FriendDecl names a type. We don't import those, so we don't have
935 // to assign a name.
936 return "";
937 }
Rosica Dejanovska2708a5f2022-06-22 06:54:59 -0700938 } else {
939 return "";
940 }
941}
942
Michael Forster500b4762022-01-27 12:30:17 +0000943std::optional<UnqualifiedIdentifier> Importer::GetTranslatedName(
Marcel Hlopko7d739792021-08-12 07:52:47 +0000944 const clang::NamedDecl* named_decl) const {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000945 switch (named_decl->getDeclName().getNameKind()) {
946 case clang::DeclarationName::Identifier: {
947 auto name = std::string(named_decl->getName());
Lukasz Anforowiczab03e562022-05-16 11:18:02 -0700948 if (const clang::ParmVarDecl* param_decl =
949 clang::dyn_cast<clang::ParmVarDecl>(named_decl)) {
950 int param_pos = param_decl->getFunctionScopeIndex();
951 if (name.empty()) {
Lukasz Anforowicz0c816f12021-12-15 17:41:49 +0000952 return {Identifier(absl::StrCat("__param_", param_pos))};
953 }
Lukasz Anforowiczab03e562022-05-16 11:18:02 -0700954 if (auto* sttpt = param_decl->getType()
955 ->getAs<clang::SubstTemplateTypeParmType>();
956 sttpt && sttpt->getReplacedParameter()->isParameterPack()) {
957 // Avoid giving the same name to all parameters expanded from a pack.
958 return {Identifier(absl::StrCat("__", name, "_", param_pos))};
959 }
960 }
961 if (name.empty()) {
Kinuko Yasuda8dd84642022-08-17 09:19:47 -0700962 auto anon_decl_name = anon_decl_names_.find(named_decl);
963 if (anon_decl_name != anon_decl_names_.end()) {
964 return {Identifier(std::string(anon_decl_name->second))};
965 }
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000966 return std::nullopt;
967 }
968 return {Identifier(std::move(name))};
969 }
970 case clang::DeclarationName::CXXConstructorName:
971 return {SpecialName::kConstructor};
972 case clang::DeclarationName::CXXDestructorName:
973 return {SpecialName::kDestructor};
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +0000974 case clang::DeclarationName::CXXOperatorName:
975 switch (named_decl->getDeclName().getCXXOverloadedOperator()) {
976 case clang::OO_None:
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700977 LOG(FATAL) << "No OO_None expected under CXXOperatorName branch";
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +0000978 return std::nullopt;
979 case clang::NUM_OVERLOADED_OPERATORS:
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700980 LOG(FATAL) << "No NUM_OVERLOADED_OPERATORS expected at runtime";
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +0000981 return std::nullopt;
982 // clang-format off
983 #define OVERLOADED_OPERATOR(name, spelling, ...) \
984 case clang::OO_##name: { \
Lukasz Anforowicz9c663ca2022-02-09 01:33:31 +0000985 return {Operator(spelling)}; \
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +0000986 }
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -0700987 #include "clang/Basic/OperatorKinds.def"
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +0000988 #undef OVERLOADED_OPERATOR
989 // clang-format on
990 }
Lukasz Anforowicz2c34cae2022-08-26 07:19:20 -0700991 LOG(FATAL) << "The `switch` above should handle all cases";
Lukasz Anforowicz34ad7f72022-03-17 16:05:28 +0000992 return std::nullopt;
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000993 default:
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +0000994 // To be implemented later: CXXConversionFunctionName.
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000995 // There are also e.g. literal operators, deduction guides, etc., but
996 // we might not need to implement them at all. Full list at:
997 // https://clang.llvm.org/doxygen/classclang_1_1DeclarationName.html#a9ab322d434446b43379d39e41af5cbe3
998 return std::nullopt;
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000999 }
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +00001000}
1001
Lukasz Anforowicz0233f982022-05-27 16:38:20 -07001002void Importer::MarkAsSuccessfullyImported(const clang::TypeDecl* decl) {
Lukasz Anforowicz23fdfad2022-05-27 16:43:43 -07001003 known_type_decls_.insert(
1004 clang::cast<clang::TypeDecl>(decl->getCanonicalDecl()));
Lukasz Anforowicz0233f982022-05-27 16:38:20 -07001005}
1006
Lukasz Anforowicz5258f762022-05-27 16:14:46 -07001007bool Importer::HasBeenAlreadySuccessfullyImported(
1008 const clang::TypeDecl* decl) const {
Lukasz Anforowicz23fdfad2022-05-27 16:43:43 -07001009 return known_type_decls_.contains(
1010 clang::cast<clang::TypeDecl>(decl->getCanonicalDecl()));
Lukasz Anforowicz5258f762022-05-27 16:14:46 -07001011}
1012
Marcel Hlopkof15e8ce2022-04-08 08:46:09 -07001013} // namespace crubit