blob: 35ad45f9cece17f280df63ce53ad279933f82cce [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>
Marcel Hlopko7d739792021-08-12 07:52:47 +000016#include <vector>
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000017
Marcel Hlopko80441c12021-11-12 10:43:18 +000018#include "base/logging.h"
Devin Jeanpierred3f959f2021-10-27 18:47:50 +000019#include "rs_bindings_from_cc/ast_convert.h"
Marcel Hlopko80441c12021-11-12 10:43:18 +000020#include "rs_bindings_from_cc/bazel_types.h"
Marcel Hlopko7d739792021-08-12 07:52:47 +000021#include "rs_bindings_from_cc/ir.h"
Marcel Hlopko80441c12021-11-12 10:43:18 +000022#include "third_party/absl/container/flat_hash_map.h"
Marcel Hlopko7d739792021-08-12 07:52:47 +000023#include "third_party/absl/container/flat_hash_set.h"
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000024#include "third_party/absl/status/status.h"
25#include "third_party/absl/status/statusor.h"
26#include "third_party/absl/strings/cord.h"
Lukasz Anforowicz0c816f12021-12-15 17:41:49 +000027#include "third_party/absl/strings/str_cat.h"
Lukasz Anforowiczc4ceb4f2022-01-28 19:29:19 +000028#include "third_party/absl/strings/str_join.h"
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +000029#include "third_party/absl/strings/string_view.h"
Michael Forster1de27b82021-09-17 07:22:22 +000030#include "third_party/absl/strings/substitute.h"
Marcel Hlopko7d739792021-08-12 07:52:47 +000031#include "third_party/llvm/llvm-project/clang/include/clang/AST/ASTContext.h"
Devin Jeanpierreb69bcae2022-02-03 09:45:50 +000032#include "third_party/llvm/llvm-project/clang/include/clang/AST/Attrs.inc"
Devin Jeanpierre56777022022-02-03 01:57:15 +000033#include "third_party/llvm/llvm-project/clang/include/clang/AST/CXXInheritance.h"
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000034#include "third_party/llvm/llvm-project/clang/include/clang/AST/Decl.h"
Googler2e85f342021-09-17 07:04:07 +000035#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclCXX.h"
Googler846e1fc2022-01-10 13:14:57 +000036#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclTemplate.h"
Marcel Hlopko7d739792021-08-12 07:52:47 +000037#include "third_party/llvm/llvm-project/clang/include/clang/AST/Mangle.h"
Michael Forster028800b2021-10-05 12:39:59 +000038#include "third_party/llvm/llvm-project/clang/include/clang/AST/RawCommentList.h"
Googler6986c072021-09-17 13:54:56 +000039#include "third_party/llvm/llvm-project/clang/include/clang/AST/RecordLayout.h"
Marcel Hlopko7d739792021-08-12 07:52:47 +000040#include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
Michael Forster7b628b12022-01-27 17:48:57 +000041#include "third_party/llvm/llvm-project/clang/include/clang/Basic/FileManager.h"
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +000042#include "third_party/llvm/llvm-project/clang/include/clang/Basic/OperatorKinds.h"
Michael Forster6a184ad2021-10-12 13:04:05 +000043#include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceLocation.h"
Michael Forster028800b2021-10-05 12:39:59 +000044#include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceManager.h"
Googler2e85f342021-09-17 07:04:07 +000045#include "third_party/llvm/llvm-project/clang/include/clang/Basic/Specifiers.h"
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000046#include "third_party/llvm/llvm-project/clang/include/clang/Sema/Sema.h"
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +000047#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/Optional.h"
Devin Jeanpierre56777022022-02-03 01:57:15 +000048#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/SmallPtrSet.h"
Marcel Hlopkob4b28742021-09-15 12:45:20 +000049#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Casting.h"
Lukasz Anforowiczc4ceb4f2022-01-28 19:29:19 +000050#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Regex.h"
Googler06f2c9a2022-01-05 12:00:47 +000051#include "util/gtl/flat_map.h"
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000052
53namespace rs_bindings_from_cc {
Devin Jeanpierre56777022022-02-03 01:57:15 +000054namespace {
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000055
Michael Forsterb836c582022-01-21 11:20:22 +000056constexpr absl::string_view kTypeStatusPayloadUrl =
Michael Forsterdc683af2021-09-17 08:51:28 +000057 "type.googleapis.com/devtools.rust.cc_interop.rs_binding_from_cc.type";
58
Googler44e3fbc2022-01-11 10:19:26 +000059// A mapping of C++ standard types to their equivalent Rust types.
60// To produce more idiomatic results, these types receive special handling
61// instead of using the generic type mapping mechanism.
Devin Jeanpierre56777022022-02-03 01:57:15 +000062constexpr auto kWellKnownTypes =
Googler44e3fbc2022-01-11 10:19:26 +000063 gtl::fixed_flat_map_of<absl::string_view, absl::string_view>({
64 {"ptrdiff_t", "isize"},
65 {"intptr_t", "isize"},
66 {"size_t", "usize"},
67 {"uintptr_t", "usize"},
Googler4e504882022-01-13 10:03:19 +000068 {"std::ptrdiff_t", "isize"},
69 {"std::intptr_t", "isize"},
70 {"std::size_t", "usize"},
71 {"std::uintptr_t", "usize"},
72
Googler44e3fbc2022-01-11 10:19:26 +000073 {"int8_t", "i8"},
Googler44e3fbc2022-01-11 10:19:26 +000074 {"int16_t", "i16"},
Googler44e3fbc2022-01-11 10:19:26 +000075 {"int32_t", "i32"},
Googler44e3fbc2022-01-11 10:19:26 +000076 {"int64_t", "i64"},
Googler4e504882022-01-13 10:03:19 +000077 {"std::int8_t", "i8"},
78 {"std::int16_t", "i16"},
79 {"std::int32_t", "i32"},
80 {"std::int64_t", "i64"},
81
82 {"uint8_t", "u8"},
83 {"uint16_t", "u16"},
84 {"uint32_t", "u32"},
Devin Jeanpierre56777022022-02-03 01:57:15 +000085
Googler44e3fbc2022-01-11 10:19:26 +000086 {"uint64_t", "u64"},
Googler4e504882022-01-13 10:03:19 +000087 {"std::uint8_t", "u8"},
88 {"std::uint16_t", "u16"},
89 {"std::uint32_t", "u32"},
90 {"std::uint64_t", "u64"},
91
Googler44e3fbc2022-01-11 10:19:26 +000092 {"char16_t", "u16"},
93 {"char32_t", "u32"},
94 {"wchar_t", "i32"},
95 });
96
Devin Jeanpierre56777022022-02-03 01:57:15 +000097DeclId GenerateDeclId(const clang::Decl* decl) {
Marcel Hlopko9c150da2021-11-12 10:30:03 +000098 return DeclId(reinterpret_cast<uintptr_t>(decl->getCanonicalDecl()));
99}
100
Devin Jeanpierre56777022022-02-03 01:57:15 +0000101std::vector<BaseClass> GetUnambiguousPublicBases(
Devin Jeanpierred652d932022-02-03 08:55:33 +0000102 const clang::CXXRecordDecl& record_decl, const clang::ASTContext& ctx) {
Devin Jeanpierre56777022022-02-03 01:57:15 +0000103 // This function is unfortunate: the only way to correctly get information
104 // about the bases is lookupInBases. It runs a complex O(N^3) algorithm for
105 // e.g. correctly determining virtual base paths, etc.
106 //
107 // However, lookupInBases does not recurse into a class once it's found.
108 // So we need to call lookupInBases once per class, making this O(N^4).
109
110 llvm::SmallPtrSet<const clang::CXXRecordDecl*, 4> seen;
111 std::vector<BaseClass> bases;
112 clang::CXXBasePaths paths;
113 // the const cast is a common pattern, apparently, see e.g.
114 // https://clang.llvm.org/doxygen/CXXInheritance_8cpp_source.html#l00074
Devin Jeanpierred652d932022-02-03 08:55:33 +0000115 paths.setOrigin(const_cast<clang::CXXRecordDecl*>(&record_decl));
Devin Jeanpierre56777022022-02-03 01:57:15 +0000116
117 auto next_class = [&]() {
118 const clang::CXXRecordDecl* found = nullptr;
119
120 // Matches the first new class it encounters (and adds it to `seen`, so
121 // that future runs don't rediscover it.)
122 auto is_new_class = [&](const clang::CXXBaseSpecifier* base_specifier,
123 clang::CXXBasePath&) {
124 const auto* record_decl = base_specifier->getType()->getAsCXXRecordDecl();
125 if (found) {
126 return record_decl == found;
127 }
128
129 if (record_decl && seen.insert(record_decl).second) {
130 found = record_decl;
131 return true;
132 }
133 return false;
134 };
Devin Jeanpierred652d932022-02-03 08:55:33 +0000135 return record_decl.lookupInBases(is_new_class, paths);
Devin Jeanpierre56777022022-02-03 01:57:15 +0000136 };
137
138 for (; next_class(); paths.clear()) {
139 for (const clang::CXXBasePath& path : paths) {
140 if (path.Access != clang::AS_public) {
141 continue;
142 }
143 const clang::CXXBaseSpecifier& base_specifier =
144 *path[path.size() - 1].Base;
145 const clang::QualType& base = base_specifier.getType();
146 if (paths.isAmbiguous(ctx.getCanonicalType(base))) {
147 continue;
148 }
149 const clang::CXXRecordDecl* base_record_decl =
150 ABSL_DIE_IF_NULL(base_specifier.getType()->getAsCXXRecordDecl());
151 std::optional<int64_t> offset = {0};
152 for (const clang::CXXBasePathElement& base_path_element : path) {
153 if (base_path_element.Base->isVirtual()) {
154 offset = std::nullopt;
155 break;
156 }
157 *offset +=
158 {ctx.getASTRecordLayout(base_path_element.Class)
159 .getBaseClassOffset(ABSL_DIE_IF_NULL(
160 base_path_element.Base->getType()->getAsCXXRecordDecl()))
161 .getQuantity()};
162 }
163 DCHECK(!offset.has_value() || *offset >= 0)
164 << "Concrete base classes should have non-negative offsets.";
165 bases.push_back(
166 BaseClass{.base_record_id = GenerateDeclId(base_record_decl),
167 .offset = offset});
168 break;
169 }
170 }
171 return bases;
172}
173} // namespace
174
Michael Forster7b628b12022-01-27 17:48:57 +0000175std::vector<clang::RawComment*> Importer::ImportFreeComments() {
Michael Forstera49d2e62022-01-28 07:26:40 +0000176 clang::SourceManager& sm = ctx_.getSourceManager();
Michael Forster7b628b12022-01-27 17:48:57 +0000177
178 // We put all comments into an ordered set in source order. Later we'll remove
179 // the comments that we don't want or that we get by other means.
180 auto source_order = [&sm](const clang::SourceLocation& a,
181 const clang::SourceLocation& b) {
182 return b.isValid() && (a.isInvalid() || sm.isBeforeInTranslationUnit(a, b));
183 };
184 auto ordered_comments = std::map<clang::SourceLocation, clang::RawComment*,
185 decltype(source_order)>(source_order);
186
Michael Forstera49d2e62022-01-28 07:26:40 +0000187 // We start off by getting the comments from all entry header files...
188 for (const auto& header : invocation_.entry_headers_) {
Michael Forster7b628b12022-01-27 17:48:57 +0000189 if (auto file = sm.getFileManager().getFile(header.IncludePath())) {
Michael Forstera49d2e62022-01-28 07:26:40 +0000190 if (auto comments = ctx_.Comments.getCommentsInFile(
Michael Forster7b628b12022-01-27 17:48:57 +0000191 sm.getOrCreateFileID(*file, clang::SrcMgr::C_User))) {
192 for (const auto& [_, comment] : *comments) {
193 ordered_comments.insert({comment->getBeginLoc(), comment});
194 }
195 }
196 }
197 }
198
199 // ... and then we remove those that "conflict" with an IR item.
200 for (const auto& [decl, result] : lookup_cache_) {
201 if (result.item()) {
202 // Remove doc comments of imported items.
Michael Forstera49d2e62022-01-28 07:26:40 +0000203 if (auto raw_comment = ctx_.getRawCommentForDeclNoCache(decl)) {
Michael Forster7b628b12022-01-27 17:48:57 +0000204 ordered_comments.erase(raw_comment->getBeginLoc());
205 }
206 // Remove comments that are within a visited decl.
207 // TODO(forster): We should retain floating comments in decls like
208 // records and namespaces.
209 ordered_comments.erase(ordered_comments.lower_bound(decl->getBeginLoc()),
210 ordered_comments.upper_bound(decl->getEndLoc()));
211 }
212 }
213
214 // Return the remaining comments as a `std::vector`.
215 std::vector<clang::RawComment*> result;
216 result.reserve(ordered_comments.size());
217 for (auto& [_, comment] : ordered_comments) {
218 result.push_back(comment);
219 }
220 return result;
221}
222
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000223// Multiple IR items can be associated with the same source location (e.g. the
224// implicitly defined constructors and assignment operators). To produce
225// deterministic output, we order such items based on GetDeclOrder. The order
226// is somewhat arbitrary, but we still try to make it aesthetically pleasing
227// (e.g. constructors go before assignment operators; default constructor goes
228// first, etc.).
229static int GetDeclOrder(const clang::Decl* decl) {
230 if (clang::isa<clang::RecordDecl>(decl)) {
231 return decl->getDeclContext()->isRecord() ? 101 : 100;
232 }
233
234 if (auto* ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
235 return ctor->isDefaultConstructor() ? 202
236 : ctor->isCopyConstructor() ? 203
237 : ctor->isMoveConstructor() ? 204
238 : 299;
239 }
240
241 if (clang::isa<clang::CXXDestructorDecl>(decl)) {
242 return 306;
243 }
244
245 if (auto* method = clang::dyn_cast<clang::CXXMethodDecl>(decl)) {
246 return method->isCopyAssignmentOperator() ? 401
247 : method->isMoveAssignmentOperator() ? 402
248 : 499;
249 }
250
251 return 999;
252}
253
Michael Forstera49d2e62022-01-28 07:26:40 +0000254void Importer::Import(clang::TranslationUnitDecl* translation_unit_decl) {
255 ImportDeclsFromDeclContext(translation_unit_decl);
256
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000257 using OrderedItem = std::tuple<clang::SourceRange, int, IR::Item>;
Michael Forstera49d2e62022-01-28 07:26:40 +0000258 clang::SourceManager& sm = ctx_.getSourceManager();
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000259 auto is_less_than = [&sm](const OrderedItem& a, const OrderedItem& b) {
260 auto a_range = std::get<0>(a);
261 auto b_range = std::get<0>(b);
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000262 if (!a_range.isValid() || !b_range.isValid()) {
263 if (a_range.isValid() != b_range.isValid())
264 return !a_range.isValid() && b_range.isValid();
265 } else {
266 if (a_range.getBegin() != b_range.getBegin()) {
267 return sm.isBeforeInTranslationUnit(a_range.getBegin(),
268 b_range.getBegin());
269 }
270 if (a_range.getEnd() != b_range.getEnd()) {
271 return sm.isBeforeInTranslationUnit(a_range.getEnd(), b_range.getEnd());
272 }
273 }
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000274
275 auto a_decl_order = std::get<1>(a);
276 auto b_decl_order = std::get<1>(b);
277 if (a_decl_order != b_decl_order) return a_decl_order < b_decl_order;
278
279 // A single FunctionDecl can be associated with multiple UnsupportedItems.
280 // Comparing the fields allows deterministic order between items like:
281 // Non-trivial_abi type '...' is not supported by value as a parameter.
282 // Non-trivial_abi type '...' is not supported by value as a return type.
283 const auto& a_variant = std::get<2>(a);
284 const auto& b_variant = std::get<2>(b);
285 const auto* a_unsupported = std::get_if<UnsupportedItem>(&a_variant);
286 const auto* b_unsupported = std::get_if<UnsupportedItem>(&b_variant);
287 if (a_unsupported && b_unsupported) {
288 if (a_unsupported->name != b_unsupported->name)
289 return a_unsupported->name < b_unsupported->name;
290 return a_unsupported->message < b_unsupported->message;
291 }
292
293 return false;
294 };
295 auto are_equal = [&is_less_than](const OrderedItem& a, const OrderedItem& b) {
296 return !is_less_than(a, b) && !is_less_than(b, a);
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000297 };
Michael Forster365bba12022-01-24 16:56:06 +0000298
299 // We emit IR items in the order of the decls they were generated for.
300 // For decls that emit multiple items we use a stable, but arbitrary order.
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000301 std::vector<OrderedItem> items;
Michael Forster500b4762022-01-27 12:30:17 +0000302 for (const auto& [decl, result] : lookup_cache_) {
Michael Forster500b4762022-01-27 12:30:17 +0000303 auto item = result.item();
304 if (item) {
Michael Forster365bba12022-01-24 16:56:06 +0000305 items.push_back(
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000306 std::make_tuple(decl->getSourceRange(), GetDeclOrder(decl), *item));
Michael Forster500b4762022-01-27 12:30:17 +0000307 }
308 if (IsFromCurrentTarget(decl)) {
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000309 std::string name = "unnamed";
310 if (const auto* named_decl = clang::dyn_cast<clang::NamedDecl>(decl)) {
311 name = named_decl->getQualifiedNameAsString();
312 }
313 SourceLoc source_loc = ConvertSourceLocation(decl->getBeginLoc());
Michael Forster500b4762022-01-27 12:30:17 +0000314 for (const auto& error : result.errors()) {
Michael Forster500b4762022-01-27 12:30:17 +0000315 items.push_back(std::make_tuple(
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000316 decl->getSourceRange(), GetDeclOrder(decl),
Michael Forster500b4762022-01-27 12:30:17 +0000317 UnsupportedItem{
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000318 .name = name, .message = error, .source_loc = source_loc}));
Michael Forster500b4762022-01-27 12:30:17 +0000319 }
Michael Forster365bba12022-01-24 16:56:06 +0000320 }
321 }
Michael Forster500b4762022-01-27 12:30:17 +0000322
Michael Forster7b628b12022-01-27 17:48:57 +0000323 for (auto comment : ImportFreeComments()) {
Michael Forster365bba12022-01-24 16:56:06 +0000324 items.push_back(std::make_tuple(
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000325 comment->getSourceRange(), 0 /* decl_order */,
Michael Forster365bba12022-01-24 16:56:06 +0000326 Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics())}));
327 }
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000328 std::sort(items.begin(), items.end(), is_less_than);
Michael Forster365bba12022-01-24 16:56:06 +0000329
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000330 for (size_t i = 0; i < items.size(); i++) {
331 const auto& item = items[i];
332 if (i > 0) {
333 const auto& prev = items[i - 1];
334 if (are_equal(item, prev)) {
335 std::string prev_json =
336 std::visit([&](auto&& item) { return item.ToJson().dump(); },
337 std::get<2>(prev));
338 std::string curr_json =
339 std::visit([&](auto&& item) { return item.ToJson().dump(); },
340 std::get<2>(item));
341 if (prev_json != curr_json) {
342 LOG(FATAL) << "Non-deterministic order of IR items: " << prev_json
343 << " -VS- " << curr_json;
344 } else {
345 // TODO(lukasza): Avoid generating duplicate IR items. Currently
346 // known example: UnsupportedItem: name=std::signbit; message=
347 // Items contained in namespaces are not supported yet.
348 LOG(WARNING) << "Duplicated IR item: " << curr_json;
349 continue;
350 }
351 }
352 }
Michael Forstera49d2e62022-01-28 07:26:40 +0000353 invocation_.ir_.items.push_back(std::get<2>(item));
Michael Forster365bba12022-01-24 16:56:06 +0000354 }
355}
356
Michael Forster500b4762022-01-27 12:30:17 +0000357void Importer::ImportDeclsFromDeclContext(
358 const clang::DeclContext* decl_context) {
359 for (auto decl : decl_context->decls()) {
Michael Forster500b4762022-01-27 12:30:17 +0000360 LookupDecl(decl->getCanonicalDecl());
361
362 if (auto* nested_context = clang::dyn_cast<clang::DeclContext>(decl)) {
363 if (nested_context->isNamespace())
364 ImportDeclsFromDeclContext(nested_context);
365 }
366 }
367}
368
369Importer::LookupResult Importer::LookupDecl(clang::Decl* decl) {
370 if (!lookup_cache_.contains(decl)) {
371 lookup_cache_.insert({decl, ImportDecl(decl)});
372 }
373
374 return lookup_cache_[decl];
375}
376
377Importer::LookupResult Importer::ImportDecl(clang::Decl* decl) {
378 if (decl->getDeclContext()->isNamespace()) {
379 return LookupResult("Items contained in namespaces are not supported yet");
380 }
381
382 if (auto* function_decl = clang::dyn_cast<clang::FunctionDecl>(decl)) {
383 return ImportFunction(function_decl);
384 } else if (auto* function_template_decl =
385 clang::dyn_cast<clang::FunctionTemplateDecl>(decl)) {
386 return ImportFunction(function_template_decl->getTemplatedDecl());
Devin Jeanpierred652d932022-02-03 08:55:33 +0000387 } else if (auto* record_decl = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
Michael Forster500b4762022-01-27 12:30:17 +0000388 auto result = ImportRecord(record_decl);
389 // TODO(forster): Should we even visit the nested decl if we couldn't
390 // import the parent? For now we have tests that check that we generate
391 // error messages for those decls, so we're visiting.
392 ImportDeclsFromDeclContext(record_decl);
393 return result;
394 } else if (auto* typedef_name_decl =
395 clang::dyn_cast<clang::TypedefNameDecl>(decl)) {
396 return ImportTypedefName(typedef_name_decl);
397 } else if (clang::isa<clang::ClassTemplateDecl>(decl)) {
398 return LookupResult("Class templates are not supported yet");
399 } else {
400 return LookupResult();
401 }
402}
403
404Importer::LookupResult Importer::ImportFunction(
405 clang::FunctionDecl* function_decl) {
406 if (!IsFromCurrentTarget(function_decl)) return LookupResult();
407 if (function_decl->isDeleted()) return LookupResult();
Marcel Hlopko3df195b2022-01-26 14:15:03 +0000408 if (function_decl->isTemplated()) {
Michael Forster500b4762022-01-27 12:30:17 +0000409 return LookupResult("Function templates are not supported yet");
Marcel Hlopko3df195b2022-01-26 14:15:03 +0000410 }
Marcel Hlopko36ced2d2021-12-02 10:47:37 +0000411
Googler4e1bc132021-12-06 10:10:42 +0000412 devtools_rust::LifetimeSymbolTable lifetime_symbol_table;
413 llvm::Expected<devtools_rust::FunctionLifetimes> lifetimes =
Michael Forstera49d2e62022-01-28 07:26:40 +0000414 devtools_rust::GetLifetimeAnnotations(function_decl,
415 *invocation_.lifetime_context_,
Googler4e1bc132021-12-06 10:10:42 +0000416 &lifetime_symbol_table);
417 llvm::DenseSet<devtools_rust::Lifetime> all_lifetimes;
418
Marcel Hlopko7d739792021-08-12 07:52:47 +0000419 std::vector<FuncParam> params;
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000420 std::set<std::string> errors;
421 auto add_error = [&errors, function_decl](std::string msg) {
422 auto result = errors.insert(std::move(msg));
423 CHECK(result.second) << "Duplicated error message for "
424 << function_decl->getNameAsString() << ": "
425 << *result.first;
426 };
Michael Forster500b4762022-01-27 12:30:17 +0000427 if (auto* method_decl =
428 clang::dyn_cast<clang::CXXMethodDecl>(function_decl)) {
Marcel Hlopkoa5a18732022-01-27 09:58:53 +0000429 if (!known_type_decls_.contains(
430 method_decl->getParent()->getCanonicalDecl())) {
Michael Forster500b4762022-01-27 12:30:17 +0000431 return LookupResult("Couldn't import the parent");
Marcel Hlopkoa5a18732022-01-27 09:58:53 +0000432 }
433
434 // non-static member functions receive an implicit `this` parameter.
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000435 if (method_decl->isInstance()) {
Googler4e1bc132021-12-06 10:10:42 +0000436 std::optional<devtools_rust::TypeLifetimes> this_lifetimes;
437 if (lifetimes) {
438 this_lifetimes = lifetimes->this_lifetimes;
439 all_lifetimes.insert(this_lifetimes->begin(), this_lifetimes->end());
440 }
441 auto param_type = ConvertType(method_decl->getThisType(), this_lifetimes,
442 /*nullable=*/false);
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000443 if (!param_type.ok()) {
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000444 add_error(absl::StrCat("`this` parameter is not supported: ",
445 param_type.status().message()));
Devin Jeanpierrefecf5472021-10-27 10:52:30 +0000446 } else {
447 params.push_back({*std::move(param_type), Identifier("__this")});
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000448 }
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000449 }
450 }
Michael Forster523dbd42021-10-12 11:05:44 +0000451
Googler4e1bc132021-12-06 10:10:42 +0000452 if (lifetimes) {
453 CHECK_EQ(lifetimes->param_lifetimes.size(), function_decl->getNumParams());
454 }
455 for (unsigned i = 0; i < function_decl->getNumParams(); ++i) {
456 const clang::ParmVarDecl* param = function_decl->getParamDecl(i);
457 std::optional<devtools_rust::TypeLifetimes> param_lifetimes;
458 if (lifetimes) {
459 param_lifetimes = lifetimes->param_lifetimes[i];
460 all_lifetimes.insert(param_lifetimes->begin(), param_lifetimes->end());
461 }
462 auto param_type = ConvertType(param->getType(), param_lifetimes);
Michael Forsterdc683af2021-09-17 08:51:28 +0000463 if (!param_type.ok()) {
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000464 add_error(absl::Substitute("Parameter #$0 is not supported: $1", i,
465 param_type.status().message()));
Michael Forster523dbd42021-10-12 11:05:44 +0000466 continue;
Michael Forster1de27b82021-09-17 07:22:22 +0000467 }
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000468
469 if (const clang::RecordType* record_type =
Michael Forster500b4762022-01-27 12:30:17 +0000470 clang::dyn_cast<clang::RecordType>(param->getType())) {
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000471 if (clang::RecordDecl* record_decl =
Michael Forster500b4762022-01-27 12:30:17 +0000472 clang::dyn_cast<clang::RecordDecl>(record_type->getDecl())) {
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000473 // TODO(b/200067242): non-trivial_abi structs, when passed by value,
474 // have a different representation which needs special support. We
475 // currently do not support it.
476 if (!record_decl->canPassInRegisters()) {
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000477 add_error(
Marcel Hlopko3df72542021-11-30 09:38:36 +0000478 absl::Substitute("Non-trivial_abi type '$0' is not "
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000479 "supported by value as parameter #$1",
480 param->getType().getAsString(), i));
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000481 }
482 }
483 }
484
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000485 std::optional<Identifier> param_name = GetTranslatedIdentifier(param);
Lukasz Anforowicz0c816f12021-12-15 17:41:49 +0000486 CHECK(param_name.has_value()); // No known cases where the above can fail.
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000487 params.push_back({*param_type, *std::move(param_name)});
Marcel Hlopko7d739792021-08-12 07:52:47 +0000488 }
489
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000490 if (const clang::RecordType* record_return_type =
Michael Forster500b4762022-01-27 12:30:17 +0000491 clang::dyn_cast<clang::RecordType>(function_decl->getReturnType())) {
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000492 if (clang::RecordDecl* record_decl =
Michael Forster500b4762022-01-27 12:30:17 +0000493 clang::dyn_cast<clang::RecordDecl>(record_return_type->getDecl())) {
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000494 // TODO(b/200067242): non-trivial_abi structs, when passed by value,
495 // have a different representation which needs special support. We
496 // currently do not support it.
497 if (!record_decl->canPassInRegisters()) {
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000498 add_error(
Marcel Hlopko3df72542021-11-30 09:38:36 +0000499 absl::Substitute("Non-trivial_abi type '$0' is not supported "
500 "by value as a return type",
Michael Forster500b4762022-01-27 12:30:17 +0000501 function_decl->getReturnType().getAsString()));
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000502 }
503 }
504 }
505
Googler4e1bc132021-12-06 10:10:42 +0000506 std::optional<devtools_rust::TypeLifetimes> return_lifetimes;
507 if (lifetimes) {
508 return_lifetimes = lifetimes->return_lifetimes;
509 all_lifetimes.insert(return_lifetimes->begin(), return_lifetimes->end());
510 }
511 auto return_type =
512 ConvertType(function_decl->getReturnType(), return_lifetimes);
Michael Forsterdc683af2021-09-17 08:51:28 +0000513 if (!return_type.ok()) {
Lukasz Anforowicz49b5bbc2022-02-04 23:40:10 +0000514 add_error(absl::StrCat("Return type is not supported: ",
515 return_type.status().message()));
Michael Forster1de27b82021-09-17 07:22:22 +0000516 }
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000517
Googler4e1bc132021-12-06 10:10:42 +0000518 std::vector<Lifetime> lifetime_params;
519 for (devtools_rust::Lifetime lifetime : all_lifetimes) {
520 std::optional<llvm::StringRef> name =
521 lifetime_symbol_table.LookupLifetime(lifetime);
522 CHECK(name.has_value());
523 lifetime_params.push_back(
524 {.name = name->str(), .id = LifetimeId(lifetime.Id())});
525 }
526 std::sort(
527 lifetime_params.begin(), lifetime_params.end(),
528 [](const Lifetime& l1, const Lifetime& l2) { return l1.name < l2.name; });
529
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000530 std::optional<MemberFuncMetadata> member_func_metadata;
Michael Forster500b4762022-01-27 12:30:17 +0000531 if (auto* method_decl =
532 clang::dyn_cast<clang::CXXMethodDecl>(function_decl)) {
Lukasz Anforowicz57331cf2021-12-16 02:57:19 +0000533 switch (method_decl->getAccess()) {
534 case clang::AS_public:
535 break;
536 case clang::AS_protected:
537 case clang::AS_private:
538 case clang::AS_none:
539 // No need for IR to include Func representing private methods.
540 // TODO(lukasza): Revisit this for protected methods.
Michael Forster500b4762022-01-27 12:30:17 +0000541 return LookupResult();
Lukasz Anforowicz57331cf2021-12-16 02:57:19 +0000542 }
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000543 std::optional<MemberFuncMetadata::InstanceMethodMetadata> instance_metadata;
544 if (method_decl->isInstance()) {
545 MemberFuncMetadata::ReferenceQualification reference;
546 switch (method_decl->getRefQualifier()) {
547 case clang::RQ_LValue:
548 reference = MemberFuncMetadata::kLValue;
549 break;
550 case clang::RQ_RValue:
551 reference = MemberFuncMetadata::kRValue;
552 break;
553 case clang::RQ_None:
554 reference = MemberFuncMetadata::kUnqualified;
555 break;
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000556 }
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000557 instance_metadata = MemberFuncMetadata::InstanceMethodMetadata{
558 .reference = reference,
559 .is_const = method_decl->isConst(),
560 .is_virtual = method_decl->isVirtual(),
Lukasz Anforowicz71716b72022-01-26 17:05:05 +0000561 .is_explicit_ctor = false,
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000562 };
Lukasz Anforowicz71716b72022-01-26 17:05:05 +0000563 if (auto* ctor_decl =
Michael Forster500b4762022-01-27 12:30:17 +0000564 clang::dyn_cast<clang::CXXConstructorDecl>(function_decl)) {
Lukasz Anforowicz71716b72022-01-26 17:05:05 +0000565 instance_metadata->is_explicit_ctor = ctor_decl->isExplicit();
566 }
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000567 }
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000568
569 member_func_metadata = MemberFuncMetadata{
570 .record_id = GenerateDeclId(method_decl->getParent()),
571 .instance_method_metadata = instance_metadata};
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000572 }
573
Michael Forster500b4762022-01-27 12:30:17 +0000574 if (!errors.empty()) {
575 return LookupResult(errors);
576 }
577
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000578 std::optional<UnqualifiedIdentifier> translated_name =
579 GetTranslatedName(function_decl);
Michael Forster277ff952022-01-27 18:14:56 +0000580 CHECK(return_type.ok()); // Silence ClangTidy, checked above.
Michael Forster500b4762022-01-27 12:30:17 +0000581 if (translated_name.has_value()) {
582 return LookupResult(Func{
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000583 .name = *translated_name,
Marcel Hlopko80441c12021-11-12 10:43:18 +0000584 .owning_target = GetOwningTarget(function_decl),
Michael Forster523dbd42021-10-12 11:05:44 +0000585 .doc_comment = GetComment(function_decl),
586 .mangled_name = GetMangledName(function_decl),
587 .return_type = *return_type,
588 .params = std::move(params),
Googler4e1bc132021-12-06 10:10:42 +0000589 .lifetime_params = std::move(lifetime_params),
Michael Forster523dbd42021-10-12 11:05:44 +0000590 .is_inline = function_decl->isInlined(),
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000591 .member_func_metadata = std::move(member_func_metadata),
Googler95f29a12022-01-07 07:47:26 +0000592 .source_loc = ConvertSourceLocation(function_decl->getBeginLoc()),
Michael Forster523dbd42021-10-12 11:05:44 +0000593 });
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000594 }
Michael Forster500b4762022-01-27 12:30:17 +0000595 return LookupResult();
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +0000596}
597
Michael Forster500b4762022-01-27 12:30:17 +0000598BlazeLabel Importer::GetOwningTarget(const clang::Decl* decl) const {
Michael Forstera49d2e62022-01-28 07:26:40 +0000599 clang::SourceManager& source_manager = ctx_.getSourceManager();
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000600 auto source_location = decl->getLocation();
Marcel Hlopko80441c12021-11-12 10:43:18 +0000601
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000602 // If the header this decl comes from is not associated with a target we
603 // consider it a textual header. In that case we go up the include stack
604 // until we find a header that has an owning target.
605
Rosica Dejanovska381d1032022-02-03 22:19:54 +0000606 while (source_location.isValid()) {
Rosica Dejanovska503d7dd2022-02-01 20:37:49 +0000607 if (source_location.isMacroID()) {
608 source_location = source_manager.getExpansionLoc(source_location);
609 }
610 auto id = source_manager.getFileID(source_location);
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000611 llvm::Optional<llvm::StringRef> filename =
612 source_manager.getNonBuiltinFilenameForID(id);
613 if (!filename) {
614 return BlazeLabel("//:builtin");
615 }
616 if (filename->startswith("./")) {
617 filename = filename->substr(2);
618 }
Michael Forstera49d2e62022-01-28 07:26:40 +0000619
620 if (auto target = invocation_.header_target(HeaderName(filename->str()))) {
621 return *target;
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000622 }
623 source_location = source_manager.getIncludeLoc(id);
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000624 }
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000625
626 return BlazeLabel("//:virtual_clang_resource_dir_target");
Marcel Hlopko80441c12021-11-12 10:43:18 +0000627}
628
Michael Forster500b4762022-01-27 12:30:17 +0000629bool Importer::IsFromCurrentTarget(const clang::Decl* decl) const {
Michael Forstera49d2e62022-01-28 07:26:40 +0000630 return invocation_.target_ == GetOwningTarget(decl);
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000631}
632
Devin Jeanpierred652d932022-02-03 08:55:33 +0000633Importer::LookupResult Importer::ImportRecord(
634 clang::CXXRecordDecl* record_decl) {
Googler21351fc2021-10-19 08:58:04 +0000635 const clang::DeclContext* decl_context = record_decl->getDeclContext();
Dmitri Gribenko14627692022-01-31 09:37:00 +0000636 if (decl_context->isFunctionOrMethod()) {
637 return LookupResult();
638 }
639 if (record_decl->isInjectedClassName()) {
640 return LookupResult();
Googler21351fc2021-10-19 08:58:04 +0000641 }
Michael Forster500b4762022-01-27 12:30:17 +0000642 if (decl_context->isRecord()) {
643 return LookupResult("Nested classes are not supported yet");
644 }
Marcel Hlopko872df5e2022-01-25 21:18:55 +0000645 if (record_decl->isUnion()) {
Michael Forster500b4762022-01-27 12:30:17 +0000646 return LookupResult("Unions are not supported yet");
Marcel Hlopko872df5e2022-01-25 21:18:55 +0000647 }
Googler8173f592022-01-04 13:57:32 +0000648 // Make sure the record has a definition that we'll be able to call
649 // ASTContext::getASTRecordLayout() on.
650 record_decl = record_decl->getDefinition();
651 if (!record_decl || record_decl->isInvalidDecl() ||
652 !record_decl->isCompleteDefinition()) {
Michael Forster500b4762022-01-27 12:30:17 +0000653 return LookupResult();
Googler8173f592022-01-04 13:57:32 +0000654 }
655
Devin Jeanpierrec80e6242022-02-03 01:56:40 +0000656 // To compute the memory layout of the record, it needs to be a concrete type,
657 // not a template.
Devin Jeanpierred652d932022-02-03 08:55:33 +0000658 if (record_decl->getDescribedClassTemplate() ||
659 clang::isa<clang::ClassTemplateSpecializationDecl>(record_decl)) {
Devin Jeanpierrec80e6242022-02-03 01:56:40 +0000660 return LookupResult("Class templates are not supported yet");
661 }
662
Devin Jeanpierred652d932022-02-03 08:55:33 +0000663 sema_.ForceDeclarationOfImplicitMembers(record_decl);
664
Devin Jeanpierrec80e6242022-02-03 01:56:40 +0000665 const clang::ASTRecordLayout& layout = ctx_.getASTRecordLayout(record_decl);
Devin Jeanpierred652d932022-02-03 08:55:33 +0000666
Devin Jeanpierrec80e6242022-02-03 01:56:40 +0000667 std::optional<size_t> base_size = std::nullopt;
668 bool override_alignment = false;
Devin Jeanpierred652d932022-02-03 08:55:33 +0000669 if (record_decl->getNumBases() != 0) {
670 // The size of the base class subobjects is easy to compute, so long as we
671 // know that fields start after the base class subobjects. (This is not
672 // guaranteed by the standard, but is true on the ABIs we work with.)
673 base_size = layout.getFieldCount() == 0
674 ? static_cast<size_t>(layout.getDataSize().getQuantity())
675 : layout.getFieldOffset(0) / 8;
676 // Ideally, we'd only include an alignment adjustment if one of the base
677 // classes is more-aligned than any of the fields, but it is simpler do it
678 // whenever there are any base classes at all.
679 override_alignment = true;
Googler2e85f342021-09-17 07:04:07 +0000680 }
Devin Jeanpierred652d932022-02-03 08:55:33 +0000681
Googler279eca32022-01-04 14:03:44 +0000682 std::optional<Identifier> record_name = GetTranslatedIdentifier(record_decl);
683 if (!record_name.has_value()) {
Michael Forster500b4762022-01-27 12:30:17 +0000684 return LookupResult();
Googler279eca32022-01-04 14:03:44 +0000685 }
686 // Provisionally assume that we know this RecordDecl so that we'll be able
687 // to import fields whose type contains the record itself.
Googlerdcca7f72022-01-10 12:30:43 +0000688 known_type_decls_.insert(record_decl);
Devin Jeanpierred652d932022-02-03 08:55:33 +0000689 absl::StatusOr<std::vector<Field>> fields = ImportFields(record_decl);
Michael Forster500b4762022-01-27 12:30:17 +0000690 if (!fields.ok()) {
Googler279eca32022-01-04 14:03:44 +0000691 // Importing a field failed, so note that we didn't import this RecordDecl
692 // after all.
Googlerdcca7f72022-01-10 12:30:43 +0000693 known_type_decls_.erase(record_decl);
Michael Forster500b4762022-01-27 12:30:17 +0000694 return LookupResult("Importing field failed");
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000695 }
Michael Forster500b4762022-01-27 12:30:17 +0000696
Devin Jeanpierreb69bcae2022-02-03 09:45:50 +0000697 for (const Field& field : *fields) {
698 if (field.is_no_unique_address) {
699 override_alignment = true;
700 break;
701 }
702 }
703
Devin Jeanpierre56777022022-02-03 01:57:15 +0000704 return LookupResult(Record{
705 .identifier = *record_name,
706 .id = GenerateDeclId(record_decl),
707 .owning_target = GetOwningTarget(record_decl),
708 .doc_comment = GetComment(record_decl),
709 .unambiguous_public_bases = GetUnambiguousPublicBases(*record_decl, ctx_),
710 .fields = *std::move(fields),
711 .size = layout.getSize().getQuantity(),
712 .alignment = layout.getAlignment().getQuantity(),
713 .base_size = base_size,
714 .override_alignment = override_alignment,
715 .copy_constructor = GetCopyCtorSpecialMemberFunc(*record_decl),
716 .move_constructor = GetMoveCtorSpecialMemberFunc(*record_decl),
717 .destructor = GetDestructorSpecialMemberFunc(*record_decl),
718 .is_trivial_abi = record_decl->canPassInRegisters(),
Devin Jeanpierred652d932022-02-03 08:55:33 +0000719 .is_final = record_decl->isEffectivelyFinal()});
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000720}
721
Michael Forster500b4762022-01-27 12:30:17 +0000722Importer::LookupResult Importer::ImportTypedefName(
Googler68346992022-01-05 06:11:31 +0000723 clang::TypedefNameDecl* typedef_name_decl) {
Googlerdcca7f72022-01-10 12:30:43 +0000724 const clang::DeclContext* decl_context = typedef_name_decl->getDeclContext();
725 if (decl_context) {
726 if (decl_context->isFunctionOrMethod()) {
Michael Forster500b4762022-01-27 12:30:17 +0000727 return LookupResult();
Googlerdcca7f72022-01-10 12:30:43 +0000728 }
729 if (decl_context->isRecord()) {
Michael Forster500b4762022-01-27 12:30:17 +0000730 return LookupResult("Typedefs nested in classes are not supported yet");
Googlerdcca7f72022-01-10 12:30:43 +0000731 }
732 }
733
Googler44e3fbc2022-01-11 10:19:26 +0000734 clang::QualType type =
735 typedef_name_decl->getASTContext().getTypedefType(typedef_name_decl);
736 if (kWellKnownTypes.contains(type.getAsString())) {
Michael Forster500b4762022-01-27 12:30:17 +0000737 return LookupResult();
Googler44e3fbc2022-01-11 10:19:26 +0000738 }
739
Googlerdcca7f72022-01-10 12:30:43 +0000740 std::optional<Identifier> identifier =
741 GetTranslatedIdentifier(typedef_name_decl);
742 if (!identifier.has_value()) {
743 // This should never happen.
744 LOG(FATAL) << "Couldn't get identifier for TypedefNameDecl";
Googlerdcca7f72022-01-10 12:30:43 +0000745 }
746 absl::StatusOr<MappedType> underlying_type =
747 ConvertType(typedef_name_decl->getUnderlyingType());
748 if (underlying_type.ok()) {
749 known_type_decls_.insert(typedef_name_decl);
Michael Forster500b4762022-01-27 12:30:17 +0000750 return LookupResult(
Googlerdcca7f72022-01-10 12:30:43 +0000751 TypeAlias{.identifier = *identifier,
752 .id = GenerateDeclId(typedef_name_decl),
753 .owning_target = GetOwningTarget(typedef_name_decl),
754 .underlying_type = *underlying_type});
755 } else {
Michael Forster500b4762022-01-27 12:30:17 +0000756 return LookupResult(std::string(underlying_type.status().message()));
Googlerdcca7f72022-01-10 12:30:43 +0000757 }
Googler68346992022-01-05 06:11:31 +0000758}
759
Lukasz Anforowiczc4ceb4f2022-01-28 19:29:19 +0000760static bool ShouldKeepCommentLine(absl::string_view line) {
761 // Based on https://clang.llvm.org/extra/clang-tidy/:
762 llvm::Regex patterns_to_ignore(
763 "^[[:space:]/]*" // Whitespace, or extra //
764 "(NOLINT|NOLINTNEXTLINE|NOLINTBEGIN|NOLINTEND)"
765 "(\\([^)[:space:]]*\\)?)?" // Optional (...)
766 "[[:space:]]*$"); // Whitespace
767 return !patterns_to_ignore.match(line);
768}
769
Michael Forster500b4762022-01-27 12:30:17 +0000770std::optional<std::string> Importer::GetComment(const clang::Decl* decl) const {
Michael Forster409d9412021-10-07 08:35:29 +0000771 // This does currently not distinguish between different types of comments.
772 // In general it is not possible in C++ to reliably only extract doc comments.
773 // This is going to be a heuristic that needs to be tuned over time.
774
Michael Forstera49d2e62022-01-28 07:26:40 +0000775 clang::SourceManager& sm = ctx_.getSourceManager();
776 clang::RawComment* raw_comment = ctx_.getRawCommentForDeclNoCache(decl);
Michael Forstercc5941a2021-10-07 07:12:24 +0000777
778 if (raw_comment == nullptr) {
779 return {};
Michael Forstercc5941a2021-10-07 07:12:24 +0000780 }
Lukasz Anforowiczc4ceb4f2022-01-28 19:29:19 +0000781
782 std::string raw_comment_text =
783 raw_comment->getFormattedText(sm, sm.getDiagnostics());
784 std::string cleaned_comment_text = absl::StrJoin(
785 absl::StrSplit(raw_comment_text, '\n', ShouldKeepCommentLine), "\n");
786 return cleaned_comment_text.empty()
787 ? std::nullopt
788 : std::optional<std::string>(std::move(cleaned_comment_text));
Michael Forstercc5941a2021-10-07 07:12:24 +0000789}
790
Michael Forster500b4762022-01-27 12:30:17 +0000791SourceLoc Importer::ConvertSourceLocation(clang::SourceLocation loc) const {
Michael Forstera49d2e62022-01-28 07:26:40 +0000792 auto& sm = ctx_.getSourceManager();
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000793
Googlerc8a8e732021-10-19 07:49:24 +0000794 clang::StringRef filename = sm.getFilename(loc);
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000795 if (filename.startswith("./")) {
796 filename = filename.substr(2);
797 }
798
799 return SourceLoc{.filename = filename.str(),
800 .line = sm.getSpellingLineNumber(loc),
801 .column = sm.getSpellingColumnNumber(loc)};
802}
803
Michael Forster500b4762022-01-27 12:30:17 +0000804absl::StatusOr<MappedType> Importer::ConvertType(
Googler4e1bc132021-12-06 10:10:42 +0000805 clang::QualType qual_type,
806 std::optional<devtools_rust::TypeLifetimes> lifetimes,
807 bool nullable) const {
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000808 std::optional<MappedType> type = std::nullopt;
Googlerdb111532022-01-05 06:12:13 +0000809 // When converting the type to a string, don't include qualifiers -- we handle
810 // these separately.
811 std::string type_string = qual_type.getUnqualifiedType().getAsString();
Michael Forsterdc683af2021-09-17 08:51:28 +0000812
Googler44e3fbc2022-01-11 10:19:26 +0000813 if (auto iter = kWellKnownTypes.find(type_string);
814 iter != kWellKnownTypes.end()) {
Googler06f2c9a2022-01-05 12:00:47 +0000815 type = MappedType::Simple(std::string(iter->second), type_string);
816 } else if (const auto* pointer_type =
817 qual_type->getAs<clang::PointerType>()) {
Googler4e1bc132021-12-06 10:10:42 +0000818 std::optional<LifetimeId> lifetime;
819 if (lifetimes.has_value()) {
820 CHECK(!lifetimes->empty());
821 lifetime = LifetimeId(lifetimes->back().Id());
822 lifetimes->pop_back();
823 }
824 auto pointee_type = ConvertType(pointer_type->getPointeeType(), lifetimes);
Michael Forsterdc683af2021-09-17 08:51:28 +0000825 if (pointee_type.ok()) {
Googler4e1bc132021-12-06 10:10:42 +0000826 type = MappedType::PointerTo(*pointee_type, lifetime, nullable);
Michael Forster1de27b82021-09-17 07:22:22 +0000827 }
Googler61dce3b2021-12-02 09:16:32 +0000828 } else if (const auto* lvalue_ref_type =
829 qual_type->getAs<clang::LValueReferenceType>()) {
Googler4e1bc132021-12-06 10:10:42 +0000830 std::optional<LifetimeId> lifetime;
831 if (lifetimes.has_value()) {
832 CHECK(!lifetimes->empty());
833 lifetime = LifetimeId(lifetimes->back().Id());
834 lifetimes->pop_back();
835 }
836 auto pointee_type =
837 ConvertType(lvalue_ref_type->getPointeeType(), lifetimes);
Googler61dce3b2021-12-02 09:16:32 +0000838 if (pointee_type.ok()) {
Googler4e1bc132021-12-06 10:10:42 +0000839 type = MappedType::LValueReferenceTo(*pointee_type, lifetime);
Googler61dce3b2021-12-02 09:16:32 +0000840 }
Googlerb6c0fe02021-12-01 10:55:31 +0000841 } else if (const auto* builtin_type =
Googler06f2c9a2022-01-05 12:00:47 +0000842 // Use getAsAdjusted instead of getAs so we don't desugar
843 // typedefs.
844 qual_type->getAsAdjusted<clang::BuiltinType>()) {
Michael Forster51da81a2021-09-20 07:14:23 +0000845 switch (builtin_type->getKind()) {
846 case clang::BuiltinType::Bool:
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000847 type = MappedType::Simple("bool", "bool");
Michael Forster51da81a2021-09-20 07:14:23 +0000848 break;
849 case clang::BuiltinType::Float:
Michael Forsterc7976ec2021-10-01 10:05:16 +0000850 type = MappedType::Simple("f32", "float");
Michael Forster51da81a2021-09-20 07:14:23 +0000851 break;
852 case clang::BuiltinType::Double:
Michael Forsterc7976ec2021-10-01 10:05:16 +0000853 type = MappedType::Simple("f64", "double");
Michael Forster51da81a2021-09-20 07:14:23 +0000854 break;
855 case clang::BuiltinType::Void:
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000856 type = MappedType::Void();
Michael Forster51da81a2021-09-20 07:14:23 +0000857 break;
858 default:
859 if (builtin_type->isIntegerType()) {
Michael Forstera49d2e62022-01-28 07:26:40 +0000860 auto size = ctx_.getTypeSize(builtin_type);
Googler06f2c9a2022-01-05 12:00:47 +0000861 if (size == 8 || size == 16 || size == 32 || size == 64) {
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000862 type = MappedType::Simple(
Michael Forster51da81a2021-09-20 07:14:23 +0000863 absl::Substitute(
864 "$0$1", builtin_type->isSignedInteger() ? 'i' : 'u', size),
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000865 type_string);
Michael Forster51da81a2021-09-20 07:14:23 +0000866 }
867 }
Marcel Hlopko7d739792021-08-12 07:52:47 +0000868 }
Michael Forster365bba12022-01-24 16:56:06 +0000869 } else if (const auto* tag_type =
Googler6a0a5252022-01-11 14:08:09 +0000870 qual_type->getAsAdjusted<clang::TagType>()) {
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000871 clang::TagDecl* tag_decl = tag_type->getDecl();
872
Googlerdcca7f72022-01-10 12:30:43 +0000873 if (known_type_decls_.contains(tag_decl)) {
Googler279eca32022-01-04 14:03:44 +0000874 if (std::optional<Identifier> id = GetTranslatedIdentifier(tag_decl)) {
875 std::string ident(id->Ident());
876 DeclId decl_id = GenerateDeclId(tag_decl);
877 type = MappedType::WithDeclIds(ident, decl_id, ident, decl_id);
878 }
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000879 }
Michael Forster365bba12022-01-24 16:56:06 +0000880 } else if (const auto* typedef_type =
Googler6a0a5252022-01-11 14:08:09 +0000881 qual_type->getAsAdjusted<clang::TypedefType>()) {
Googlerdcca7f72022-01-10 12:30:43 +0000882 clang::TypedefNameDecl* typedef_name_decl = typedef_type->getDecl();
883
884 if (known_type_decls_.contains(typedef_name_decl)) {
885 if (std::optional<Identifier> id =
886 GetTranslatedIdentifier(typedef_name_decl)) {
887 std::string ident(id->Ident());
888 DeclId decl_id = GenerateDeclId(typedef_name_decl);
889 type = MappedType::WithDeclIds(ident, decl_id, ident, decl_id);
890 }
891 }
Marcel Hlopko7d739792021-08-12 07:52:47 +0000892 }
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000893
894 if (!type.has_value()) {
895 absl::Status error = absl::UnimplementedError(
896 absl::Substitute("Unsupported type '$0'", type_string));
897 error.SetPayload(kTypeStatusPayloadUrl, absl::Cord(type_string));
898 return error;
899 }
900
901 // Add cv-qualification.
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000902 type->cc_type.is_const = qual_type.isConstQualified();
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000903 // Not doing volatile for now -- note that volatile pointers do not exist in
904 // Rust, though volatile reads/writes still do.
905
906 return *std::move(type);
Marcel Hlopko7d739792021-08-12 07:52:47 +0000907}
908
Michael Forster500b4762022-01-27 12:30:17 +0000909absl::StatusOr<std::vector<Field>> Importer::ImportFields(
Devin Jeanpierred652d932022-02-03 08:55:33 +0000910 clang::CXXRecordDecl* record_decl) {
911 clang::AccessSpecifier default_access =
912 record_decl->isClass() ? clang::AS_private : clang::AS_public;
Googlere3434c32021-10-19 10:28:35 +0000913 std::vector<Field> fields;
Michael Forstera49d2e62022-01-28 07:26:40 +0000914 const clang::ASTRecordLayout& layout = ctx_.getASTRecordLayout(record_decl);
Googlere3434c32021-10-19 10:28:35 +0000915 for (const clang::FieldDecl* field_decl : record_decl->fields()) {
916 auto type = ConvertType(field_decl->getType());
917 if (!type.ok()) {
Michael Forster500b4762022-01-27 12:30:17 +0000918 return absl::UnimplementedError(
919 absl::Substitute("Field type '$0' is not supported",
920 field_decl->getType().getAsString()));
Googlere3434c32021-10-19 10:28:35 +0000921 }
922 clang::AccessSpecifier access = field_decl->getAccess();
923 if (access == clang::AS_none) {
924 access = default_access;
925 }
926
927 std::optional<Identifier> field_name = GetTranslatedIdentifier(field_decl);
928 if (!field_name.has_value()) {
Michael Forster500b4762022-01-27 12:30:17 +0000929 return absl::UnimplementedError(
Googler279eca32022-01-04 14:03:44 +0000930 absl::Substitute("Cannot translate name for field '$0'",
Michael Forster500b4762022-01-27 12:30:17 +0000931 field_decl->getNameAsString()));
Googlere3434c32021-10-19 10:28:35 +0000932 }
933 fields.push_back(
934 {.identifier = *std::move(field_name),
935 .doc_comment = GetComment(field_decl),
936 .type = *type,
937 .access = TranslateAccessSpecifier(access),
Devin Jeanpierreb69bcae2022-02-03 09:45:50 +0000938 .offset = layout.getFieldOffset(field_decl->getFieldIndex()),
939 .is_no_unique_address =
940 field_decl->hasAttr<clang::NoUniqueAddressAttr>()});
Googlere3434c32021-10-19 10:28:35 +0000941 }
942 return fields;
943}
944
Michael Forster500b4762022-01-27 12:30:17 +0000945std::string Importer::GetMangledName(const clang::NamedDecl* named_decl) const {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000946 clang::GlobalDecl decl;
947
948 // There are only three named decl types that don't work with the GlobalDecl
949 // unary constructor: GPU kernels (which do not exist in standard C++, so we
950 // ignore), constructors, and destructors. GlobalDecl does not support
951 // constructors and destructors from the unary constructor because there is
952 // more than one global declaration for a given constructor or destructor!
953 //
954 // * (Ctor|Dtor)_Complete is a function which constructs / destroys the
955 // entire object. This is what we want. :)
956 // * Dtor_Deleting is a function which additionally calls operator delete.
957 // * (Ctor|Dtor)_Base is a function which constructs/destroys the object but
958 // NOT including virtual base class subobjects.
959 // * (Ctor|Dtor)_Comdat: I *believe* this is the identifier used to
960 // deduplicate inline functions, and is not callable.
961 // * Dtor_(Copying|Default)Closure: These only exist in the MSVC++ ABI,
962 // which we don't support for now. I don't know when they are used.
963 //
964 // It was hard to piece this together, so writing it down here to explain why
965 // we magically picked the *_Complete variants.
Michael Forster500b4762022-01-27 12:30:17 +0000966 if (auto dtor = clang::dyn_cast<clang::CXXDestructorDecl>(named_decl)) {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000967 decl = clang::GlobalDecl(dtor, clang::CXXDtorType::Dtor_Complete);
968 } else if (auto ctor =
Michael Forster500b4762022-01-27 12:30:17 +0000969 clang::dyn_cast<clang::CXXConstructorDecl>(named_decl)) {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000970 decl = clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete);
971 } else {
972 decl = clang::GlobalDecl(named_decl);
973 }
974
Marcel Hlopko7d739792021-08-12 07:52:47 +0000975 std::string name;
976 llvm::raw_string_ostream stream(name);
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000977 mangler_->mangleName(decl, stream);
Marcel Hlopko7d739792021-08-12 07:52:47 +0000978 stream.flush();
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +0000979 return name;
Marcel Hlopko7d739792021-08-12 07:52:47 +0000980}
981
Michael Forster500b4762022-01-27 12:30:17 +0000982std::optional<UnqualifiedIdentifier> Importer::GetTranslatedName(
Marcel Hlopko7d739792021-08-12 07:52:47 +0000983 const clang::NamedDecl* named_decl) const {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000984 switch (named_decl->getDeclName().getNameKind()) {
985 case clang::DeclarationName::Identifier: {
986 auto name = std::string(named_decl->getName());
987 if (name.empty()) {
Lukasz Anforowicz0c816f12021-12-15 17:41:49 +0000988 if (const clang::ParmVarDecl* param_decl =
989 clang::dyn_cast<clang::ParmVarDecl>(named_decl)) {
990 int param_pos = param_decl->getFunctionScopeIndex();
991 return {Identifier(absl::StrCat("__param_", param_pos))};
992 }
993 // TODO(lukasza): Handle anonymous structs (probably this won't be an
994 // issue until nested types are handled - b/200067824).
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000995 return std::nullopt;
996 }
997 return {Identifier(std::move(name))};
998 }
999 case clang::DeclarationName::CXXConstructorName:
1000 return {SpecialName::kConstructor};
1001 case clang::DeclarationName::CXXDestructorName:
1002 return {SpecialName::kDestructor};
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +00001003 case clang::DeclarationName::CXXOperatorName:
1004 switch (named_decl->getDeclName().getCXXOverloadedOperator()) {
1005 case clang::OO_None:
1006 LOG(FATAL) << "No OO_None expected under CXXOperatorName branch";
1007 return std::nullopt;
1008 case clang::NUM_OVERLOADED_OPERATORS:
1009 LOG(FATAL) << "No NUM_OVERLOADED_OPERATORS expected at runtime";
1010 return std::nullopt;
1011 // clang-format off
1012 #define OVERLOADED_OPERATOR(name, spelling, ...) \
1013 case clang::OO_##name: { \
1014 std::string name = "operator"; \
1015 if ('a' <= spelling[0] && spelling[0] <= 'z') { \
1016 absl::StrAppend(&name, " "); \
1017 } \
1018 absl::StrAppend(&name, spelling); \
1019 return {Identifier(std::move(name))}; \
1020 }
1021 #include "third_party/llvm/llvm-project/clang/include/clang/Basic/OperatorKinds.def"
1022 #undef OVERLOADED_OPERATOR
1023 // clang-format on
1024 }
1025 LOG(FATAL) << "The `switch` above should handle all cases and `return`";
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001026 default:
Lukasz Anforowiczfae90a12022-02-03 20:58:15 +00001027 // To be implemented later: CXXConversionFunctionName.
Devin Jeanpierref2ec8712021-10-13 20:47:16 +00001028 // There are also e.g. literal operators, deduction guides, etc., but
1029 // we might not need to implement them at all. Full list at:
1030 // https://clang.llvm.org/doxygen/classclang_1_1DeclarationName.html#a9ab322d434446b43379d39e41af5cbe3
1031 return std::nullopt;
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +00001032 }
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +00001033}
1034
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +00001035} // namespace rs_bindings_from_cc