blob: c575cc94bf0c8be2b5da0702771b71a0f233edae [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
5#include "rs_bindings_from_cc/ast_visitor.h"
6
Marcel Hlopko9c150da2021-11-12 10:30:03 +00007#include <stdint.h>
8
Googler4e1bc132021-12-06 10:10:42 +00009#include <algorithm>
Marcel Hlopko7d739792021-08-12 07:52:47 +000010#include <memory>
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000011#include <optional>
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000012#include <string>
Michael Forster365bba12022-01-24 16:56:06 +000013#include <tuple>
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000014#include <utility>
15#include <variant>
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"
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +000028#include "third_party/absl/strings/string_view.h"
Michael Forster1de27b82021-09-17 07:22:22 +000029#include "third_party/absl/strings/substitute.h"
Marcel Hlopko7d739792021-08-12 07:52:47 +000030#include "third_party/llvm/llvm-project/clang/include/clang/AST/ASTContext.h"
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000031#include "third_party/llvm/llvm-project/clang/include/clang/AST/Decl.h"
Googler2e85f342021-09-17 07:04:07 +000032#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclCXX.h"
Googler846e1fc2022-01-10 13:14:57 +000033#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclTemplate.h"
Marcel Hlopko7d739792021-08-12 07:52:47 +000034#include "third_party/llvm/llvm-project/clang/include/clang/AST/Mangle.h"
Michael Forster028800b2021-10-05 12:39:59 +000035#include "third_party/llvm/llvm-project/clang/include/clang/AST/RawCommentList.h"
Googler6986c072021-09-17 13:54:56 +000036#include "third_party/llvm/llvm-project/clang/include/clang/AST/RecordLayout.h"
Marcel Hlopko7d739792021-08-12 07:52:47 +000037#include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
Michael Forster6a184ad2021-10-12 13:04:05 +000038#include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceLocation.h"
Michael Forster028800b2021-10-05 12:39:59 +000039#include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceManager.h"
Googler2e85f342021-09-17 07:04:07 +000040#include "third_party/llvm/llvm-project/clang/include/clang/Basic/Specifiers.h"
Marcel Hlopko20f4ce42021-11-02 08:20:00 +000041#include "third_party/llvm/llvm-project/clang/include/clang/Sema/Sema.h"
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +000042#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/Optional.h"
Marcel Hlopkob4b28742021-09-15 12:45:20 +000043#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Casting.h"
Googler06f2c9a2022-01-05 12:00:47 +000044#include "util/gtl/flat_map.h"
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000045
46namespace rs_bindings_from_cc {
47
Michael Forsterb836c582022-01-21 11:20:22 +000048constexpr absl::string_view kTypeStatusPayloadUrl =
Michael Forsterdc683af2021-09-17 08:51:28 +000049 "type.googleapis.com/devtools.rust.cc_interop.rs_binding_from_cc.type";
50
Googler44e3fbc2022-01-11 10:19:26 +000051// A mapping of C++ standard types to their equivalent Rust types.
52// To produce more idiomatic results, these types receive special handling
53// instead of using the generic type mapping mechanism.
54static constexpr auto kWellKnownTypes =
55 gtl::fixed_flat_map_of<absl::string_view, absl::string_view>({
56 {"ptrdiff_t", "isize"},
57 {"intptr_t", "isize"},
58 {"size_t", "usize"},
59 {"uintptr_t", "usize"},
Googler4e504882022-01-13 10:03:19 +000060 {"std::ptrdiff_t", "isize"},
61 {"std::intptr_t", "isize"},
62 {"std::size_t", "usize"},
63 {"std::uintptr_t", "usize"},
64
Googler44e3fbc2022-01-11 10:19:26 +000065 {"int8_t", "i8"},
Googler44e3fbc2022-01-11 10:19:26 +000066 {"int16_t", "i16"},
Googler44e3fbc2022-01-11 10:19:26 +000067 {"int32_t", "i32"},
Googler44e3fbc2022-01-11 10:19:26 +000068 {"int64_t", "i64"},
Googler4e504882022-01-13 10:03:19 +000069 {"std::int8_t", "i8"},
70 {"std::int16_t", "i16"},
71 {"std::int32_t", "i32"},
72 {"std::int64_t", "i64"},
73
74 {"uint8_t", "u8"},
75 {"uint16_t", "u16"},
76 {"uint32_t", "u32"},
Googler44e3fbc2022-01-11 10:19:26 +000077 {"uint64_t", "u64"},
Googler4e504882022-01-13 10:03:19 +000078 {"std::uint8_t", "u8"},
79 {"std::uint16_t", "u16"},
80 {"std::uint32_t", "u32"},
81 {"std::uint64_t", "u64"},
82
Googler44e3fbc2022-01-11 10:19:26 +000083 {"char16_t", "u16"},
84 {"char32_t", "u32"},
85 {"wchar_t", "i32"},
86 });
87
Marcel Hlopko264b9ad2021-12-02 21:06:44 +000088static DeclId GenerateDeclId(const clang::Decl* decl) {
Marcel Hlopko9c150da2021-11-12 10:30:03 +000089 return DeclId(reinterpret_cast<uintptr_t>(decl->getCanonicalDecl()));
90}
91
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +000092bool AstVisitor::TraverseDecl(clang::Decl* decl) {
Googleracea5b92022-01-04 14:00:31 +000093 // TODO(mboehme): I'm not sure if TraverseDecl() is supposed to be called with
94 // null pointers or whether this is a bug in RecursiveASTVisitor, but I've
95 // seen null pointers occur here in practice. In the case where this occurred,
96 // TraverseDecl was being called from TraverseTemplateTemplateParmDecl().
97 if (!decl) {
98 return true;
99 }
100
Googlere0a94782022-01-04 14:06:02 +0000101 // Skip declarations that we've already seen, except for namespaces, which
102 // can and typically will contain new declarations when they are "reopened".
Michael Forster365bba12022-01-24 16:56:06 +0000103 if (seen_decls_.contains(decl->getCanonicalDecl()) &&
Googlere0a94782022-01-04 14:06:02 +0000104 !clang::isa<clang::NamespaceDecl>(decl)) {
Googlerc8a8e732021-10-19 07:49:24 +0000105 return true;
Marcel Hlopko7d739792021-08-12 07:52:47 +0000106 }
Googlerc8a8e732021-10-19 07:49:24 +0000107
Googlerc68cd5a2021-10-19 09:02:56 +0000108 const clang::DeclContext* decl_context = decl->getDeclContext();
109 if (decl_context && decl_context->isNamespace()) {
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000110 PushUnsupportedItem(decl,
Marcel Hlopko3df72542021-11-30 09:38:36 +0000111 "Items contained in namespaces are not supported yet",
112 decl->getBeginLoc());
113
Googlerc8a8e732021-10-19 07:49:24 +0000114 return true;
115 }
116
117 // Emit all comments in the current file before the decl
118 comment_manager_.TraverseDecl(decl);
119
120 return Base::TraverseDecl(decl);
Marcel Hlopko7d739792021-08-12 07:52:47 +0000121}
122
123bool AstVisitor::TraverseTranslationUnitDecl(
124 clang::TranslationUnitDecl* translation_unit_decl) {
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000125 ctx_ = &translation_unit_decl->getASTContext();
126 mangler_.reset(ctx_->createMangleContext());
Marcel Hlopkof1123c82021-08-19 11:38:52 +0000127
Marcel Hlopko7aa38a72021-11-11 07:39:51 +0000128 for (const HeaderName& header_name : public_header_names_) {
129 ir_.used_headers.push_back(header_name);
Marcel Hlopkof1123c82021-08-19 11:38:52 +0000130 }
131
Marcel Hlopko80441c12021-11-12 10:43:18 +0000132 ir_.current_target = current_target_;
133
Michael Forsterf1dce422021-10-13 09:50:16 +0000134 bool result = Base::TraverseTranslationUnitDecl(translation_unit_decl);
135
136 // Emit comments after the last decl
137 comment_manager_.FlushComments();
138
Michael Forster365bba12022-01-24 16:56:06 +0000139 EmitIRItems();
140
Michael Forsterf1dce422021-10-13 09:50:16 +0000141 return result;
Marcel Hlopko7d739792021-08-12 07:52:47 +0000142}
143
Michael Forster365bba12022-01-24 16:56:06 +0000144void AstVisitor::EmitIRItems() {
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000145 using OrderedItem = std::tuple<clang::SourceRange, int, IR::Item>;
146 clang::SourceManager& sm = ctx_->getSourceManager();
147 auto is_less_than = [&sm](const OrderedItem& a, const OrderedItem& b) {
148 auto a_range = std::get<0>(a);
149 auto b_range = std::get<0>(b);
150
151 if (!a_range.isValid() || !b_range.isValid()) {
152 if (a_range.isValid() != b_range.isValid())
153 return !a_range.isValid() && b_range.isValid();
154 } else {
155 if (a_range.getBegin() != b_range.getBegin()) {
156 return sm.isBeforeInTranslationUnit(a_range.getBegin(),
157 b_range.getBegin());
158 }
159 if (a_range.getEnd() != b_range.getEnd()) {
160 return sm.isBeforeInTranslationUnit(a_range.getEnd(), b_range.getEnd());
161 }
162 }
163 return std::get<1>(a) < std::get<1>(b);
164 };
Michael Forster365bba12022-01-24 16:56:06 +0000165
166 // We emit IR items in the order of the decls they were generated for.
167 // For decls that emit multiple items we use a stable, but arbitrary order.
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000168 std::vector<OrderedItem> items;
Michael Forster365bba12022-01-24 16:56:06 +0000169 for (const auto& [decl, decl_items] : seen_decls_) {
170 for (const auto& decl_item : decl_items) {
171 int local_order;
172
173 if (clang::isa<clang::RecordDecl>(decl)) {
174 local_order = decl->getDeclContext()->isRecord() ? 1 : 0;
175 } else if (auto ctor = clang::dyn_cast<clang::CXXConstructorDecl>(decl)) {
176 local_order = ctor->isDefaultConstructor() ? 2
177 : ctor->isCopyConstructor() ? 3
178 : ctor->isMoveConstructor() ? 4
179 : 5;
180 } else if (clang::isa<clang::CXXDestructorDecl>(decl)) {
181 local_order = 6;
182 } else {
183 local_order = 7;
184 }
185
186 items.push_back(
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000187 std::make_tuple(decl->getSourceRange(), local_order, decl_item));
Michael Forster365bba12022-01-24 16:56:06 +0000188 }
189 }
Michael Forster365bba12022-01-24 16:56:06 +0000190 for (auto comment : comment_manager_.comments()) {
191 items.push_back(std::make_tuple(
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000192 comment->getSourceRange(), 0 /* local_order */,
Michael Forster365bba12022-01-24 16:56:06 +0000193 Comment{.text = comment->getFormattedText(sm, sm.getDiagnostics())}));
194 }
Lukasz Anforowiczbdf70d32022-01-26 19:06:21 +0000195 std::stable_sort(items.begin(), items.end(), is_less_than);
Michael Forster365bba12022-01-24 16:56:06 +0000196
197 for (const auto& item : items) {
198 ir_.items.push_back(std::get<2>(item));
199 }
200}
201
Marcel Hlopko7d739792021-08-12 07:52:47 +0000202bool AstVisitor::VisitFunctionDecl(clang::FunctionDecl* function_decl) {
Marcel Hlopko36ced2d2021-12-02 10:47:37 +0000203 if (!IsFromCurrentTarget(function_decl)) return true;
Lukasz Anforowicz0a1b4802021-12-22 15:30:56 +0000204 if (function_decl->isDeleted()) return true;
Marcel Hlopko3df195b2022-01-26 14:15:03 +0000205 if (function_decl->isTemplated()) {
206 PushUnsupportedItem(function_decl,
207 "Function templates are not supported yet",
208 function_decl->getBeginLoc());
209 }
Marcel Hlopko36ced2d2021-12-02 10:47:37 +0000210
Googler4e1bc132021-12-06 10:10:42 +0000211 devtools_rust::LifetimeSymbolTable lifetime_symbol_table;
212 llvm::Expected<devtools_rust::FunctionLifetimes> lifetimes =
213 devtools_rust::GetLifetimeAnnotations(function_decl, lifetime_context_,
214 &lifetime_symbol_table);
215 llvm::DenseSet<devtools_rust::Lifetime> all_lifetimes;
216
Marcel Hlopko7d739792021-08-12 07:52:47 +0000217 std::vector<FuncParam> params;
Michael Forster523dbd42021-10-12 11:05:44 +0000218 bool success = true;
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000219 // non-static member functions receive an implicit `this` parameter.
220 if (auto* method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(function_decl)) {
221 if (method_decl->isInstance()) {
Googler4e1bc132021-12-06 10:10:42 +0000222 std::optional<devtools_rust::TypeLifetimes> this_lifetimes;
223 if (lifetimes) {
224 this_lifetimes = lifetimes->this_lifetimes;
225 all_lifetimes.insert(this_lifetimes->begin(), this_lifetimes->end());
226 }
227 auto param_type = ConvertType(method_decl->getThisType(), this_lifetimes,
228 /*nullable=*/false);
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000229 if (!param_type.ok()) {
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000230 PushUnsupportedItem(function_decl, param_type.status().ToString(),
Marcel Hlopko3df72542021-11-30 09:38:36 +0000231 method_decl->getBeginLoc());
232
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000233 success = false;
Devin Jeanpierrefecf5472021-10-27 10:52:30 +0000234 } else {
235 params.push_back({*std::move(param_type), Identifier("__this")});
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000236 }
Devin Jeanpierred4dde0e2021-10-13 20:48:25 +0000237 }
238 }
Michael Forster523dbd42021-10-12 11:05:44 +0000239
Googler4e1bc132021-12-06 10:10:42 +0000240 if (lifetimes) {
241 CHECK_EQ(lifetimes->param_lifetimes.size(), function_decl->getNumParams());
242 }
243 for (unsigned i = 0; i < function_decl->getNumParams(); ++i) {
244 const clang::ParmVarDecl* param = function_decl->getParamDecl(i);
245 std::optional<devtools_rust::TypeLifetimes> param_lifetimes;
246 if (lifetimes) {
247 param_lifetimes = lifetimes->param_lifetimes[i];
248 all_lifetimes.insert(param_lifetimes->begin(), param_lifetimes->end());
249 }
250 auto param_type = ConvertType(param->getType(), param_lifetimes);
Michael Forsterdc683af2021-09-17 08:51:28 +0000251 if (!param_type.ok()) {
Marcel Hlopko3df72542021-11-30 09:38:36 +0000252 PushUnsupportedItem(
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000253 function_decl,
Marcel Hlopko3df72542021-11-30 09:38:36 +0000254 absl::Substitute("Parameter type '$0' is not supported",
255 param->getType().getAsString()),
256 param->getBeginLoc());
Michael Forster523dbd42021-10-12 11:05:44 +0000257 success = false;
258 continue;
Michael Forster1de27b82021-09-17 07:22:22 +0000259 }
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000260
261 if (const clang::RecordType* record_type =
262 llvm::dyn_cast<clang::RecordType>(param->getType())) {
263 if (clang::RecordDecl* record_decl =
264 llvm::dyn_cast<clang::RecordDecl>(record_type->getDecl())) {
265 // TODO(b/200067242): non-trivial_abi structs, when passed by value,
266 // have a different representation which needs special support. We
267 // currently do not support it.
268 if (!record_decl->canPassInRegisters()) {
Marcel Hlopko3df72542021-11-30 09:38:36 +0000269 PushUnsupportedItem(
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000270 function_decl,
Marcel Hlopko3df72542021-11-30 09:38:36 +0000271 absl::Substitute("Non-trivial_abi type '$0' is not "
272 "supported by value as a parameter",
273 param->getType().getAsString()),
274 param->getBeginLoc());
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000275 success = false;
276 }
277 }
278 }
279
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000280 std::optional<Identifier> param_name = GetTranslatedIdentifier(param);
Lukasz Anforowicz0c816f12021-12-15 17:41:49 +0000281 CHECK(param_name.has_value()); // No known cases where the above can fail.
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000282 params.push_back({*param_type, *std::move(param_name)});
Marcel Hlopko7d739792021-08-12 07:52:47 +0000283 }
284
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000285 if (const clang::RecordType* record_return_type =
286 llvm::dyn_cast<clang::RecordType>(function_decl->getReturnType())) {
287 if (clang::RecordDecl* record_decl =
288 llvm::dyn_cast<clang::RecordDecl>(record_return_type->getDecl())) {
289 // TODO(b/200067242): non-trivial_abi structs, when passed by value,
290 // have a different representation which needs special support. We
291 // currently do not support it.
292 if (!record_decl->canPassInRegisters()) {
Marcel Hlopko3df72542021-11-30 09:38:36 +0000293 PushUnsupportedItem(
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000294 function_decl,
Marcel Hlopko3df72542021-11-30 09:38:36 +0000295 absl::Substitute("Non-trivial_abi type '$0' is not supported "
296 "by value as a return type",
297 function_decl->getReturnType().getAsString()),
298 function_decl->getReturnTypeSourceRange());
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000299 success = false;
300 }
301 }
302 }
303
Googler4e1bc132021-12-06 10:10:42 +0000304 std::optional<devtools_rust::TypeLifetimes> return_lifetimes;
305 if (lifetimes) {
306 return_lifetimes = lifetimes->return_lifetimes;
307 all_lifetimes.insert(return_lifetimes->begin(), return_lifetimes->end());
308 }
309 auto return_type =
310 ConvertType(function_decl->getReturnType(), return_lifetimes);
Michael Forsterdc683af2021-09-17 08:51:28 +0000311 if (!return_type.ok()) {
Marcel Hlopko3df72542021-11-30 09:38:36 +0000312 PushUnsupportedItem(
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000313 function_decl,
Marcel Hlopko3df72542021-11-30 09:38:36 +0000314 absl::Substitute("Return type '$0' is not supported",
315 function_decl->getReturnType().getAsString()),
316 function_decl->getReturnTypeSourceRange());
Michael Forster523dbd42021-10-12 11:05:44 +0000317 success = false;
Michael Forster1de27b82021-09-17 07:22:22 +0000318 }
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000319
Googler4e1bc132021-12-06 10:10:42 +0000320 std::vector<Lifetime> lifetime_params;
321 for (devtools_rust::Lifetime lifetime : all_lifetimes) {
322 std::optional<llvm::StringRef> name =
323 lifetime_symbol_table.LookupLifetime(lifetime);
324 CHECK(name.has_value());
325 lifetime_params.push_back(
326 {.name = name->str(), .id = LifetimeId(lifetime.Id())});
327 }
328 std::sort(
329 lifetime_params.begin(), lifetime_params.end(),
330 [](const Lifetime& l1, const Lifetime& l2) { return l1.name < l2.name; });
331
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000332 std::optional<MemberFuncMetadata> member_func_metadata;
333 if (auto* method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(function_decl)) {
Lukasz Anforowicz57331cf2021-12-16 02:57:19 +0000334 switch (method_decl->getAccess()) {
335 case clang::AS_public:
336 break;
337 case clang::AS_protected:
338 case clang::AS_private:
339 case clang::AS_none:
340 // No need for IR to include Func representing private methods.
341 // TODO(lukasza): Revisit this for protected methods.
342 return true;
343 }
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000344 std::optional<MemberFuncMetadata::InstanceMethodMetadata> instance_metadata;
345 if (method_decl->isInstance()) {
346 MemberFuncMetadata::ReferenceQualification reference;
347 switch (method_decl->getRefQualifier()) {
348 case clang::RQ_LValue:
349 reference = MemberFuncMetadata::kLValue;
350 break;
351 case clang::RQ_RValue:
352 reference = MemberFuncMetadata::kRValue;
353 break;
354 case clang::RQ_None:
355 reference = MemberFuncMetadata::kUnqualified;
356 break;
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000357 }
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000358 instance_metadata = MemberFuncMetadata::InstanceMethodMetadata{
359 .reference = reference,
360 .is_const = method_decl->isConst(),
361 .is_virtual = method_decl->isVirtual(),
Lukasz Anforowicz71716b72022-01-26 17:05:05 +0000362 .is_explicit_ctor = false,
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000363 };
Lukasz Anforowicz71716b72022-01-26 17:05:05 +0000364 if (auto* ctor_decl =
365 llvm::dyn_cast<clang::CXXConstructorDecl>(function_decl)) {
366 instance_metadata->is_explicit_ctor = ctor_decl->isExplicit();
367 }
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000368 }
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000369
370 member_func_metadata = MemberFuncMetadata{
371 .record_id = GenerateDeclId(method_decl->getParent()),
372 .instance_method_metadata = instance_metadata};
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000373 }
374
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000375 std::optional<UnqualifiedIdentifier> translated_name =
376 GetTranslatedName(function_decl);
Michael Forster523dbd42021-10-12 11:05:44 +0000377 if (success && translated_name.has_value()) {
Michael Forster365bba12022-01-24 16:56:06 +0000378 seen_decls_[function_decl->getCanonicalDecl()].push_back(Func{
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000379 .name = *translated_name,
Marcel Hlopko80441c12021-11-12 10:43:18 +0000380 .owning_target = GetOwningTarget(function_decl),
Michael Forster523dbd42021-10-12 11:05:44 +0000381 .doc_comment = GetComment(function_decl),
382 .mangled_name = GetMangledName(function_decl),
383 .return_type = *return_type,
384 .params = std::move(params),
Googler4e1bc132021-12-06 10:10:42 +0000385 .lifetime_params = std::move(lifetime_params),
Michael Forster523dbd42021-10-12 11:05:44 +0000386 .is_inline = function_decl->isInlined(),
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000387 .member_func_metadata = std::move(member_func_metadata),
Googler95f29a12022-01-07 07:47:26 +0000388 .source_loc = ConvertSourceLocation(function_decl->getBeginLoc()),
Michael Forster523dbd42021-10-12 11:05:44 +0000389 });
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000390 }
Michael Forster523dbd42021-10-12 11:05:44 +0000391
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +0000392 return true;
393}
394
Googlere05154d2022-01-10 08:39:03 +0000395BlazeLabel AstVisitor::GetOwningTarget(const clang::Decl* decl) const {
Marcel Hlopko80441c12021-11-12 10:43:18 +0000396 clang::SourceManager& source_manager = ctx_->getSourceManager();
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000397 auto source_location = decl->getLocation();
398 auto id = source_manager.getFileID(source_location);
Marcel Hlopko80441c12021-11-12 10:43:18 +0000399
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000400 // If the header this decl comes from is not associated with a target we
401 // consider it a textual header. In that case we go up the include stack
402 // until we find a header that has an owning target.
403
404 // TODO(b/208377928): We currently don't have a target for the headers in
405 // Clang's resource directory, so for the time being we return a fictional
406 // "//:virtual_clang_resource_dir_target" for system headers.
407 while (source_location.isValid() &&
408 !source_manager.isInSystemHeader(source_location)) {
409 llvm::Optional<llvm::StringRef> filename =
410 source_manager.getNonBuiltinFilenameForID(id);
411 if (!filename) {
412 return BlazeLabel("//:builtin");
413 }
414 if (filename->startswith("./")) {
415 filename = filename->substr(2);
416 }
417 auto target_iterator =
418 headers_to_targets_.find(HeaderName(filename->str()));
419 if (target_iterator != headers_to_targets_.end()) {
420 return target_iterator->second;
421 }
422 source_location = source_manager.getIncludeLoc(id);
423 id = source_manager.getFileID(source_location);
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000424 }
Rosica Dejanovskad0fc2942022-01-21 11:26:00 +0000425
426 return BlazeLabel("//:virtual_clang_resource_dir_target");
Marcel Hlopko80441c12021-11-12 10:43:18 +0000427}
428
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000429bool AstVisitor::IsFromCurrentTarget(const clang::Decl* decl) const {
430 return current_target_ == GetOwningTarget(decl);
431}
432
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000433bool AstVisitor::VisitRecordDecl(clang::RecordDecl* record_decl) {
Googler21351fc2021-10-19 08:58:04 +0000434 const clang::DeclContext* decl_context = record_decl->getDeclContext();
Googler648adff2022-01-10 13:14:06 +0000435 if (decl_context) {
436 if (decl_context->isFunctionOrMethod()) {
437 return true;
438 }
Marcel Hlopkod7f76ff2022-01-26 14:08:19 +0000439 if (record_decl->isInjectedClassName()) {
440 return true;
441 }
Googler648adff2022-01-10 13:14:06 +0000442 if (decl_context->isRecord()) {
443 PushUnsupportedItem(record_decl, "Nested classes are not supported yet",
444 record_decl->getBeginLoc());
445 return true;
446 }
Googler21351fc2021-10-19 08:58:04 +0000447 }
448
Marcel Hlopko872df5e2022-01-25 21:18:55 +0000449 if (record_decl->isUnion()) {
450 PushUnsupportedItem(record_decl, "Unions are not supported yet",
451 record_decl->getBeginLoc());
452 return true;
453 }
454
Googler8173f592022-01-04 13:57:32 +0000455 // Make sure the record has a definition that we'll be able to call
456 // ASTContext::getASTRecordLayout() on.
457 record_decl = record_decl->getDefinition();
458 if (!record_decl || record_decl->isInvalidDecl() ||
459 !record_decl->isCompleteDefinition()) {
460 return true;
461 }
462
Googler2e85f342021-09-17 07:04:07 +0000463 clang::AccessSpecifier default_access = clang::AS_public;
Devin Jeanpierre1ad7d552021-10-27 18:45:49 +0000464
Devin Jeanpierree6e16652021-12-22 15:54:46 +0000465 bool is_final = true;
Devin Jeanpierre296c6072021-10-27 10:53:05 +0000466 if (auto* cxx_record_decl =
Googler2e85f342021-09-17 07:04:07 +0000467 clang::dyn_cast<clang::CXXRecordDecl>(record_decl)) {
Googler846e1fc2022-01-10 13:14:57 +0000468 if (cxx_record_decl->getDescribedClassTemplate() ||
469 clang::isa<clang::ClassTemplateSpecializationDecl>(record_decl)) {
470 PushUnsupportedItem(record_decl, "Class templates are not supported yet",
471 record_decl->getBeginLoc());
472 return true;
473 }
474
Devin Jeanpierre296c6072021-10-27 10:53:05 +0000475 sema_.ForceDeclarationOfImplicitMembers(cxx_record_decl);
Googler2e85f342021-09-17 07:04:07 +0000476 if (cxx_record_decl->isClass()) {
477 default_access = clang::AS_private;
478 }
Devin Jeanpierree6e16652021-12-22 15:54:46 +0000479 is_final = cxx_record_decl->isEffectivelyFinal();
Googler2e85f342021-09-17 07:04:07 +0000480 }
Googler279eca32022-01-04 14:03:44 +0000481 std::optional<Identifier> record_name = GetTranslatedIdentifier(record_decl);
482 if (!record_name.has_value()) {
483 return true;
484 }
485 // Provisionally assume that we know this RecordDecl so that we'll be able
486 // to import fields whose type contains the record itself.
Googlerdcca7f72022-01-10 12:30:43 +0000487 known_type_decls_.insert(record_decl);
Googlere3434c32021-10-19 10:28:35 +0000488 std::optional<std::vector<Field>> fields =
489 ImportFields(record_decl, default_access);
490 if (!fields.has_value()) {
Googler279eca32022-01-04 14:03:44 +0000491 // Importing a field failed, so note that we didn't import this RecordDecl
492 // after all.
Googlerdcca7f72022-01-10 12:30:43 +0000493 known_type_decls_.erase(record_decl);
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000494 return true;
495 }
Googlere3434c32021-10-19 10:28:35 +0000496 const clang::ASTRecordLayout& layout = ctx_->getASTRecordLayout(record_decl);
Michael Forster365bba12022-01-24 16:56:06 +0000497 seen_decls_[record_decl->getCanonicalDecl()].push_back(
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000498 Record{.identifier = *record_name,
Marcel Hlopko264b9ad2021-12-02 21:06:44 +0000499 .id = GenerateDeclId(record_decl),
Marcel Hlopko80441c12021-11-12 10:43:18 +0000500 .owning_target = GetOwningTarget(record_decl),
Michael Forstercc5941a2021-10-07 07:12:24 +0000501 .doc_comment = GetComment(record_decl),
Googlere3434c32021-10-19 10:28:35 +0000502 .fields = *std::move(fields),
Michael Forster7ef80732021-10-01 18:12:19 +0000503 .size = layout.getSize().getQuantity(),
504 .alignment = layout.getAlignment().getQuantity(),
Devin Jeanpierre1ad7d552021-10-27 18:45:49 +0000505 .copy_constructor = GetCopyCtorSpecialMemberFunc(*record_decl),
506 .move_constructor = GetMoveCtorSpecialMemberFunc(*record_decl),
507 .destructor = GetDestructorSpecialMemberFunc(*record_decl),
Devin Jeanpierree6e16652021-12-22 15:54:46 +0000508 .is_trivial_abi = record_decl->canPassInRegisters(),
509 .is_final = is_final});
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000510 return true;
511}
512
Googler68346992022-01-05 06:11:31 +0000513bool AstVisitor::VisitTypedefNameDecl(
514 clang::TypedefNameDecl* typedef_name_decl) {
Googlerdcca7f72022-01-10 12:30:43 +0000515 const clang::DeclContext* decl_context = typedef_name_decl->getDeclContext();
516 if (decl_context) {
517 if (decl_context->isFunctionOrMethod()) {
518 return true;
519 }
520 if (decl_context->isRecord()) {
521 PushUnsupportedItem(typedef_name_decl,
522 "Typedefs nested in classes are not supported yet",
523 typedef_name_decl->getBeginLoc());
524 return true;
525 }
526 }
527
Googler44e3fbc2022-01-11 10:19:26 +0000528 clang::QualType type =
529 typedef_name_decl->getASTContext().getTypedefType(typedef_name_decl);
530 if (kWellKnownTypes.contains(type.getAsString())) {
531 return true;
532 }
533
Googlerdcca7f72022-01-10 12:30:43 +0000534 std::optional<Identifier> identifier =
535 GetTranslatedIdentifier(typedef_name_decl);
536 if (!identifier.has_value()) {
537 // This should never happen.
538 LOG(FATAL) << "Couldn't get identifier for TypedefNameDecl";
539 return true;
540 }
541 absl::StatusOr<MappedType> underlying_type =
542 ConvertType(typedef_name_decl->getUnderlyingType());
543 if (underlying_type.ok()) {
544 known_type_decls_.insert(typedef_name_decl);
Michael Forster365bba12022-01-24 16:56:06 +0000545 seen_decls_[typedef_name_decl->getCanonicalDecl()].push_back(
Googlerdcca7f72022-01-10 12:30:43 +0000546 TypeAlias{.identifier = *identifier,
547 .id = GenerateDeclId(typedef_name_decl),
548 .owning_target = GetOwningTarget(typedef_name_decl),
549 .underlying_type = *underlying_type});
550 } else {
551 PushUnsupportedItem(typedef_name_decl, underlying_type.status().ToString(),
552 typedef_name_decl->getBeginLoc());
553 }
Googler68346992022-01-05 06:11:31 +0000554 return true;
555}
556
Michael Forstercc5941a2021-10-07 07:12:24 +0000557std::optional<std::string> AstVisitor::GetComment(
558 const clang::Decl* decl) const {
Michael Forster409d9412021-10-07 08:35:29 +0000559 // This does currently not distinguish between different types of comments.
560 // In general it is not possible in C++ to reliably only extract doc comments.
561 // This is going to be a heuristic that needs to be tuned over time.
562
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000563 clang::SourceManager& sm = ctx_->getSourceManager();
564 clang::RawComment* raw_comment = ctx_->getRawCommentForDeclNoCache(decl);
Michael Forstercc5941a2021-10-07 07:12:24 +0000565
566 if (raw_comment == nullptr) {
567 return {};
568 } else {
569 return raw_comment->getFormattedText(sm, sm.getDiagnostics());
570 }
571}
572
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000573void AstVisitor::PushUnsupportedItem(const clang::Decl* decl,
574 std::string message,
Marcel Hlopko3df72542021-11-30 09:38:36 +0000575 clang::SourceLocation source_location) {
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000576 if (!IsFromCurrentTarget(decl)) return;
577
578 std::string name = "unnamed";
579 if (const auto* named_decl = llvm::dyn_cast<clang::NamedDecl>(decl)) {
580 name = named_decl->getQualifiedNameAsString();
581 }
Michael Forster365bba12022-01-24 16:56:06 +0000582 seen_decls_[decl->getCanonicalDecl()].push_back(UnsupportedItem{
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000583 .name = std::move(name),
584 .message = std::move(message),
585 .source_loc = ConvertSourceLocation(std::move(source_location))});
Marcel Hlopko3df72542021-11-30 09:38:36 +0000586}
587
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000588void AstVisitor::PushUnsupportedItem(const clang::Decl* decl,
589 std::string message,
Marcel Hlopko3df72542021-11-30 09:38:36 +0000590 clang::SourceRange source_range) {
Marcel Hlopko4c660dd2021-12-02 09:52:47 +0000591 PushUnsupportedItem(decl, message, source_range.getBegin());
Marcel Hlopko3df72542021-11-30 09:38:36 +0000592}
593
594SourceLoc AstVisitor::ConvertSourceLocation(clang::SourceLocation loc) const {
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000595 auto& sm = ctx_->getSourceManager();
596
Googlerc8a8e732021-10-19 07:49:24 +0000597 clang::StringRef filename = sm.getFilename(loc);
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000598 if (filename.startswith("./")) {
599 filename = filename.substr(2);
600 }
601
602 return SourceLoc{.filename = filename.str(),
603 .line = sm.getSpellingLineNumber(loc),
604 .column = sm.getSpellingColumnNumber(loc)};
605}
606
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000607absl::StatusOr<MappedType> AstVisitor::ConvertType(
Googler4e1bc132021-12-06 10:10:42 +0000608 clang::QualType qual_type,
609 std::optional<devtools_rust::TypeLifetimes> lifetimes,
610 bool nullable) const {
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000611 std::optional<MappedType> type = std::nullopt;
Googlerdb111532022-01-05 06:12:13 +0000612 // When converting the type to a string, don't include qualifiers -- we handle
613 // these separately.
614 std::string type_string = qual_type.getUnqualifiedType().getAsString();
Michael Forsterdc683af2021-09-17 08:51:28 +0000615
Googler44e3fbc2022-01-11 10:19:26 +0000616 if (auto iter = kWellKnownTypes.find(type_string);
617 iter != kWellKnownTypes.end()) {
Googler06f2c9a2022-01-05 12:00:47 +0000618 type = MappedType::Simple(std::string(iter->second), type_string);
619 } else if (const auto* pointer_type =
620 qual_type->getAs<clang::PointerType>()) {
Googler4e1bc132021-12-06 10:10:42 +0000621 std::optional<LifetimeId> lifetime;
622 if (lifetimes.has_value()) {
623 CHECK(!lifetimes->empty());
624 lifetime = LifetimeId(lifetimes->back().Id());
625 lifetimes->pop_back();
626 }
627 auto pointee_type = ConvertType(pointer_type->getPointeeType(), lifetimes);
Michael Forsterdc683af2021-09-17 08:51:28 +0000628 if (pointee_type.ok()) {
Googler4e1bc132021-12-06 10:10:42 +0000629 type = MappedType::PointerTo(*pointee_type, lifetime, nullable);
Michael Forster1de27b82021-09-17 07:22:22 +0000630 }
Googler61dce3b2021-12-02 09:16:32 +0000631 } else if (const auto* lvalue_ref_type =
632 qual_type->getAs<clang::LValueReferenceType>()) {
Googler4e1bc132021-12-06 10:10:42 +0000633 std::optional<LifetimeId> lifetime;
634 if (lifetimes.has_value()) {
635 CHECK(!lifetimes->empty());
636 lifetime = LifetimeId(lifetimes->back().Id());
637 lifetimes->pop_back();
638 }
639 auto pointee_type =
640 ConvertType(lvalue_ref_type->getPointeeType(), lifetimes);
Googler61dce3b2021-12-02 09:16:32 +0000641 if (pointee_type.ok()) {
Googler4e1bc132021-12-06 10:10:42 +0000642 type = MappedType::LValueReferenceTo(*pointee_type, lifetime);
Googler61dce3b2021-12-02 09:16:32 +0000643 }
Googlerb6c0fe02021-12-01 10:55:31 +0000644 } else if (const auto* builtin_type =
Googler06f2c9a2022-01-05 12:00:47 +0000645 // Use getAsAdjusted instead of getAs so we don't desugar
646 // typedefs.
647 qual_type->getAsAdjusted<clang::BuiltinType>()) {
Michael Forster51da81a2021-09-20 07:14:23 +0000648 switch (builtin_type->getKind()) {
649 case clang::BuiltinType::Bool:
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000650 type = MappedType::Simple("bool", "bool");
Michael Forster51da81a2021-09-20 07:14:23 +0000651 break;
652 case clang::BuiltinType::Float:
Michael Forsterc7976ec2021-10-01 10:05:16 +0000653 type = MappedType::Simple("f32", "float");
Michael Forster51da81a2021-09-20 07:14:23 +0000654 break;
655 case clang::BuiltinType::Double:
Michael Forsterc7976ec2021-10-01 10:05:16 +0000656 type = MappedType::Simple("f64", "double");
Michael Forster51da81a2021-09-20 07:14:23 +0000657 break;
658 case clang::BuiltinType::Void:
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000659 type = MappedType::Void();
Michael Forster51da81a2021-09-20 07:14:23 +0000660 break;
661 default:
662 if (builtin_type->isIntegerType()) {
Michael Forsterd3ef1e92021-10-12 16:15:31 +0000663 auto size = ctx_->getTypeSize(builtin_type);
Googler06f2c9a2022-01-05 12:00:47 +0000664 if (size == 8 || size == 16 || size == 32 || size == 64) {
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000665 type = MappedType::Simple(
Michael Forster51da81a2021-09-20 07:14:23 +0000666 absl::Substitute(
667 "$0$1", builtin_type->isSignedInteger() ? 'i' : 'u', size),
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000668 type_string);
Michael Forster51da81a2021-09-20 07:14:23 +0000669 }
670 }
Marcel Hlopko7d739792021-08-12 07:52:47 +0000671 }
Michael Forster365bba12022-01-24 16:56:06 +0000672 } else if (const auto* tag_type =
Googler6a0a5252022-01-11 14:08:09 +0000673 qual_type->getAsAdjusted<clang::TagType>()) {
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000674 clang::TagDecl* tag_decl = tag_type->getDecl();
675
Googlerdcca7f72022-01-10 12:30:43 +0000676 if (known_type_decls_.contains(tag_decl)) {
Googler279eca32022-01-04 14:03:44 +0000677 if (std::optional<Identifier> id = GetTranslatedIdentifier(tag_decl)) {
678 std::string ident(id->Ident());
679 DeclId decl_id = GenerateDeclId(tag_decl);
680 type = MappedType::WithDeclIds(ident, decl_id, ident, decl_id);
681 }
Devin Jeanpierrebf0d5602021-10-13 20:47:39 +0000682 }
Michael Forster365bba12022-01-24 16:56:06 +0000683 } else if (const auto* typedef_type =
Googler6a0a5252022-01-11 14:08:09 +0000684 qual_type->getAsAdjusted<clang::TypedefType>()) {
Googlerdcca7f72022-01-10 12:30:43 +0000685 clang::TypedefNameDecl* typedef_name_decl = typedef_type->getDecl();
686
687 if (known_type_decls_.contains(typedef_name_decl)) {
688 if (std::optional<Identifier> id =
689 GetTranslatedIdentifier(typedef_name_decl)) {
690 std::string ident(id->Ident());
691 DeclId decl_id = GenerateDeclId(typedef_name_decl);
692 type = MappedType::WithDeclIds(ident, decl_id, ident, decl_id);
693 }
694 }
Marcel Hlopko7d739792021-08-12 07:52:47 +0000695 }
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000696
697 if (!type.has_value()) {
698 absl::Status error = absl::UnimplementedError(
699 absl::Substitute("Unsupported type '$0'", type_string));
700 error.SetPayload(kTypeStatusPayloadUrl, absl::Cord(type_string));
701 return error;
702 }
703
704 // Add cv-qualification.
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000705 type->cc_type.is_const = qual_type.isConstQualified();
Devin Jeanpierre184f9ac2021-09-17 13:47:03 +0000706 // Not doing volatile for now -- note that volatile pointers do not exist in
707 // Rust, though volatile reads/writes still do.
708
709 return *std::move(type);
Marcel Hlopko7d739792021-08-12 07:52:47 +0000710}
711
Googlere3434c32021-10-19 10:28:35 +0000712std::optional<std::vector<Field>> AstVisitor::ImportFields(
713 clang::RecordDecl* record_decl, clang::AccessSpecifier default_access) {
714 std::vector<Field> fields;
715 const clang::ASTRecordLayout& layout = ctx_->getASTRecordLayout(record_decl);
716 for (const clang::FieldDecl* field_decl : record_decl->fields()) {
717 auto type = ConvertType(field_decl->getType());
718 if (!type.ok()) {
Googler279eca32022-01-04 14:03:44 +0000719 PushUnsupportedItem(record_decl,
720 absl::Substitute("Field type '$0' is not supported",
721 field_decl->getType().getAsString()),
722 field_decl->getBeginLoc());
Googlere3434c32021-10-19 10:28:35 +0000723 return std::nullopt;
724 }
725 clang::AccessSpecifier access = field_decl->getAccess();
726 if (access == clang::AS_none) {
727 access = default_access;
728 }
729
730 std::optional<Identifier> field_name = GetTranslatedIdentifier(field_decl);
731 if (!field_name.has_value()) {
Googler279eca32022-01-04 14:03:44 +0000732 PushUnsupportedItem(
733 record_decl,
734 absl::Substitute("Cannot translate name for field '$0'",
735 field_decl->getNameAsString()),
736 field_decl->getBeginLoc());
Googlere3434c32021-10-19 10:28:35 +0000737 return std::nullopt;
738 }
739 fields.push_back(
740 {.identifier = *std::move(field_name),
741 .doc_comment = GetComment(field_decl),
742 .type = *type,
743 .access = TranslateAccessSpecifier(access),
744 .offset = layout.getFieldOffset(field_decl->getFieldIndex())});
745 }
746 return fields;
747}
748
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +0000749std::string AstVisitor::GetMangledName(
Marcel Hlopko7d739792021-08-12 07:52:47 +0000750 const clang::NamedDecl* named_decl) const {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000751 clang::GlobalDecl decl;
752
753 // There are only three named decl types that don't work with the GlobalDecl
754 // unary constructor: GPU kernels (which do not exist in standard C++, so we
755 // ignore), constructors, and destructors. GlobalDecl does not support
756 // constructors and destructors from the unary constructor because there is
757 // more than one global declaration for a given constructor or destructor!
758 //
759 // * (Ctor|Dtor)_Complete is a function which constructs / destroys the
760 // entire object. This is what we want. :)
761 // * Dtor_Deleting is a function which additionally calls operator delete.
762 // * (Ctor|Dtor)_Base is a function which constructs/destroys the object but
763 // NOT including virtual base class subobjects.
764 // * (Ctor|Dtor)_Comdat: I *believe* this is the identifier used to
765 // deduplicate inline functions, and is not callable.
766 // * Dtor_(Copying|Default)Closure: These only exist in the MSVC++ ABI,
767 // which we don't support for now. I don't know when they are used.
768 //
769 // It was hard to piece this together, so writing it down here to explain why
770 // we magically picked the *_Complete variants.
771 if (auto dtor = llvm::dyn_cast<clang::CXXDestructorDecl>(named_decl)) {
772 decl = clang::GlobalDecl(dtor, clang::CXXDtorType::Dtor_Complete);
773 } else if (auto ctor =
774 llvm::dyn_cast<clang::CXXConstructorDecl>(named_decl)) {
775 decl = clang::GlobalDecl(ctor, clang::CXXCtorType::Ctor_Complete);
776 } else {
777 decl = clang::GlobalDecl(named_decl);
778 }
779
Marcel Hlopko7d739792021-08-12 07:52:47 +0000780 std::string name;
781 llvm::raw_string_ostream stream(name);
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000782 mangler_->mangleName(decl, stream);
Marcel Hlopko7d739792021-08-12 07:52:47 +0000783 stream.flush();
Marcel Hlopkoa5f59ae2021-08-24 20:38:04 +0000784 return name;
Marcel Hlopko7d739792021-08-12 07:52:47 +0000785}
786
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000787std::optional<UnqualifiedIdentifier> AstVisitor::GetTranslatedName(
Marcel Hlopko7d739792021-08-12 07:52:47 +0000788 const clang::NamedDecl* named_decl) const {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000789 switch (named_decl->getDeclName().getNameKind()) {
790 case clang::DeclarationName::Identifier: {
791 auto name = std::string(named_decl->getName());
792 if (name.empty()) {
Lukasz Anforowicz0c816f12021-12-15 17:41:49 +0000793 if (const clang::ParmVarDecl* param_decl =
794 clang::dyn_cast<clang::ParmVarDecl>(named_decl)) {
795 int param_pos = param_decl->getFunctionScopeIndex();
796 return {Identifier(absl::StrCat("__param_", param_pos))};
797 }
798 // TODO(lukasza): Handle anonymous structs (probably this won't be an
799 // issue until nested types are handled - b/200067824).
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000800 return std::nullopt;
801 }
802 return {Identifier(std::move(name))};
803 }
804 case clang::DeclarationName::CXXConstructorName:
805 return {SpecialName::kConstructor};
806 case clang::DeclarationName::CXXDestructorName:
807 return {SpecialName::kDestructor};
808 default:
809 // To be implemented later: operators, conversion functions.
810 // There are also e.g. literal operators, deduction guides, etc., but
811 // we might not need to implement them at all. Full list at:
812 // https://clang.llvm.org/doxygen/classclang_1_1DeclarationName.html#a9ab322d434446b43379d39e41af5cbe3
813 return std::nullopt;
Devin Jeanpierree78b2fb2021-10-05 11:40:33 +0000814 }
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +0000815}
816
Michael Forsterf1dce422021-10-13 09:50:16 +0000817void AstVisitor::CommentManager::TraverseDecl(clang::Decl* decl) {
818 ctx_ = &decl->getASTContext();
819
820 // When we go to a new file we flush the comments from the previous file,
821 // because source locations won't be comparable by '<' any more.
822 clang::FileID file = ctx_->getSourceManager().getFileID(decl->getBeginLoc());
Devin Jeanpierre96839c12021-12-14 00:27:38 +0000823 // For example, we hit an invalid FileID for virtual destructor definitions.
824 if (file.isInvalid()) {
825 return;
826 }
Michael Forsterf1dce422021-10-13 09:50:16 +0000827 if (file != current_file_) {
828 FlushComments();
829 current_file_ = file;
830 LoadComments();
831 }
832
833 // Visit all comments from the current file up to the current decl.
834 clang::RawComment* decl_comment = ctx_->getRawCommentForDeclNoCache(decl);
835 while (next_comment_ != file_comments_.end() &&
836 (*next_comment_)->getBeginLoc() < decl->getBeginLoc()) {
837 // Skip the decl's doc comment, which will be emitted as part of the decl.
838 if (*next_comment_ != decl_comment) {
839 VisitTopLevelComment(*next_comment_);
840 }
841 ++next_comment_;
842 }
843
844 // Skip comments that are within the decl, e.g., comments in the body of an
845 // inline function
846 // TODO(forster): We should retain floating comments within `Record`s
847 if (!clang::isa<clang::NamespaceDecl>(decl)) {
848 while (next_comment_ != file_comments_.end() &&
849 (*next_comment_)->getBeginLoc() < decl->getEndLoc()) {
850 ++next_comment_;
851 }
852 }
853}
854
855void AstVisitor::CommentManager::LoadComments() {
856 auto comments = ctx_->Comments.getCommentsInFile(current_file_);
857 if (comments) {
858 for (auto [_, comment] : *comments) {
859 file_comments_.push_back(comment);
860 }
861 }
862 next_comment_ = file_comments_.begin();
863}
864
865void AstVisitor::CommentManager::FlushComments() {
866 while (next_comment_ != file_comments_.end()) {
867 VisitTopLevelComment(*next_comment_);
868 next_comment_++;
869 }
870 file_comments_.clear();
871}
872
873void AstVisitor::CommentManager::VisitTopLevelComment(
Michael Forster365bba12022-01-24 16:56:06 +0000874 const clang::RawComment* comment) {
875 comments_.push_back(comment);
Michael Forsterf1dce422021-10-13 09:50:16 +0000876}
877
Marcel Hlopkoe8f1c4e2021-07-28 18:12:49 +0000878} // namespace rs_bindings_from_cc