Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 1 | // 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 Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 5 | #include "rs_bindings_from_cc/importer.h" |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 6 | |
Marcel Hlopko | 9c150da | 2021-11-12 10:30:03 +0000 | [diff] [blame] | 7 | #include <stdint.h> |
| 8 | |
Googler | 4e1bc13 | 2021-12-06 10:10:42 +0000 | [diff] [blame] | 9 | #include <algorithm> |
Martin Brænne | 83bda99 | 2023-07-10 12:03:12 -0700 | [diff] [blame] | 10 | #include <cassert> |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 11 | #include <cstddef> |
Devin Jeanpierre | 257f0f6 | 2023-05-08 11:52:01 -0700 | [diff] [blame] | 12 | #include <iterator> |
| 13 | #include <map> |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 14 | #include <memory> |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 15 | #include <optional> |
Devin Jeanpierre | 257f0f6 | 2023-05-08 11:52:01 -0700 | [diff] [blame] | 16 | #include <set> |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 17 | #include <string> |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 18 | #include <tuple> |
Marcel Hlopko | 20f4ce4 | 2021-11-02 08:20:00 +0000 | [diff] [blame] | 19 | #include <utility> |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 20 | #include <variant> |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 21 | #include <vector> |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 22 | |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 23 | #include "absl/container/flat_hash_map.h" |
| 24 | #include "absl/container/flat_hash_set.h" |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 25 | #include "absl/log/check.h" |
| 26 | #include "absl/log/log.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 27 | #include "absl/status/status.h" |
| 28 | #include "absl/status/statusor.h" |
| 29 | #include "absl/strings/cord.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 30 | #include "absl/strings/str_cat.h" |
Googler | 442733c | 2023-01-23 01:05:35 -0800 | [diff] [blame] | 31 | #include "absl/strings/str_format.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 32 | #include "absl/strings/str_join.h" |
| 33 | #include "absl/strings/string_view.h" |
| 34 | #include "absl/strings/substitute.h" |
Marco Poletti | c61bcc4 | 2022-04-08 12:54:30 -0700 | [diff] [blame] | 35 | #include "common/status_macros.h" |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 36 | #include "lifetime_annotations/type_lifetimes.h" |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 37 | #include "rs_bindings_from_cc/ast_util.h" |
Marcel Hlopko | 3b254b3 | 2022-03-09 14:10:49 +0000 | [diff] [blame] | 38 | #include "rs_bindings_from_cc/bazel_types.h" |
| 39 | #include "rs_bindings_from_cc/ir.h" |
Devin Jeanpierre | 12b7b57 | 2023-05-03 15:40:55 -0700 | [diff] [blame] | 40 | #include "rs_bindings_from_cc/type_map.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 41 | #include "clang/AST/ASTContext.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 42 | #include "clang/AST/Decl.h" |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 43 | #include "clang/AST/DeclBase.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 44 | #include "clang/AST/DeclCXX.h" |
Michael VanBemmel | 7a4d4c0 | 2022-07-27 13:21:47 -0700 | [diff] [blame] | 45 | #include "clang/AST/DeclFriend.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 46 | #include "clang/AST/Mangle.h" |
| 47 | #include "clang/AST/RawCommentList.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 48 | #include "clang/AST/Type.h" |
| 49 | #include "clang/Basic/FileManager.h" |
Rosica Dejanovska | 93aeafb | 2022-06-01 07:05:31 -0700 | [diff] [blame] | 50 | #include "clang/Basic/LLVM.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 51 | #include "clang/Basic/OperatorKinds.h" |
| 52 | #include "clang/Basic/SourceLocation.h" |
| 53 | #include "clang/Basic/SourceManager.h" |
| 54 | #include "clang/Basic/Specifiers.h" |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 55 | #include "clang/Sema/Sema.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 56 | #include "llvm/ADT/STLExtras.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 57 | #include "llvm/Support/Casting.h" |
Devin Jeanpierre | 1bcd726 | 2022-10-04 20:07:59 -0700 | [diff] [blame] | 58 | #include "llvm/Support/FormatVariadic.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 59 | #include "llvm/Support/Regex.h" |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 60 | |
Marcel Hlopko | f15e8ce | 2022-04-08 08:46:09 -0700 | [diff] [blame] | 61 | namespace crubit { |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 62 | namespace { |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 63 | |
Michael Forster | b836c58 | 2022-01-21 11:20:22 +0000 | [diff] [blame] | 64 | constexpr absl::string_view kTypeStatusPayloadUrl = |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 65 | "type.googleapis.com/devtools.rust.cc_interop.rs_binding_from_cc.type"; |
| 66 | |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 67 | // Checks if the return value from `GetDeclItem` indicates that the import was |
| 68 | // successful. |
| 69 | absl::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 Jeanpierre | e971ed7 | 2022-08-09 05:07:04 -0700 | [diff] [blame] | 78 | } // namespace |
Michael Forster | 64217b4 | 2022-04-22 05:48:54 -0700 | [diff] [blame] | 79 | |
Michael Forster | 64217b4 | 2022-04-22 05:48:54 -0700 | [diff] [blame] | 80 | namespace { |
| 81 | |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 82 | // 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 |
| 90 | absl::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 Hlopko | f80bf51 | 2022-05-12 01:20:33 -0700 | [diff] [blame] | 147 | // TODO(hlopko): Uncomment once we integrate the upstream change that |
| 148 | // introduced it: |
| 149 | // case clang::CC_AArch64SVEPCS: __attribute__((aarch64_sve_pcs)) |
| 150 | |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 151 | // These don't seem to have any Rust equivalents. |
| 152 | break; |
Marcel Hlopko | f80bf51 | 2022-05-12 01:20:33 -0700 | [diff] [blame] | 153 | default: |
Googler | 75c7ad0 | 2022-05-23 13:27:49 -0700 | [diff] [blame] | 154 | break; |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 155 | } |
| 156 | return absl::UnimplementedError( |
| 157 | absl::StrCat("Unsupported calling convention: ", |
| 158 | absl::string_view( |
| 159 | clang::FunctionType::getNameForCallConv(cc_call_conv)))); |
| 160 | } |
| 161 | |
Devin Jeanpierre | 5677702 | 2022-02-03 01:57:15 +0000 | [diff] [blame] | 162 | } // namespace |
| 163 | |
Lukasz Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 164 | // 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.). |
| 170 | static 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 Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 195 | class Importer::SourceOrderKey { |
| 196 | public: |
Devin Jeanpierre | 257f0f6 | 2023-05-08 11:52:01 -0700 | [diff] [blame] | 197 | explicit SourceOrderKey(clang::SourceRange source_range, int decl_order = 0, |
| 198 | std::string name = "") |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 199 | : 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 | |
| 234 | Importer::SourceOrderKey Importer::GetSourceOrderKey( |
| 235 | const clang::Decl* decl) const { |
| 236 | return SourceOrderKey(decl->getSourceRange(), GetDeclOrder(decl), |
| 237 | GetNameForSourceOrder(decl)); |
| 238 | } |
| 239 | |
| 240 | Importer::SourceOrderKey Importer::GetSourceOrderKey( |
| 241 | const clang::RawComment* comment) const { |
| 242 | return SourceOrderKey(comment->getSourceRange()); |
| 243 | } |
| 244 | |
| 245 | class Importer::SourceLocationComparator { |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 246 | public: |
Devin Jeanpierre | 0d8e34b | 2023-05-08 11:43:44 -0700 | [diff] [blame] | 247 | bool operator()(const clang::SourceLocation& a, |
| 248 | const clang::SourceLocation& b) const { |
Devin Jeanpierre | 8f8049c | 2023-05-08 11:53:16 -0700 | [diff] [blame] | 249 | return b.isValid() && a.isValid() && sm_.isBeforeInTranslationUnit(a, b); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 250 | } |
Devin Jeanpierre | 0d8e34b | 2023-05-08 11:43:44 -0700 | [diff] [blame] | 251 | bool operator()(const clang::RawComment* a, |
| 252 | const clang::SourceLocation& b) const { |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 253 | return this->operator()(a->getBeginLoc(), b); |
| 254 | } |
Devin Jeanpierre | 0d8e34b | 2023-05-08 11:43:44 -0700 | [diff] [blame] | 255 | bool operator()(const clang::SourceLocation& a, |
| 256 | const clang::RawComment* b) const { |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 257 | return this->operator()(a, b->getBeginLoc()); |
| 258 | } |
Devin Jeanpierre | 0d8e34b | 2023-05-08 11:43:44 -0700 | [diff] [blame] | 259 | bool operator()(const clang::RawComment* a, |
| 260 | const clang::RawComment* b) const { |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 261 | return this->operator()(a->getBeginLoc(), b->getBeginLoc()); |
| 262 | } |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 263 | |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 264 | using OrderedItemId = std::pair<SourceOrderKey, ItemId>; |
| 265 | using OrderedItem = std::pair<SourceOrderKey, IR::Item>; |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 266 | |
| 267 | template <typename OrderedItemOrId> |
| 268 | bool operator()(const OrderedItemOrId& a, const OrderedItemOrId& b) const { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 269 | auto a_source_order = a.first; |
| 270 | auto b_source_order = b.first; |
Devin Jeanpierre | 8f8049c | 2023-05-08 11:53:16 -0700 | [diff] [blame] | 271 | return a_source_order.isBefore(b_source_order, sm_); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 272 | } |
Devin Jeanpierre | 8f8049c | 2023-05-08 11:53:16 -0700 | [diff] [blame] | 273 | explicit SourceLocationComparator(const clang::SourceManager& sm) : sm_(sm) {} |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 274 | |
| 275 | private: |
Devin Jeanpierre | 8f8049c | 2023-05-08 11:53:16 -0700 | [diff] [blame] | 276 | const clang::SourceManager& sm_; |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 277 | }; |
| 278 | |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 279 | static 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 Anforowicz | 38310f3 | 2022-09-09 11:17:52 -0700 | [diff] [blame] | 290 | // `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 Anforowicz | 02ce0f7 | 2022-09-02 12:10:26 -0700 | [diff] [blame] | 298 | // 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 Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 304 | } |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 305 | } |
| 306 | |
| 307 | return result; |
| 308 | } |
| 309 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 310 | std::vector<ItemId> Importer::GetItemIdsInSourceOrder( |
| 311 | clang::Decl* parent_decl) { |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 312 | 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 Hlopko | d4678de | 2022-05-25 01:38:13 -0700 | [diff] [blame] | 331 | |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 332 | auto* decl_context = clang::cast<clang::DeclContext>(parent_decl); |
| 333 | for (auto decl : GetCanonicalChildren(decl_context)) { |
Rosica Dejanovska | 001852d | 2022-06-07 14:19:41 -0700 | [diff] [blame] | 334 | 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 Jeanpierre | 1bcd726 | 2022-10-04 20:07:59 -0700 | [diff] [blame] | 338 | if (decl_context->isTranslationUnit() && !IsFromCurrentTarget(decl)) { |
Rosica Dejanovska | 001852d | 2022-06-07 14:19:41 -0700 | [diff] [blame] | 339 | continue; |
Devin Jeanpierre | 1bcd726 | 2022-10-04 20:07:59 -0700 | [diff] [blame] | 340 | } |
Rosica Dejanovska | 001852d | 2022-06-07 14:19:41 -0700 | [diff] [blame] | 341 | // 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 Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 348 | items.push_back({GetSourceOrderKey(decl), item_id}); |
Rosica Dejanovska | 001852d | 2022-06-07 14:19:41 -0700 | [diff] [blame] | 349 | } |
| 350 | } |
| 351 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 352 | // 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 Anforowicz | 49b5bbc | 2022-02-04 23:40:10 +0000 | [diff] [blame] | 356 | } |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 357 | ordered_comments.erase(ordered_comments.lower_bound(decl->getBeginLoc()), |
| 358 | ordered_comments.upper_bound(decl->getEndLoc())); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 359 | } |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 360 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 361 | for (auto& [_, comment] : ordered_comments) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 362 | items.push_back({GetSourceOrderKey(comment), GenerateItemId(comment)}); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 363 | } |
Dmitri Gribenko | 620bc91 | 2022-04-22 03:38:04 -0700 | [diff] [blame] | 364 | llvm::sort(items, compare_locations); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 365 | |
| 366 | std::vector<ItemId> ordered_item_ids; |
| 367 | ordered_item_ids.reserve(items.size()); |
| 368 | for (auto& ordered_item : items) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 369 | ordered_item_ids.push_back(ordered_item.second); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 370 | } |
| 371 | return ordered_item_ids; |
| 372 | } |
| 373 | |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 374 | std::vector<ItemId> Importer::GetOrderedItemIdsOfTemplateInstantiations() |
| 375 | const { |
| 376 | std::vector<SourceLocationComparator::OrderedItemId> items; |
Lukasz Anforowicz | c72a9d8 | 2022-09-22 16:25:32 -0700 | [diff] [blame] | 377 | items.reserve(class_template_instantiations_.size()); |
| 378 | for (const auto* decl : class_template_instantiations_) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 379 | items.push_back({GetSourceOrderKey(decl), GenerateItemId(decl)}); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 380 | } |
| 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 Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 389 | ordered_item_ids.push_back(ordered_item.second); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 390 | } |
| 391 | return ordered_item_ids; |
| 392 | } |
| 393 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 394 | void Importer::ImportFreeComments() { |
| 395 | clang::SourceManager& sm = ctx_.getSourceManager(); |
Lukasz Anforowicz | 121338a | 2022-11-01 14:28:32 -0700 | [diff] [blame] | 396 | for (const auto& header : invocation_.public_headers_) { |
Googler | fbc9765 | 2023-10-05 16:49:32 -0700 | [diff] [blame] | 397 | if (auto file = sm.getFileManager().getFileRef(header.IncludePath())) { |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 398 | 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 Gribenko | 620bc91 | 2022-04-22 03:38:04 -0700 | [diff] [blame] | 406 | llvm::sort(comments_, SourceLocationComparator(sm)); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 407 | } |
| 408 | |
| 409 | void Importer::Import(clang::TranslationUnitDecl* translation_unit_decl) { |
| 410 | ImportFreeComments(); |
| 411 | clang::SourceManager& sm = ctx_.getSourceManager(); |
| 412 | std::vector<SourceLocationComparator::OrderedItem> ordered_items; |
| 413 | |
Devin Jeanpierre | 0d8e34b | 2023-05-08 11:43:44 -0700 | [diff] [blame] | 414 | ordered_items.reserve(comments_.size()); |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 415 | for (auto& comment : comments_) { |
| 416 | ordered_items.push_back( |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 417 | {GetSourceOrderKey(comment), |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 418 | Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics()), |
| 419 | .id = GenerateItemId(comment)}}); |
| 420 | } |
| 421 | |
| 422 | ImportDeclsFromDeclContext(translation_unit_decl); |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 423 | 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 Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 429 | ordered_items.push_back({GetSourceOrderKey(decl), *item}); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 430 | } |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 431 | } |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 432 | |
Dmitri Gribenko | 620bc91 | 2022-04-22 03:38:04 -0700 | [diff] [blame] | 433 | llvm::sort(ordered_items, SourceLocationComparator(sm)); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 434 | |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 435 | invocation_.ir_.items.reserve(ordered_items.size()); |
| 436 | for (auto& ordered_item : ordered_items) { |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 437 | invocation_.ir_.items.push_back(ordered_item.second); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 438 | } |
Rosica Dejanovska | b2bd59e | 2022-04-11 09:02:03 -0700 | [diff] [blame] | 439 | invocation_.ir_.top_level_item_ids = |
| 440 | GetItemIdsInSourceOrder(translation_unit_decl); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 441 | |
Lukasz Anforowicz | a6f9625 | 2022-11-03 13:49:08 -0700 | [diff] [blame] | 442 | // TODO(b/257302656): Consider placing the generated template instantiations |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 443 | // into a separate namespace (maybe `crubit::instantiated_templates` ?). |
| 444 | llvm::copy(GetOrderedItemIdsOfTemplateInstantiations(), |
| 445 | std::back_inserter(invocation_.ir_.top_level_item_ids)); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 446 | } |
| 447 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 448 | void Importer::ImportDeclsFromDeclContext( |
| 449 | const clang::DeclContext* decl_context) { |
Lukasz Anforowicz | d1e7cdf | 2022-09-02 11:09:33 -0700 | [diff] [blame] | 450 | for (auto decl : GetCanonicalChildren(decl_context)) { |
| 451 | GetDeclItem(decl); |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 452 | } |
| 453 | } |
| 454 | |
Michael Forster | 1b50637 | 2022-04-12 11:31:54 -0700 | [diff] [blame] | 455 | std::optional<IR::Item> Importer::GetDeclItem(clang::Decl* decl) { |
Devin Jeanpierre | 257f0f6 | 2023-05-08 11:52:01 -0700 | [diff] [blame] | 456 | // TODO(jeanpierreda): Move `decl->getCanonicalDecl()` from callers into here. |
Devin Jeanpierre | 1bcd726 | 2022-10-04 20:07:59 -0700 | [diff] [blame] | 457 | if (auto it = import_cache_.find(decl); it != import_cache_.end()) { |
| 458 | return it->second; |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 459 | } |
Devin Jeanpierre | 1bcd726 | 2022-10-04 20:07:59 -0700 | [diff] [blame] | 460 | // 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 Jeanpierre | 61804f7 | 2022-10-04 20:26:13 -0700 | [diff] [blame] | 520 | 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 Jeanpierre | 1bcd726 | 2022-10-04 20:07:59 -0700 | [diff] [blame] | 526 | return result; |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 527 | } |
| 528 | |
Devin Jeanpierre | 4223859 | 2022-10-04 20:27:44 -0700 | [diff] [blame] | 529 | /// Returns true if a decl is inside a private section, or is inside a |
| 530 | /// RecordDecl which is IsTransitivelyInPrivate. |
| 531 | bool 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 Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 555 | std::optional<IR::Item> Importer::ImportDecl(clang::Decl* decl) { |
Devin Jeanpierre | 4223859 | 2022-10-04 20:27:44 -0700 | [diff] [blame] | 556 | if (IsTransitivelyInPrivate(decl)) return std::nullopt; |
Michael Forster | 64217b4 | 2022-04-22 05:48:54 -0700 | [diff] [blame] | 557 | for (auto& importer : decl_importers_) { |
Devin Jeanpierre | c2c39ff | 2023-05-08 11:42:21 -0700 | [diff] [blame] | 558 | std::optional<IR::Item> result = importer->ImportDecl(decl); |
| 559 | if (result.has_value()) { |
| 560 | return result; |
Michael Forster | 64217b4 | 2022-04-22 05:48:54 -0700 | [diff] [blame] | 561 | } |
| 562 | } |
Devin Jeanpierre | c2c39ff | 2023-05-08 11:42:21 -0700 | [diff] [blame] | 563 | return std::nullopt; |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 564 | } |
| 565 | |
Kinuko Yasuda | 6ff59f1 | 2022-08-11 08:41:45 -0700 | [diff] [blame] | 566 | std::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 | |
Googler | 6c3de12 | 2022-03-28 11:40:41 +0000 | [diff] [blame] | 574 | BazelLabel Importer::GetOwningTarget(const clang::Decl* decl) const { |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 575 | // 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 Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 581 | clang::SourceManager& source_manager = ctx_.getSourceManager(); |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 582 | auto source_location = decl->getLocation(); |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 583 | |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 584 | // 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 Dejanovska | 381d103 | 2022-02-03 22:19:54 +0000 | [diff] [blame] | 588 | while (source_location.isValid()) { |
Rosica Dejanovska | 503d7dd | 2022-02-01 20:37:49 +0000 | [diff] [blame] | 589 | if (source_location.isMacroID()) { |
| 590 | source_location = source_manager.getExpansionLoc(source_location); |
| 591 | } |
| 592 | auto id = source_manager.getFileID(source_location); |
Googler | 261c531 | 2023-03-01 08:50:58 -0800 | [diff] [blame] | 593 | std::optional<llvm::StringRef> filename = |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 594 | source_manager.getNonBuiltinFilenameForID(id); |
| 595 | if (!filename) { |
Marcel Hlopko | 457bdef | 2022-05-18 06:01:49 -0700 | [diff] [blame] | 596 | return BazelLabel("//:_nothing_should_depend_on_private_builtin_hdrs"); |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 597 | } |
| 598 | if (filename->startswith("./")) { |
| 599 | filename = filename->substr(2); |
| 600 | } |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 601 | |
| 602 | if (auto target = invocation_.header_target(HeaderName(filename->str()))) { |
| 603 | return *target; |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 604 | } |
| 605 | source_location = source_manager.getIncludeLoc(id); |
Marcel Hlopko | 4c660dd | 2021-12-02 09:52:47 +0000 | [diff] [blame] | 606 | } |
Rosica Dejanovska | d0fc294 | 2022-01-21 11:26:00 +0000 | [diff] [blame] | 607 | |
Googler | 6c3de12 | 2022-03-28 11:40:41 +0000 | [diff] [blame] | 608 | return BazelLabel("//:virtual_clang_resource_dir_target"); |
Marcel Hlopko | 80441c1 | 2021-11-12 10:43:18 +0000 | [diff] [blame] | 609 | } |
| 610 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 611 | bool Importer::IsFromCurrentTarget(const clang::Decl* decl) const { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 612 | return invocation_.target_ == GetOwningTarget(decl); |
Marcel Hlopko | 4c660dd | 2021-12-02 09:52:47 +0000 | [diff] [blame] | 613 | } |
| 614 | |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 615 | IR::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 | } |
Googler | 442733c | 2023-01-23 01:05:35 -0800 | [diff] [blame] | 621 | std::string source_loc = ConvertSourceLocation(decl->getBeginLoc()); |
Rosica Dejanovska | d638cf5 | 2022-03-23 15:45:01 +0000 | [diff] [blame] | 622 | return UnsupportedItem{.name = name, |
| 623 | .message = error, |
| 624 | .source_loc = source_loc, |
| 625 | .id = GenerateItemId(decl)}; |
Lukasz Anforowicz | 06f76b1 | 2022-03-23 13:48:39 +0000 | [diff] [blame] | 626 | } |
| 627 | |
| 628 | IR::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 Anforowicz | c4ceb4f | 2022-01-28 19:29:19 +0000 | [diff] [blame] | 633 | static 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 | |
Googler | a6c60bb | 2022-12-20 07:32:17 -0800 | [diff] [blame] | 643 | std::optional<std::string> Importer::GetComment(const clang::Decl* decl) const { |
Michael Forster | 409d941 | 2021-10-07 08:35:29 +0000 | [diff] [blame] | 644 | // 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 Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 648 | clang::SourceManager& sm = ctx_.getSourceManager(); |
| 649 | clang::RawComment* raw_comment = ctx_.getRawCommentForDeclNoCache(decl); |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 650 | |
| 651 | if (raw_comment == nullptr) { |
| 652 | return {}; |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 653 | } |
Lukasz Anforowicz | c4ceb4f | 2022-01-28 19:29:19 +0000 | [diff] [blame] | 654 | |
| 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 Anforowicz | 3b4be12 | 2022-03-16 00:09:35 +0000 | [diff] [blame] | 659 | if (cleaned_comment_text.empty()) return {}; |
| 660 | return cleaned_comment_text; |
Michael Forster | cc5941a | 2021-10-07 07:12:24 +0000 | [diff] [blame] | 661 | } |
| 662 | |
Googler | 442733c | 2023-01-23 01:05:35 -0800 | [diff] [blame] | 663 | std::string Importer::ConvertSourceLocation(clang::SourceLocation loc) const { |
Michael Forster | a49d2e6 | 2022-01-28 07:26:40 +0000 | [diff] [blame] | 664 | auto& sm = ctx_.getSourceManager(); |
Googler | 3191037 | 2023-01-25 12:47:16 -0800 | [diff] [blame] | 665 | // 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. |
Googler | ba8c50c | 2023-01-25 13:07:31 -0800 | [diff] [blame] | 673 | 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 | }; |
Googler | 3191037 | 2023-01-25 12:47:16 -0800 | [diff] [blame] | 679 | 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; |
Googler | 442733c | 2023-01-23 01:05:35 -0800 | [diff] [blame] | 684 | } else { |
Googler | 3191037 | 2023-01-25 12:47:16 -0800 | [diff] [blame] | 685 | uint32_t spelling_line = sm.getSpellingLineNumber(loc); |
| 686 | if (absl::StartsWith(spelling_filename, "./")) { |
| 687 | spelling_filename = spelling_filename.substr(2); |
| 688 | } |
Googler | ba8c50c | 2023-01-25 13:07:31 -0800 | [diff] [blame] | 689 | spelling_loc_str = |
| 690 | kSourceLocationFunc(kGeneratedFrom, spelling_filename, spelling_line); |
Googler | 442733c | 2023-01-23 01:05:35 -0800 | [diff] [blame] | 691 | } |
Googler | 3191037 | 2023-01-25 12:47:16 -0800 | [diff] [blame] | 692 | 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 | } |
Googler | ba8c50c | 2023-01-25 13:07:31 -0800 | [diff] [blame] | 705 | expansion_loc_str = |
| 706 | kSourceLocationFunc(kExpandedAt, expansion_filename, expansion_line); |
Googler | 3191037 | 2023-01-25 12:47:16 -0800 | [diff] [blame] | 707 | } |
Googler | ba8c50c | 2023-01-25 13:07:31 -0800 | [diff] [blame] | 708 | return absl::StrCat(spelling_loc_str, "\n", expansion_loc_str); |
Michael Forster | d3ef1e9 | 2021-10-12 16:15:31 +0000 | [diff] [blame] | 709 | } |
| 710 | |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 711 | absl::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 Anforowicz | 3a2026b | 2022-06-09 09:08:42 -0700 | [diff] [blame] | 726 | if (HasBeenAlreadySuccessfullyImported(specialization_decl)) |
| 727 | return ConvertTypeDecl(specialization_decl); |
| 728 | |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 729 | // `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 Anforowicz | 38310f3 | 2022-09-09 11:17:52 -0700 | [diff] [blame] | 733 | (void)sema_.isCompleteType(specialization_decl->getLocation(), |
| 734 | ctx_.getRecordType(specialization_decl)); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 735 | |
| 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 Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 747 | return ConvertTypeDecl(specialization_decl); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 748 | } |
| 749 | |
Devin Jeanpierre | 3c4354b | 2023-05-26 16:01:49 -0700 | [diff] [blame] | 750 | absl::StatusOr<MappedType> Importer::ConvertTypeDecl(clang::NamedDecl* decl) { |
Devin Jeanpierre | 61804f7 | 2022-10-04 20:26:13 -0700 | [diff] [blame] | 751 | if (!EnsureSuccessfullyImported(decl)) { |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 752 | return absl::NotFoundError(absl::Substitute( |
| 753 | "No generated bindings found for '$0'", decl->getNameAsString())); |
| 754 | } |
| 755 | |
Rosica Dejanovska | d638cf5 | 2022-03-23 15:45:01 +0000 | [diff] [blame] | 756 | ItemId decl_id = GenerateItemId(decl); |
Lukasz Anforowicz | 58f2711 | 2022-03-15 17:51:03 +0000 | [diff] [blame] | 757 | return MappedType::WithDeclId(decl_id); |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 758 | } |
| 759 | |
Martin Brænne | 83bda99 | 2023-07-10 12:03:12 -0700 | [diff] [blame] | 760 | static 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 Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 775 | absl::StatusOr<MappedType> Importer::ConvertType( |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 776 | const clang::Type* type, |
Martin Brænne | 390ffa2 | 2023-07-10 12:26:53 -0700 | [diff] [blame] | 777 | const clang::tidy::lifetimes::ValueLifetimes* lifetimes, |
Googler | 1bff637 | 2023-03-24 10:06:29 -0700 | [diff] [blame] | 778 | std::optional<clang::RefQualifierKind> ref_qualifier_kind, bool nullable) { |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 779 | // Qualifiers are handled separately in ConvertQualType(). |
| 780 | std::string type_string = clang::QualType(type, 0).getAsString(); |
Michael Forster | dc683af | 2021-09-17 08:51:28 +0000 | [diff] [blame] | 781 | |
Martin Brænne | 390ffa2 | 2023-07-10 12:26:53 -0700 | [diff] [blame] | 782 | assert(!lifetimes || IsSameCanonicalUnqualifiedType( |
| 783 | lifetimes->Type(), clang::QualType(type, 0))); |
Martin Brænne | 83bda99 | 2023-07-10 12:03:12 -0700 | [diff] [blame] | 784 | |
Devin Jeanpierre | b7f8e28 | 2023-05-26 16:03:12 -0700 | [diff] [blame] | 785 | if (auto override_type = GetTypeMapOverride(*type); |
| 786 | override_type.has_value()) { |
Devin Jeanpierre | 12b7b57 | 2023-05-03 15:40:55 -0700 | [diff] [blame] | 787 | return *std::move(override_type); |
Devin Jeanpierre | deea789 | 2022-03-29 02:13:31 -0700 | [diff] [blame] | 788 | } else if (type->isPointerType() || type->isLValueReferenceType() || |
| 789 | type->isRValueReferenceType()) { |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 790 | clang::QualType pointee_type = type->getPointeeType(); |
Lukasz Anforowicz | 92c81c3 | 2022-03-04 19:03:56 +0000 | [diff] [blame] | 791 | std::optional<LifetimeId> lifetime; |
Martin Brænne | 390ffa2 | 2023-07-10 12:26:53 -0700 | [diff] [blame] | 792 | const clang::tidy::lifetimes::ValueLifetimes* pointee_lifetimes = nullptr; |
| 793 | if (lifetimes) { |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 794 | lifetime = |
| 795 | LifetimeId(lifetimes->GetPointeeLifetimes().GetLifetime().Id()); |
Martin Brænne | 390ffa2 | 2023-07-10 12:26:53 -0700 | [diff] [blame] | 796 | pointee_lifetimes = &lifetimes->GetPointeeLifetimes().GetValueLifetimes(); |
Lukasz Anforowicz | 92c81c3 | 2022-03-04 19:03:56 +0000 | [diff] [blame] | 797 | } |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 798 | if (const auto* func_type = |
Lukasz Anforowicz | 92c81c3 | 2022-03-04 19:03:56 +0000 | [diff] [blame] | 799 | pointee_type->getAs<clang::FunctionProtoType>()) { |
Lukasz Anforowicz | 5087e1f | 2023-04-03 08:41:29 -0700 | [diff] [blame] | 800 | // 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 Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 805 | |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 806 | clang::StringRef cc_call_conv = |
| 807 | clang::FunctionType::getNameForCallConv(func_type->getCallConv()); |
Lukasz Anforowicz | d41a4e9 | 2022-03-17 17:08:57 +0000 | [diff] [blame] | 808 | CRUBIT_ASSIGN_OR_RETURN( |
| 809 | absl::string_view rs_abi, |
| 810 | ConvertCcCallConvIntoRsAbi(func_type->getCallConv())); |
Martin Brænne | 390ffa2 | 2023-07-10 12:26:53 -0700 | [diff] [blame] | 811 | const clang::tidy::lifetimes::ValueLifetimes* return_lifetimes = nullptr; |
| 812 | if (pointee_lifetimes) { |
| 813 | return_lifetimes = |
| 814 | &pointee_lifetimes->GetFuncLifetimes().GetReturnLifetimes(); |
| 815 | } |
Martin Brænne | 83bda99 | 2023-07-10 12:03:12 -0700 | [diff] [blame] | 816 | CRUBIT_ASSIGN_OR_RETURN( |
| 817 | MappedType mapped_return_type, |
| 818 | ConvertQualType(func_type->getReturnType(), return_lifetimes, |
| 819 | ref_qualifier_kind)); |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 820 | |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 821 | std::vector<MappedType> mapped_param_types; |
Martin Brænne | 83bda99 | 2023-07-10 12:03:12 -0700 | [diff] [blame] | 822 | for (unsigned i = 0; i < func_type->getNumParams(); ++i) { |
Martin Brænne | 390ffa2 | 2023-07-10 12:26:53 -0700 | [diff] [blame] | 823 | const clang::tidy::lifetimes::ValueLifetimes* param_lifetimes = nullptr; |
| 824 | if (pointee_lifetimes) { |
| 825 | param_lifetimes = |
| 826 | &pointee_lifetimes->GetFuncLifetimes().GetParamLifetimes(i); |
| 827 | } |
Googler | 1bff637 | 2023-03-24 10:06:29 -0700 | [diff] [blame] | 828 | CRUBIT_ASSIGN_OR_RETURN( |
| 829 | MappedType mapped_param_type, |
Martin Brænne | 83bda99 | 2023-07-10 12:03:12 -0700 | [diff] [blame] | 830 | ConvertQualType(func_type->getParamType(i), param_lifetimes, |
| 831 | ref_qualifier_kind)); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 832 | mapped_param_types.push_back(std::move(mapped_param_type)); |
Lukasz Anforowicz | cf230fd | 2022-02-18 19:20:39 +0000 | [diff] [blame] | 833 | } |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 834 | |
| 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 Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 840 | CHECK(type->isLValueReferenceType()); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 841 | return MappedType::FuncRef(cc_call_conv, rs_abi, lifetime, |
| 842 | std::move(mapped_return_type), |
| 843 | std::move(mapped_param_types)); |
| 844 | } |
| 845 | } |
| 846 | |
Googler | 1bff637 | 2023-03-24 10:06:29 -0700 | [diff] [blame] | 847 | CRUBIT_ASSIGN_OR_RETURN( |
| 848 | MappedType mapped_pointee_type, |
Martin Brænne | 390ffa2 | 2023-07-10 12:26:53 -0700 | [diff] [blame] | 849 | ConvertQualType(pointee_type, pointee_lifetimes, ref_qualifier_kind)); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 850 | if (type->isPointerType()) { |
| 851 | return MappedType::PointerTo(std::move(mapped_pointee_type), lifetime, |
Googler | 1bff637 | 2023-03-24 10:06:29 -0700 | [diff] [blame] | 852 | ref_qualifier_kind, nullable); |
Devin Jeanpierre | deea789 | 2022-03-29 02:13:31 -0700 | [diff] [blame] | 853 | } else if (type->isLValueReferenceType()) { |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 854 | return MappedType::LValueReferenceTo(std::move(mapped_pointee_type), |
| 855 | lifetime); |
Devin Jeanpierre | deea789 | 2022-03-29 02:13:31 -0700 | [diff] [blame] | 856 | } else { |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 857 | CHECK(type->isRValueReferenceType()); |
Devin Jeanpierre | deea789 | 2022-03-29 02:13:31 -0700 | [diff] [blame] | 858 | 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); |
Googler | 61dce3b | 2021-12-02 09:16:32 +0000 | [diff] [blame] | 864 | } |
Googler | b6c0fe0 | 2021-12-01 10:55:31 +0000 | [diff] [blame] | 865 | } else if (const auto* builtin_type = |
Googler | 06f2c9a | 2022-01-05 12:00:47 +0000 | [diff] [blame] | 866 | // Use getAsAdjusted instead of getAs so we don't desugar |
| 867 | // typedefs. |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 868 | type->getAsAdjusted<clang::BuiltinType>()) { |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 869 | switch (builtin_type->getKind()) { |
| 870 | case clang::BuiltinType::Bool: |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 871 | return MappedType::Simple("bool", "bool"); |
Michael Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 872 | case clang::BuiltinType::Void: |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 873 | return MappedType::Void(); |
Lukasz Anforowicz | 460e427 | 2023-05-18 16:11:46 -0700 | [diff] [blame] | 874 | |
| 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 Forster | 51da81a | 2021-09-20 07:14:23 +0000 | [diff] [blame] | 916 | default: |
Lukasz Anforowicz | 4d01461 | 2023-05-18 16:27:36 -0700 | [diff] [blame] | 917 | return absl::UnimplementedError("Unsupported builtin type"); |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 918 | } |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 919 | } else if (const auto* tag_type = type->getAsAdjusted<clang::TagType>()) { |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 920 | return ConvertTypeDecl(tag_type->getDecl()); |
Michael Forster | 365bba1 | 2022-01-24 16:56:06 +0000 | [diff] [blame] | 921 | } else if (const auto* typedef_type = |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 922 | type->getAsAdjusted<clang::TypedefType>()) { |
Lukasz Anforowicz | b6635b0 | 2022-03-08 19:13:53 +0000 | [diff] [blame] | 923 | return ConvertTypeDecl(typedef_type->getDecl()); |
Devin Jeanpierre | 3c4354b | 2023-05-26 16:01:49 -0700 | [diff] [blame] | 924 | } else if (const auto* using_type = type->getAs<clang::UsingType>()) { |
| 925 | return ConvertTypeDecl(using_type->getFoundDecl()); |
Lukasz Anforowicz | 14732b2 | 2022-06-02 09:11:08 -0700 | [diff] [blame] | 926 | } else if (const auto* tst_type = |
| 927 | type->getAs<clang::TemplateSpecializationType>()) { |
| 928 | return ConvertTemplateSpecializationType(tst_type); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 929 | } else if (const auto* subst_type = |
| 930 | type->getAs<clang::SubstTemplateTypeParmType>()) { |
Googler | 1bff637 | 2023-03-24 10:06:29 -0700 | [diff] [blame] | 931 | return ConvertQualType(subst_type->getReplacementType(), lifetimes, |
| 932 | ref_qualifier_kind); |
Lukasz Anforowicz | 8f59068 | 2022-05-17 12:39:20 -0700 | [diff] [blame] | 933 | } 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 Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 936 | CHECK(deduced_type->isDeduced()); |
Googler | 1bff637 | 2023-03-24 10:06:29 -0700 | [diff] [blame] | 937 | return ConvertQualType(deduced_type->getDeducedType(), lifetimes, |
| 938 | ref_qualifier_kind); |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 939 | } |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 940 | |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 941 | return absl::UnimplementedError(absl::StrCat( |
| 942 | "Unsupported clang::Type class '", type->getTypeClassName(), "'")); |
| 943 | } |
| 944 | |
Devin Jeanpierre | e971ed7 | 2022-08-09 05:07:04 -0700 | [diff] [blame] | 945 | // Returns a QualType with leading ElaboratedType nodes removed. |
| 946 | // |
| 947 | // This is analogous to getDesugaredType but *only* removes ElaboratedType |
| 948 | // sugar. |
| 949 | static 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 Anforowicz | 63559d3 | 2022-05-27 16:42:36 -0700 | [diff] [blame] | 963 | absl::StatusOr<MappedType> Importer::ConvertQualType( |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 964 | clang::QualType qual_type, |
Martin Brænne | 390ffa2 | 2023-07-10 12:26:53 -0700 | [diff] [blame] | 965 | const clang::tidy::lifetimes::ValueLifetimes* lifetimes, |
Googler | 1bff637 | 2023-03-24 10:06:29 -0700 | [diff] [blame] | 966 | std::optional<clang::RefQualifierKind> ref_qualifier_kind, bool nullable) { |
Devin Jeanpierre | e971ed7 | 2022-08-09 05:07:04 -0700 | [diff] [blame] | 967 | qual_type = GetUnelaboratedType(std::move(qual_type), ctx_); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 968 | std::string type_string = qual_type.getAsString(); |
Googler | 1bff637 | 2023-03-24 10:06:29 -0700 | [diff] [blame] | 969 | absl::StatusOr<MappedType> type = ConvertType( |
| 970 | qual_type.getTypePtr(), lifetimes, ref_qualifier_kind, nullable); |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 971 | if (!type.ok()) { |
| 972 | absl::Status error = absl::UnimplementedError(absl::Substitute( |
| 973 | "Unsupported type '$0': $1", type_string, type.status().message())); |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 974 | error.SetPayload(kTypeStatusPayloadUrl, absl::Cord(type_string)); |
| 975 | return error; |
| 976 | } |
| 977 | |
Lukasz Anforowicz | 0c3f8b2 | 2022-02-15 14:56:40 +0000 | [diff] [blame] | 978 | // Handle cv-qualification. |
Devin Jeanpierre | 09c6f45 | 2021-09-29 07:34:24 +0000 | [diff] [blame] | 979 | type->cc_type.is_const = qual_type.isConstQualified(); |
Lukasz Anforowicz | 0c3f8b2 | 2022-02-15 14:56:40 +0000 | [diff] [blame] | 980 | if (qual_type.isVolatileQualified()) { |
| 981 | return absl::UnimplementedError( |
| 982 | absl::StrCat("Unsupported `volatile` qualifier: ", type_string)); |
| 983 | } |
Devin Jeanpierre | 184f9ac | 2021-09-17 13:47:03 +0000 | [diff] [blame] | 984 | |
Lukasz Anforowicz | e933358 | 2022-03-07 15:27:06 +0000 | [diff] [blame] | 985 | return type; |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 986 | } |
| 987 | |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 988 | std::string Importer::GetMangledName(const clang::NamedDecl* named_decl) const { |
Lukasz Anforowicz | 3f13397 | 2022-09-01 09:01:02 -0700 | [diff] [blame] | 989 | 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 Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 993 | llvm::SmallString<128> storage; |
| 994 | llvm::raw_svector_ostream buffer(storage); |
Googler | 0517597 | 2023-10-04 15:19:16 -0700 | [diff] [blame] | 995 | mangler_->mangleCanonicalTypeName(ctx_.getRecordType(record_decl), buffer); |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 996 | |
| 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 Anforowicz | 3f13397 | 2022-09-01 09:01:02 -0700 | [diff] [blame] | 1000 | // prefix. |
Lukasz Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 1001 | constexpr llvm::StringRef kZtsPrefix = "_ZTS"; |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 1002 | CHECK(buffer.str().take_front(4) == kZtsPrefix); |
Lukasz Anforowicz | 3f13397 | 2022-09-01 09:01:02 -0700 | [diff] [blame] | 1003 | 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 Anforowicz | b1ff2e5 | 2022-05-16 10:54:23 -0700 | [diff] [blame] | 1013 | } |
| 1014 | |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1015 | 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 Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 1035 | if (auto dtor = clang::dyn_cast<clang::CXXDestructorDecl>(named_decl)) { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1036 | decl = clang::GlobalDecl(dtor, clang::CXXDtorType::Dtor_Complete); |
| 1037 | } else if (auto ctor = |
Michael Forster | 500b476 | 2022-01-27 12:30:17 +0000 | [diff] [blame] | 1038 | clang::dyn_cast<clang::CXXConstructorDecl>(named_decl)) { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1039 | decl = clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete); |
| 1040 | } else { |
| 1041 | decl = clang::GlobalDecl(named_decl); |
| 1042 | } |
| 1043 | |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 1044 | std::string name; |
| 1045 | llvm::raw_string_ostream stream(name); |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1046 | mangler_->mangleName(decl, stream); |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 1047 | stream.flush(); |
Marcel Hlopko | a5f59ae | 2021-08-24 20:38:04 +0000 | [diff] [blame] | 1048 | return name; |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 1049 | } |
| 1050 | |
Rosica Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 1051 | std::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 VanBemmel | 7a4d4c0 | 2022-07-27 13:21:47 -0700 | [diff] [blame] | 1061 | } 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 Dejanovska | 2708a5f | 2022-06-22 06:54:59 -0700 | [diff] [blame] | 1075 | } else { |
| 1076 | return ""; |
| 1077 | } |
| 1078 | } |
| 1079 | |
Lukasz Anforowicz | 5837b7d | 2023-02-23 16:39:02 -0800 | [diff] [blame] | 1080 | absl::StatusOr<UnqualifiedIdentifier> Importer::GetTranslatedName( |
Marcel Hlopko | 7d73979 | 2021-08-12 07:52:47 +0000 | [diff] [blame] | 1081 | const clang::NamedDecl* named_decl) const { |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1082 | switch (named_decl->getDeclName().getNameKind()) { |
| 1083 | case clang::DeclarationName::Identifier: { |
| 1084 | auto name = std::string(named_decl->getName()); |
Lukasz Anforowicz | ab03e56 | 2022-05-16 11:18:02 -0700 | [diff] [blame] | 1085 | if (name.empty()) { |
Lukasz Anforowicz | 5837b7d | 2023-02-23 16:39:02 -0800 | [diff] [blame] | 1086 | return absl::InvalidArgumentError("Missing identifier"); |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1087 | } |
Lukasz Anforowicz | 5837b7d | 2023-02-23 16:39:02 -0800 | [diff] [blame] | 1088 | |
| 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 Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1098 | 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 Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 1104 | case clang::DeclarationName::CXXOperatorName: |
| 1105 | switch (named_decl->getDeclName().getCXXOverloadedOperator()) { |
| 1106 | case clang::OO_None: |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 1107 | LOG(FATAL) << "No OO_None expected under CXXOperatorName branch"; |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 1108 | case clang::NUM_OVERLOADED_OPERATORS: |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 1109 | LOG(FATAL) << "No NUM_OVERLOADED_OPERATORS expected at runtime"; |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 1110 | // clang-format off |
| 1111 | #define OVERLOADED_OPERATOR(name, spelling, ...) \ |
| 1112 | case clang::OO_##name: { \ |
Lukasz Anforowicz | 9c663ca | 2022-02-09 01:33:31 +0000 | [diff] [blame] | 1113 | return {Operator(spelling)}; \ |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 1114 | } |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 1115 | #include "clang/Basic/OperatorKinds.def" |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 1116 | #undef OVERLOADED_OPERATOR |
| 1117 | // clang-format on |
| 1118 | } |
Lukasz Anforowicz | 2c34cae | 2022-08-26 07:19:20 -0700 | [diff] [blame] | 1119 | LOG(FATAL) << "The `switch` above should handle all cases"; |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1120 | default: |
Lukasz Anforowicz | fae90a1 | 2022-02-03 20:58:15 +0000 | [diff] [blame] | 1121 | // To be implemented later: CXXConversionFunctionName. |
Devin Jeanpierre | f2ec871 | 2021-10-13 20:47:16 +0000 | [diff] [blame] | 1122 | // 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 Anforowicz | f1acde7 | 2023-02-23 16:53:43 -0800 | [diff] [blame] | 1125 | return absl::UnimplementedError( |
| 1126 | absl::StrCat("Unsupported name: ", named_decl->getNameAsString())); |
Devin Jeanpierre | e78b2fb | 2021-10-05 11:40:33 +0000 | [diff] [blame] | 1127 | } |
Marcel Hlopko | e8f1c4e | 2021-07-28 18:12:49 +0000 | [diff] [blame] | 1128 | } |
| 1129 | |
Devin Jeanpierre | 3c4354b | 2023-05-26 16:01:49 -0700 | [diff] [blame] | 1130 | void Importer::MarkAsSuccessfullyImported(const clang::NamedDecl* decl) { |
Lukasz Anforowicz | 23fdfad | 2022-05-27 16:43:43 -0700 | [diff] [blame] | 1131 | known_type_decls_.insert( |
| 1132 | clang::cast<clang::TypeDecl>(decl->getCanonicalDecl())); |
Lukasz Anforowicz | 0233f98 | 2022-05-27 16:38:20 -0700 | [diff] [blame] | 1133 | } |
| 1134 | |
Lukasz Anforowicz | 5258f76 | 2022-05-27 16:14:46 -0700 | [diff] [blame] | 1135 | bool Importer::HasBeenAlreadySuccessfullyImported( |
Devin Jeanpierre | 3c4354b | 2023-05-26 16:01:49 -0700 | [diff] [blame] | 1136 | const clang::NamedDecl* decl) const { |
Lukasz Anforowicz | 23fdfad | 2022-05-27 16:43:43 -0700 | [diff] [blame] | 1137 | return known_type_decls_.contains( |
| 1138 | clang::cast<clang::TypeDecl>(decl->getCanonicalDecl())); |
Lukasz Anforowicz | 5258f76 | 2022-05-27 16:14:46 -0700 | [diff] [blame] | 1139 | } |
| 1140 | |
Marcel Hlopko | f15e8ce | 2022-04-08 08:46:09 -0700 | [diff] [blame] | 1141 | } // namespace crubit |