blob: 1926d703fa42ed9adae2e755f9b930a210c774ab [file] [log] [blame]
Marcel Hlopko42abfc82021-08-09 07:03:17 +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
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -07005//! Types and deserialization logic for IR. See docs in
6//! `rs_bindings_from_cc/ir.h` for more
7//! information.
8
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -07009use arc_anyhow::{anyhow, bail, Context, Error, Result};
10use once_cell::unsync::OnceCell;
Devin Jeanpierred61c6d72023-02-02 14:30:19 -080011use proc_macro2::TokenStream;
12use quote::{quote, ToTokens};
Marcel Hlopko42abfc82021-08-09 07:03:17 +000013use serde::Deserialize;
Devin Jeanpierre9886fb42022-04-01 04:31:20 -070014use std::collections::hash_map::{Entry, HashMap};
Devin Jeanpierre7eb04042021-12-03 07:19:22 +000015use std::convert::TryFrom;
Devin Jeanpierreab8732a2023-03-22 19:09:03 -070016use std::fmt::{self, Debug, Display, Formatter};
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -070017use std::hash::{Hash, Hasher};
Marcel Hlopko42abfc82021-08-09 07:03:17 +000018use std::io::Read;
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -070019use std::rc::Rc;
Marcel Hlopko42abfc82021-08-09 07:03:17 +000020
Devin Jeanpierreab8732a2023-03-22 19:09:03 -070021/// Common data about all items.
22pub trait GenericItem {
23 fn id(&self) -> ItemId;
24 /// The name of the item, readable by programmers.
25 ///
26 /// For example, `void Foo();` should have name `Foo`.
27 fn debug_name(&self, ir: &IR) -> Rc<str>;
28
29 /// The recorded source location, or None if none is present.
30 fn source_loc(&self) -> Option<Rc<str>>;
31}
32
33impl<T> GenericItem for Rc<T>
34where
35 T: GenericItem + ?Sized,
36{
37 fn id(&self) -> ItemId {
38 (**self).id()
39 }
40 fn debug_name(&self, ir: &IR) -> Rc<str> {
41 (**self).debug_name(ir)
42 }
43 fn source_loc(&self) -> Option<Rc<str>> {
44 (**self).source_loc()
45 }
46}
47
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000048/// Deserialize `IR` from JSON given as a reader.
Marcel Hlopko42abfc82021-08-09 07:03:17 +000049pub fn deserialize_ir<R: Read>(reader: R) -> Result<IR> {
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000050 let flat_ir = serde_json::from_reader(reader)?;
Lukasz Anforowicz578ba8b2023-05-15 11:15:51 -070051 Ok(make_ir(flat_ir))
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000052}
53
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000054/// Create a testing `IR` instance from given parts. This function does not use
55/// any mock values.
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -080056pub fn make_ir_from_parts<CrubitFeatures>(
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000057 items: Vec<Item>,
Lukasz Anforowicz121338a2022-11-01 14:28:32 -070058 public_headers: Vec<HeaderName>,
Googler6c3de122022-03-28 11:40:41 +000059 current_target: BazelLabel,
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -070060 top_level_item_ids: Vec<ItemId>,
Googler841386c2022-11-29 07:42:32 -080061 crate_root_path: Option<Rc<str>>,
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -080062 crubit_features: HashMap<BazelLabel, CrubitFeatures>,
Lukasz Anforowicz578ba8b2023-05-15 11:15:51 -070063) -> IR
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -080064where
65 CrubitFeatures: Into<flagset::FlagSet<CrubitFeature>>,
66{
67 make_ir(FlatIR {
68 public_headers,
69 current_target,
70 items,
71 top_level_item_ids,
72 crate_root_path,
73 crubit_features: crubit_features
74 .into_iter()
75 .map(|(label, features)| (label, CrubitFeaturesIR(features.into())))
76 .collect(),
77 })
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000078}
79
Lukasz Anforowicz578ba8b2023-05-15 11:15:51 -070080fn make_ir(flat_ir: FlatIR) -> IR {
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000081 let mut used_decl_ids = HashMap::new();
82 for item in &flat_ir.items {
Rosica Dejanovska10accf12022-03-31 04:47:58 -070083 if let Some(existing_decl) = used_decl_ids.insert(item.id(), item) {
Lukasz Anforowicz578ba8b2023-05-15 11:15:51 -070084 panic!("Duplicate decl_id found in {:?} and {:?}", existing_decl, item);
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000085 }
86 }
Rosica Dejanovskad638cf52022-03-23 15:45:01 +000087 let item_id_to_item_idx = flat_ir
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000088 .items
89 .iter()
90 .enumerate()
Rosica Dejanovska10accf12022-03-31 04:47:58 -070091 .map(|(idx, item)| (item.id(), idx))
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +000092 .collect::<HashMap<_, _>>();
Devin Jeanpierre9886fb42022-04-01 04:31:20 -070093
Marcel Hlopkoaf682a02022-04-08 07:27:14 -070094 let mut lifetimes: HashMap<LifetimeId, LifetimeName> = HashMap::new();
Devin Jeanpierre9886fb42022-04-01 04:31:20 -070095 for item in &flat_ir.items {
96 let lifetime_params = match item {
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -070097 Item::Record(record) => &record.lifetime_params,
98 Item::Func(func) => &func.lifetime_params,
Devin Jeanpierre9886fb42022-04-01 04:31:20 -070099 _ => continue,
100 };
101 for lifetime in lifetime_params {
Devin Jeanpierred2b7a8f2022-04-01 04:37:16 -0700102 match lifetimes.entry(lifetime.id) {
Devin Jeanpierre9886fb42022-04-01 04:31:20 -0700103 Entry::Occupied(occupied) => {
Lukasz Anforowicz578ba8b2023-05-15 11:15:51 -0700104 panic!(
Devin Jeanpierre6af160e2022-09-21 05:30:34 -0700105 "Duplicate use of lifetime ID {:?} in item {item:?} for names: '{}, '{}",
Devin Jeanpierre9886fb42022-04-01 04:31:20 -0700106 lifetime.id,
Devin Jeanpierred2b7a8f2022-04-01 04:37:16 -0700107 &occupied.get().name,
Devin Jeanpierre9886fb42022-04-01 04:31:20 -0700108 &lifetime.name
109 )
110 }
111 Entry::Vacant(vacant) => {
Devin Jeanpierred2b7a8f2022-04-01 04:37:16 -0700112 vacant.insert(lifetime.clone());
Devin Jeanpierre9886fb42022-04-01 04:31:20 -0700113 }
114 }
115 }
116 }
Rosica Dejanovska93aeafb2022-06-01 07:05:31 -0700117 let mut namespace_id_to_number_of_reopened_namespaces = HashMap::new();
118 let mut reopened_namespace_id_to_idx = HashMap::new();
119
120 flat_ir
121 .items
122 .iter()
123 .filter_map(|item| match item {
124 Item::Namespace(ns) if ns.owning_target == flat_ir.current_target => {
125 Some((ns.canonical_namespace_id, ns.id))
126 }
127 _ => None,
128 })
129 .for_each(|(canonical_id, id)| {
130 let current_count =
131 *namespace_id_to_number_of_reopened_namespaces.entry(canonical_id).or_insert(0);
132 reopened_namespace_id_to_idx.insert(id, current_count);
133 namespace_id_to_number_of_reopened_namespaces.insert(canonical_id, current_count + 1);
134 });
135
Felipe de A. Mello Pereira3a953722023-03-02 05:37:36 -0800136 let mut function_name_to_functions = HashMap::<UnqualifiedIdentifier, Vec<Rc<Func>>>::new();
137 flat_ir
138 .items
139 .iter()
140 .filter_map(|item| match item {
141 Item::Func(func) => Some(func),
142 _ => None,
143 })
144 .for_each(|f| {
145 function_name_to_functions.entry(f.name.clone()).or_default().push(f.clone());
146 });
147
Lukasz Anforowicz578ba8b2023-05-15 11:15:51 -0700148 IR {
Rosica Dejanovska93aeafb2022-06-01 07:05:31 -0700149 flat_ir,
150 item_id_to_item_idx,
151 lifetimes,
152 namespace_id_to_number_of_reopened_namespaces,
153 reopened_namespace_id_to_idx,
Felipe de A. Mello Pereira3a953722023-03-02 05:37:36 -0800154 function_name_to_functions,
Lukasz Anforowicz578ba8b2023-05-15 11:15:51 -0700155 }
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000156}
157
158#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800159#[serde(deny_unknown_fields)]
Marcel Hlopkof1123c82021-08-19 11:38:52 +0000160pub struct HeaderName {
Lukasz Anforowicz434c4692022-11-01 14:05:24 -0700161 pub name: Rc<str>,
Marcel Hlopkof1123c82021-08-19 11:38:52 +0000162}
163
Googler64e4edb2021-12-03 12:17:38 +0000164#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800165#[serde(deny_unknown_fields)]
Googler64e4edb2021-12-03 12:17:38 +0000166#[serde(transparent)]
167pub struct LifetimeId(pub i32);
168
169#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800170#[serde(deny_unknown_fields)]
Marcel Hlopkoaf682a02022-04-08 07:27:14 -0700171pub struct LifetimeName {
Devin Jeanpierreb2b6cf82022-07-07 01:49:27 -0700172 pub name: Rc<str>,
Googler64e4edb2021-12-03 12:17:38 +0000173 pub id: LifetimeId,
174}
175
Marcel Hlopkof1123c82021-08-19 11:38:52 +0000176#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800177#[serde(deny_unknown_fields)]
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000178pub struct RsType {
Googler841386c2022-11-29 07:42:32 -0800179 pub name: Option<Rc<str>>,
Devin Jeanpierre409f6f62022-07-07 02:00:26 -0700180 pub lifetime_args: Rc<[LifetimeId]>,
181 pub type_args: Rc<[RsType]>,
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000182 pub decl_id: Option<ItemId>,
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000183}
184
Lukasz Anforowicz4ad012b2021-12-15 18:13:40 +0000185impl RsType {
186 pub fn is_unit_type(&self) -> bool {
187 self.name.as_deref() == Some("()")
188 }
189}
190
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000191#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800192#[serde(deny_unknown_fields)]
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000193pub struct CcType {
Googler841386c2022-11-29 07:42:32 -0800194 pub name: Option<Rc<str>>,
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000195 pub is_const: bool,
Googlerff7fc232021-12-02 09:43:00 +0000196 pub type_args: Vec<CcType>,
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000197 pub decl_id: Option<ItemId>,
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000198}
199
Marcel Hlopko264b9ad2021-12-02 21:06:44 +0000200pub trait TypeWithDeclId {
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000201 fn decl_id(&self) -> Option<ItemId>;
Marcel Hlopkoc0956cf2021-11-29 08:31:28 +0000202}
203
Marcel Hlopko264b9ad2021-12-02 21:06:44 +0000204impl TypeWithDeclId for RsType {
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000205 fn decl_id(&self) -> Option<ItemId> {
Marcel Hlopkoc0956cf2021-11-29 08:31:28 +0000206 self.decl_id
207 }
208}
209
Marcel Hlopko264b9ad2021-12-02 21:06:44 +0000210impl TypeWithDeclId for CcType {
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000211 fn decl_id(&self) -> Option<ItemId> {
Marcel Hlopkoc0956cf2021-11-29 08:31:28 +0000212 self.decl_id
213 }
214}
215
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000216#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800217#[serde(deny_unknown_fields)]
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000218pub struct MappedType {
219 pub rs_type: RsType,
220 pub cc_type: CcType,
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000221}
222
Marcel Hlopkoafdc5022021-12-16 14:31:19 +0000223#[derive(PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800224#[serde(deny_unknown_fields)]
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000225pub struct Identifier {
Lukasz Anforowicz8c1a6c42022-11-23 16:18:09 -0800226 pub identifier: Rc<str>,
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000227}
228
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700229impl Display for Identifier {
Marcel Hlopkoafdc5022021-12-16 14:31:19 +0000230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700231 write!(f, "{}", self.identifier)
232 }
233}
234
235impl Debug for Identifier {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 write!(f, "\"{}\"", self.identifier)
Marcel Hlopkoafdc5022021-12-16 14:31:19 +0000238 }
239}
240
Teddy Katz76fa42b2022-02-23 01:22:56 +0000241#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800242#[serde(deny_unknown_fields)]
Teddy Katz76fa42b2022-02-23 01:22:56 +0000243pub struct IntegerConstant {
244 pub is_negative: bool,
245 pub wrapped_value: u64,
246}
247
Lukasz Anforowicz9c663ca2022-02-09 01:33:31 +0000248#[derive(PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800249#[serde(deny_unknown_fields)]
Lukasz Anforowicz9c663ca2022-02-09 01:33:31 +0000250pub struct Operator {
Googler408ef402022-11-28 02:59:28 -0800251 pub name: Rc<str>,
Lukasz Anforowicz9c663ca2022-02-09 01:33:31 +0000252}
253
254impl Operator {
255 pub fn cc_name(&self) -> String {
256 let separator = match self.name.chars().next() {
257 Some(c) if c.is_alphabetic() => " ",
258 _ => "",
259 };
260 format!("operator{separator}{name}", separator = separator, name = self.name)
261 }
262}
263
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700264impl Debug for Operator {
Lukasz Anforowicz9c663ca2022-02-09 01:33:31 +0000265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700266 write!(f, "\"{}\"", self.cc_name())
Lukasz Anforowicz9c663ca2022-02-09 01:33:31 +0000267 }
268}
269
Marcel Hlopko9c150da2021-11-12 10:30:03 +0000270#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Deserialize)]
271#[serde(transparent)]
Lukasz Anforowicz14732b22022-06-02 09:11:08 -0700272pub struct ItemId(usize);
273
274impl ItemId {
275 pub fn new_for_testing(value: usize) -> Self {
276 Self(value)
277 }
278}
279
280impl ToTokens for ItemId {
281 fn to_tokens(&self, tokens: &mut TokenStream) {
282 proc_macro2::Literal::usize_unsuffixed(self.0).to_tokens(tokens)
283 }
284}
Marcel Hlopko9c150da2021-11-12 10:30:03 +0000285
Devin Jeanpierre89230f32023-03-15 12:27:02 -0700286/// A Bazel label, e.g. `//foo:bar`.
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000287#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Marcel Hlopko80441c12021-11-12 10:43:18 +0000288#[serde(transparent)]
Googlerc2102ee2022-11-29 07:18:24 -0800289pub struct BazelLabel(pub Rc<str>);
Marcel Hlopko80441c12021-11-12 10:43:18 +0000290
Googler6c3de122022-03-28 11:40:41 +0000291impl BazelLabel {
Devin Jeanpierre89230f32023-03-15 12:27:02 -0700292 /// Returns the target name. E.g. `bar` for `//foo:bar`.
Devin Jeanpierre084ebbd2022-04-01 04:32:46 -0700293 pub fn target_name(&self) -> &str {
Devin Jeanpierre89230f32023-03-15 12:27:02 -0700294 if let Some((_package, target_name)) = self.0.split_once(':') {
295 return target_name;
Marcel Hlopkoa0f38662021-12-03 08:45:26 +0000296 }
Devin Jeanpierre89230f32023-03-15 12:27:02 -0700297 if let Some((_, last_package_component)) = self.0.rsplit_once('/') {
298 return last_package_component;
299 }
300 &self.0
Marcel Hlopkoa0f38662021-12-03 08:45:26 +0000301 }
302}
303
Googler6c3de122022-03-28 11:40:41 +0000304impl<T: Into<String>> From<T> for BazelLabel {
Marcel Hlopko80441c12021-11-12 10:43:18 +0000305 fn from(label: T) -> Self {
Googlerc2102ee2022-11-29 07:18:24 -0800306 Self(label.into().into())
Marcel Hlopko80441c12021-11-12 10:43:18 +0000307 }
308}
309
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700310impl Display for BazelLabel {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Devin Jeanpierredff65282023-03-14 20:32:28 -0700312 write!(f, "{}", &*self.0)
313 }
314}
315
Marcel Hlopkoafdc5022021-12-16 14:31:19 +0000316#[derive(PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000317pub enum UnqualifiedIdentifier {
318 Identifier(Identifier),
Lukasz Anforowicz9c663ca2022-02-09 01:33:31 +0000319 Operator(Operator),
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000320 Constructor,
321 Destructor,
322}
323
Marcel Hlopko36ced2d2021-12-02 10:47:37 +0000324impl UnqualifiedIdentifier {
325 pub fn identifier_as_str(&self) -> Option<&str> {
326 match self {
Lukasz Anforowicz8c1a6c42022-11-23 16:18:09 -0800327 UnqualifiedIdentifier::Identifier(identifier) => Some(identifier.identifier.as_ref()),
Marcel Hlopko36ced2d2021-12-02 10:47:37 +0000328 _ => None,
329 }
330 }
331}
332
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700333impl Debug for UnqualifiedIdentifier {
Marcel Hlopkoafdc5022021-12-16 14:31:19 +0000334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 match self {
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700336 UnqualifiedIdentifier::Identifier(identifier) => Debug::fmt(identifier, f),
337 UnqualifiedIdentifier::Operator(op) => Debug::fmt(op, f),
Marcel Hlopkoafdc5022021-12-16 14:31:19 +0000338 UnqualifiedIdentifier::Constructor => f.write_str("Constructor"),
339 UnqualifiedIdentifier::Destructor => f.write_str("Destructor"),
340 }
341 }
342}
343
Devin Jeanpierre435d71f2022-10-04 22:18:50 -0700344#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Deserialize)]
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000345pub enum ReferenceQualification {
346 LValue,
347 RValue,
348 Unqualified,
349}
350
351#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800352#[serde(deny_unknown_fields)]
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000353pub struct InstanceMethodMetadata {
354 pub reference: ReferenceQualification,
355 pub is_const: bool,
356 pub is_virtual: bool,
357}
358
359#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800360#[serde(deny_unknown_fields)]
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000361pub struct MemberFuncMetadata {
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000362 pub record_id: ItemId,
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000363 pub instance_method_metadata: Option<InstanceMethodMetadata>,
364}
365
366#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800367#[serde(deny_unknown_fields)]
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000368pub struct FuncParam {
369 #[serde(rename(deserialize = "type"))]
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000370 pub type_: MappedType,
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000371 pub identifier: Identifier,
372}
373
374#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800375#[serde(deny_unknown_fields)]
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000376pub struct Func {
Devin Jeanpierref2ec8712021-10-13 20:47:16 +0000377 pub name: UnqualifiedIdentifier,
Googler6c3de122022-03-28 11:40:41 +0000378 pub owning_target: BazelLabel,
Googlerc2102ee2022-11-29 07:18:24 -0800379 pub mangled_name: Rc<str>,
Googler841386c2022-11-29 07:42:32 -0800380 pub doc_comment: Option<Rc<str>>,
Devin Jeanpierre09c6f452021-09-29 07:34:24 +0000381 pub return_type: MappedType,
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000382 pub params: Vec<FuncParam>,
Devin Jeanpierre6bb81802022-08-10 02:08:47 -0700383 /// For tests and internal use only.
384 ///
385 /// Prefer to reconstruct the lifetime params from the parameter types, as
386 /// needed. This allows new parameters and lifetimes to be added that were
387 /// not originally part of the IR.
Marcel Hlopkoaf682a02022-04-08 07:27:14 -0700388 pub lifetime_params: Vec<LifetimeName>,
Marcel Hlopko3164eee2021-08-24 20:09:22 +0000389 pub is_inline: bool,
Devin Jeanpierrec6877bb2021-10-13 20:47:54 +0000390 pub member_func_metadata: Option<MemberFuncMetadata>,
Lukasz Anforowicz0b6a6ac2022-03-22 22:32:23 +0000391 pub has_c_calling_convention: bool,
Lukasz Anforowiczb1ff2e52022-05-16 10:54:23 -0700392 pub is_member_or_descendant_of_class_template: bool,
Googler442733c2023-01-23 01:05:35 -0800393 pub source_loc: Rc<str>,
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000394 pub id: ItemId,
Rosica Dejanovskae91d2992022-05-05 05:31:39 -0700395 pub enclosing_namespace_id: Option<ItemId>,
Michael VanBemmel7a4d4c02022-07-27 13:21:47 -0700396 pub adl_enclosing_record: Option<ItemId>,
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000397}
398
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700399impl GenericItem for Func {
400 fn id(&self) -> ItemId {
401 self.id
402 }
403 fn debug_name(&self, ir: &IR) -> Rc<str> {
404 let record: Option<Rc<str>> = ir.record_for_member_func(self).map(|r| r.debug_name(ir));
405 let record: Option<&str> = record.as_deref();
406
407 let func_name = match &self.name {
408 UnqualifiedIdentifier::Identifier(id) => id.identifier.to_string(),
409 UnqualifiedIdentifier::Operator(op) => op.cc_name(),
410 UnqualifiedIdentifier::Destructor => {
411 format!("~{}", record.expect("destructor must be associated with a record"))
412 }
413 UnqualifiedIdentifier::Constructor => {
414 record.expect("constructor must be associated with a record").to_string()
415 }
416 };
417
418 if let Some(record_name) = record {
419 format!("{}::{}", record_name, func_name).into()
420 } else {
421 func_name.into()
422 }
423 }
424 fn source_loc(&self) -> Option<Rc<str>> {
425 Some(self.source_loc.clone())
426 }
427}
428
Lukasz Anforowicz231a3bb2022-01-12 14:05:59 +0000429impl Func {
430 pub fn is_instance_method(&self) -> bool {
431 self.member_func_metadata
432 .as_ref()
433 .filter(|meta| meta.instance_method_metadata.is_some())
434 .is_some()
435 }
436}
437
Googler2294c702021-09-17 07:32:07 +0000438#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Deserialize)]
439pub enum AccessSpecifier {
440 Public,
441 Protected,
442 Private,
443}
444
Marcel Hlopko42abfc82021-08-09 07:03:17 +0000445#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800446#[serde(deny_unknown_fields)]
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000447pub struct Field {
Michael Forster7a004912022-05-12 07:45:57 -0700448 pub identifier: Option<Identifier>,
Googler841386c2022-11-29 07:42:32 -0800449 pub doc_comment: Option<Rc<str>>,
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000450 #[serde(rename(deserialize = "type"))]
Lukasz Anforowiczfea0db92022-05-17 17:28:04 -0700451 pub type_: Result<MappedType, String>,
Googler2294c702021-09-17 07:32:07 +0000452 pub access: AccessSpecifier,
Googler5ea88642021-09-29 08:05:59 +0000453 pub offset: usize,
Lukasz Anforowicz5765bb82022-05-17 17:21:06 -0700454 pub size: usize,
Devin Jeanpierreb69bcae2022-02-03 09:45:50 +0000455 pub is_no_unique_address: bool,
Michael Forster82c02d32022-05-20 21:47:33 -0700456 pub is_bitfield: bool,
Kinuko Yasuda6ff59f12022-08-11 08:41:45 -0700457 // TODO(kinuko): Consider removing this, it is a duplicate of the same information
458 // in `Record`.
459 pub is_inheritable: bool,
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000460}
461
462#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Lukasz Anforowiczff7df4a2022-06-02 14:27:45 -0700463pub enum SpecialMemberFunc {
Devin Jeanpierre8fc6b432021-10-05 11:41:53 +0000464 Trivial,
Devin Jeanpierrebe2f33b2021-10-21 12:54:19 +0000465 NontrivialMembers,
Devin Jeanpierre7b62e952021-12-08 21:43:30 +0000466 NontrivialUserDefined,
Lukasz Anforowiczff7df4a2022-06-02 14:27:45 -0700467 Unavailable,
Devin Jeanpierre8fc6b432021-10-05 11:41:53 +0000468}
469
470#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800471#[serde(deny_unknown_fields)]
Devin Jeanpierre56777022022-02-03 01:57:15 +0000472pub struct BaseClass {
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000473 pub base_record_id: ItemId,
Devin Jeanpierre56777022022-02-03 01:57:15 +0000474 pub offset: Option<i64>,
475}
476
477#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800478#[serde(deny_unknown_fields)]
Devin Jeanpierrec0543eb2022-04-20 16:00:34 -0700479pub struct IncompleteRecord {
Googlerc2102ee2022-11-29 07:18:24 -0800480 pub cc_name: Rc<str>,
481 pub rs_name: Rc<str>,
Devin Jeanpierrec0543eb2022-04-20 16:00:34 -0700482 pub id: ItemId,
483 pub owning_target: BazelLabel,
Lukasz Anforowicz8dd51792022-08-31 10:11:17 -0700484 pub record_type: RecordType,
Rosica Dejanovskae91d2992022-05-05 05:31:39 -0700485 pub enclosing_namespace_id: Option<ItemId>,
Devin Jeanpierrec0543eb2022-04-20 16:00:34 -0700486}
487
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700488impl GenericItem for IncompleteRecord {
489 fn id(&self) -> ItemId {
490 self.id
491 }
492 fn debug_name(&self, _: &IR) -> Rc<str> {
493 self.cc_name.clone()
494 }
495 fn source_loc(&self) -> Option<Rc<str>> {
496 None
497 }
498}
499
Lukasz Anforowiczd4742ff2022-07-11 17:05:02 -0700500#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Deserialize)]
501pub enum RecordType {
502 Struct,
503 Union,
504 Class,
505}
506
Lukasz Anforowicz8dd51792022-08-31 10:11:17 -0700507impl ToTokens for RecordType {
508 fn to_tokens(&self, tokens: &mut TokenStream) {
509 let tag = match self {
510 RecordType::Struct => quote! { struct },
511 RecordType::Union => quote! { union },
512 RecordType::Class => quote! { class },
513 };
514 tag.to_tokens(tokens)
515 }
516}
517
Devin Jeanpierrec0543eb2022-04-20 16:00:34 -0700518#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800519#[serde(deny_unknown_fields)]
Devin Jeanpierre1e2d3242023-05-15 12:21:59 -0700520pub struct SizeAlign {
521 pub size: usize,
522 pub alignment: usize,
523}
524
525#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
526#[serde(deny_unknown_fields)]
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000527pub struct Record {
Googlerc2102ee2022-11-29 07:18:24 -0800528 pub rs_name: Rc<str>,
529 pub cc_name: Rc<str>,
530 pub mangled_cc_name: Rc<str>,
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000531 pub id: ItemId,
Googler6c3de122022-03-28 11:40:41 +0000532 pub owning_target: BazelLabel,
Devin Jeanpierre3f0d0682023-04-13 14:47:28 -0700533 /// The target containing the template definition, if this is a templated
534 /// record type.
535 pub defining_target: Option<BazelLabel>,
Googler841386c2022-11-29 07:42:32 -0800536 pub doc_comment: Option<Rc<str>>,
Googlerafd18fb2023-01-25 12:55:07 -0800537 pub source_loc: Rc<str>,
Devin Jeanpierre56777022022-02-03 01:57:15 +0000538 pub unambiguous_public_bases: Vec<BaseClass>,
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000539 pub fields: Vec<Field>,
Marcel Hlopkoaf682a02022-04-08 07:27:14 -0700540 pub lifetime_params: Vec<LifetimeName>,
Devin Jeanpierre1e2d3242023-05-15 12:21:59 -0700541 pub size_align: SizeAlign,
Devin Jeanpierre1221c2a2022-05-05 22:36:22 -0700542 pub is_derived_class: bool,
Devin Jeanpierrec80e6242022-02-03 01:56:40 +0000543 pub override_alignment: bool,
Devin Jeanpierre8fc6b432021-10-05 11:41:53 +0000544 pub copy_constructor: SpecialMemberFunc,
545 pub move_constructor: SpecialMemberFunc,
546 pub destructor: SpecialMemberFunc,
Devin Jeanpierreb2cd0212021-10-01 07:16:23 +0000547 pub is_trivial_abi: bool,
Teddy Katzd2cd1422022-04-04 09:41:33 -0700548 pub is_inheritable: bool,
Devin Jeanpierreccb67672022-08-17 10:05:47 -0700549 pub is_abstract: bool,
Lukasz Anforowiczd4742ff2022-07-11 17:05:02 -0700550 pub record_type: RecordType,
Devin Jeanpierrea2be2a22022-05-18 18:59:05 -0700551 pub is_aggregate: bool,
Kinuko Yasuda8dd84642022-08-17 09:19:47 -0700552 pub is_anon_record_with_typedef: bool,
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -0700553 pub child_item_ids: Vec<ItemId>,
Rosica Dejanovskae91d2992022-05-05 05:31:39 -0700554 pub enclosing_namespace_id: Option<ItemId>,
Marcel Hlopkob4b28742021-09-15 12:45:20 +0000555}
556
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700557impl GenericItem for Record {
558 fn id(&self) -> ItemId {
559 self.id
560 }
561 fn debug_name(&self, _: &IR) -> Rc<str> {
562 self.cc_name.clone()
563 }
564 fn source_loc(&self) -> Option<Rc<str>> {
565 Some(self.source_loc.clone())
566 }
567}
568
Marcel Hlopkoa0f38662021-12-03 08:45:26 +0000569impl Record {
Devin Jeanpierree6e16652021-12-22 15:54:46 +0000570 /// Whether this type has Rust-like object semantics for mutating
571 /// assignment, and can be passed by mut reference as a result.
572 ///
573 /// If a type `T` is mut reference safe, it can be possed as a `&mut T`
574 /// safely. Otherwise, mutable references must use `Pin<&mut T>`.
575 ///
576 /// Conditions:
577 ///
578 /// 1. It is trivially relocatable, and thus can be passed by value and have
579 /// its memory directly mutated by Rust using memcpy-like
580 /// assignment/swap.
581 ///
582 /// 2. It cannot overlap with any other objects. In particular, it cannot be
583 /// inherited from, as inheritance allows for the tail padding to be
584 /// reused by other objects.
585 ///
586 /// (In future versions, we could also include types which are POD for
587 /// the purpose of layout, but this is less predictable to C++ users,
588 /// and ABI-specific.)
589 ///
590 /// We are assuming, for the moment, that no object is stored in a
591 /// `[[no_unique_address]]` variable. Much like packed structs and
592 /// the like, users of `[[no_unique_address]]` must be very careful
593 /// when passing mutable references to Rust.
594 ///
595 /// Described in more detail at: docs/unpin
Devin Jeanpierree6e16652021-12-22 15:54:46 +0000596 pub fn is_unpin(&self) -> bool {
Kinuko Yasuda6ff59f12022-08-11 08:41:45 -0700597 self.is_trivial_abi && !self.is_inheritable && self.fields.iter().all(|f| !f.is_inheritable)
Devin Jeanpierree6e16652021-12-22 15:54:46 +0000598 }
Lukasz Anforowiczd4742ff2022-07-11 17:05:02 -0700599
600 pub fn is_union(&self) -> bool {
601 match self.record_type {
602 RecordType::Union => true,
603 RecordType::Struct | RecordType::Class => false,
604 }
605 }
Marcel Hlopkoa0f38662021-12-03 08:45:26 +0000606}
607
Michael Forster7ef80732021-10-01 18:12:19 +0000608#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800609#[serde(deny_unknown_fields)]
Teddy Katz76fa42b2022-02-23 01:22:56 +0000610pub struct Enum {
611 pub identifier: Identifier,
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000612 pub id: ItemId,
Googler6c3de122022-03-28 11:40:41 +0000613 pub owning_target: BazelLabel,
Googlerafd18fb2023-01-25 12:55:07 -0800614 pub source_loc: Rc<str>,
Teddy Katz76fa42b2022-02-23 01:22:56 +0000615 pub underlying_type: MappedType,
616 pub enumerators: Vec<Enumerator>,
Rosica Dejanovskae91d2992022-05-05 05:31:39 -0700617 pub enclosing_namespace_id: Option<ItemId>,
Teddy Katz76fa42b2022-02-23 01:22:56 +0000618}
619
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700620impl GenericItem for Enum {
621 fn id(&self) -> ItemId {
622 self.id
623 }
624 fn debug_name(&self, _: &IR) -> Rc<str> {
Devin Jeanpierre861697a2023-04-13 14:35:27 -0700625 self.identifier.identifier.clone()
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700626 }
627 fn source_loc(&self) -> Option<Rc<str>> {
628 Some(self.source_loc.clone())
629 }
630}
631
Teddy Katz76fa42b2022-02-23 01:22:56 +0000632#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800633#[serde(deny_unknown_fields)]
Teddy Katz76fa42b2022-02-23 01:22:56 +0000634pub struct Enumerator {
635 pub identifier: Identifier,
636 pub value: IntegerConstant,
637}
638
639#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800640#[serde(deny_unknown_fields)]
Googler098c4582022-01-10 12:29:34 +0000641pub struct TypeAlias {
642 pub identifier: Identifier,
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000643 pub id: ItemId,
Googler6c3de122022-03-28 11:40:41 +0000644 pub owning_target: BazelLabel,
Googler841386c2022-11-29 07:42:32 -0800645 pub doc_comment: Option<Rc<str>>,
Googler098c4582022-01-10 12:29:34 +0000646 pub underlying_type: MappedType,
Googler442733c2023-01-23 01:05:35 -0800647 pub source_loc: Rc<str>,
Devin Jeanpierre5fecde52022-09-14 06:53:39 -0700648 pub enclosing_record_id: Option<ItemId>,
Rosica Dejanovskae91d2992022-05-05 05:31:39 -0700649 pub enclosing_namespace_id: Option<ItemId>,
Googler098c4582022-01-10 12:29:34 +0000650}
651
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700652impl GenericItem for TypeAlias {
653 fn id(&self) -> ItemId {
654 self.id
655 }
656 fn debug_name(&self, _: &IR) -> Rc<str> {
Devin Jeanpierre861697a2023-04-13 14:35:27 -0700657 self.identifier.identifier.clone()
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700658 }
659 fn source_loc(&self) -> Option<Rc<str>> {
660 Some(self.source_loc.clone())
661 }
662}
663
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700664/// A wrapper type that does not contribute to equality or hashing. All
665/// instances are equal.
666#[derive(Clone, Copy, Default)]
667struct IgnoredField<T>(T);
668
669impl<T> Debug for IgnoredField<T> {
670 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
671 write!(f, "_")
672 }
673}
674
675impl<T> PartialEq for IgnoredField<T> {
676 fn eq(&self, _other: &Self) -> bool {
677 true
678 }
679}
680
681impl<T> Eq for IgnoredField<T> {}
682
683impl<T> Hash for IgnoredField<T> {
684 fn hash<H: Hasher>(&self, _state: &mut H) {}
685}
686
Michael Forster6a184ad2021-10-12 13:04:05 +0000687#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800688#[serde(deny_unknown_fields)]
Michael Forster523dbd42021-10-12 11:05:44 +0000689pub struct UnsupportedItem {
Googlerc2102ee2022-11-29 07:18:24 -0800690 pub name: Rc<str>,
691 message: Rc<str>,
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700692 pub source_loc: Option<Rc<str>>,
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000693 pub id: ItemId,
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700694 #[serde(skip)]
695 cause: IgnoredField<OnceCell<Error>>,
696}
697
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700698impl GenericItem for UnsupportedItem {
699 fn id(&self) -> ItemId {
700 self.id
701 }
702 fn debug_name(&self, _: &IR) -> Rc<str> {
703 self.name.clone()
704 }
705 fn source_loc(&self) -> Option<Rc<str>> {
706 self.source_loc.clone()
707 }
708}
709
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700710impl UnsupportedItem {
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700711 fn new(ir: &IR, item: &impl GenericItem, message: Rc<str>, cause: Option<Error>) -> Self {
Googlerc2102ee2022-11-29 07:18:24 -0800712 Self {
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700713 name: item.debug_name(ir),
714 message,
715 source_loc: item.source_loc(),
716 id: item.id(),
717 cause: IgnoredField(cause.map(OnceCell::from).unwrap_or_default()),
Googlerc2102ee2022-11-29 07:18:24 -0800718 }
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700719 }
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700720
721 pub fn new_with_message(ir: &IR, item: &impl GenericItem, message: impl Into<Rc<str>>) -> Self {
722 Self::new(ir, item, message.into(), None)
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700723 }
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700724 pub fn new_with_cause(ir: &IR, item: &impl GenericItem, cause: Error) -> Self {
Devin Jeanpierre851a6412023-04-13 14:38:14 -0700725 Self::new(ir, item, format!("{cause:#}").into(), Some(cause))
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700726 }
727
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700728 pub fn message(&self) -> &str {
Googlerc2102ee2022-11-29 07:18:24 -0800729 self.message.as_ref()
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700730 }
731
732 pub fn cause(&self) -> &Error {
Googlerc2102ee2022-11-29 07:18:24 -0800733 self.cause.0.get_or_init(|| anyhow!(self.message.as_ref().to_owned()))
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700734 }
Michael Forster523dbd42021-10-12 11:05:44 +0000735}
736
737#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800738#[serde(deny_unknown_fields)]
Michael Forsterf1dce422021-10-13 09:50:16 +0000739pub struct Comment {
Googlerc2102ee2022-11-29 07:18:24 -0800740 pub text: Rc<str>,
Rosica Dejanovskad638cf52022-03-23 15:45:01 +0000741 pub id: ItemId,
Michael Forsterf1dce422021-10-13 09:50:16 +0000742}
743
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700744impl GenericItem for Comment {
745 fn id(&self) -> ItemId {
746 self.id
747 }
748 fn debug_name(&self, _: &IR) -> Rc<str> {
749 "comment".into()
750 }
751 fn source_loc(&self) -> Option<Rc<str>> {
752 None
753 }
754}
755
Michael Forsterf1dce422021-10-13 09:50:16 +0000756#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800757#[serde(deny_unknown_fields)]
Rosica Dejanovskadd9a9032022-04-12 07:34:41 -0700758pub struct Namespace {
759 pub name: Identifier,
760 pub id: ItemId,
Rosica Dejanovska6efd17f2022-05-11 08:09:57 -0700761 pub canonical_namespace_id: ItemId,
Rosica Dejanovska36aefad2022-05-12 03:53:14 -0700762 pub owning_target: BazelLabel,
Rosica Dejanovskadd9a9032022-04-12 07:34:41 -0700763 #[serde(default)]
764 pub child_item_ids: Vec<ItemId>,
Rosica Dejanovskae91d2992022-05-05 05:31:39 -0700765 pub enclosing_namespace_id: Option<ItemId>,
Devin Jeanpierrefe6aaea2022-09-09 12:33:50 -0700766 pub is_inline: bool,
Rosica Dejanovskadd9a9032022-04-12 07:34:41 -0700767}
768
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700769impl GenericItem for Namespace {
770 fn id(&self) -> ItemId {
771 self.id
772 }
773 fn debug_name(&self, _: &IR) -> Rc<str> {
774 self.name.to_string().into()
775 }
776 fn source_loc(&self) -> Option<Rc<str>> {
777 None
778 }
779}
780
Rosica Dejanovskadd9a9032022-04-12 07:34:41 -0700781#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -0800782#[serde(deny_unknown_fields)]
Devin Jeanpierre96bf0bd2022-10-04 20:32:15 -0700783pub struct UseMod {
784 pub path: Rc<str>,
785 pub mod_name: Identifier,
786 pub id: ItemId,
787}
788
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700789impl GenericItem for UseMod {
790 fn id(&self) -> ItemId {
791 self.id
792 }
793 fn debug_name(&self, _: &IR) -> Rc<str> {
794 format!("[internal] use mod {}::* = {}", self.mod_name, self.path).into()
795 }
796 fn source_loc(&self) -> Option<Rc<str>> {
797 None
798 }
799}
800
Devin Jeanpierre96bf0bd2022-10-04 20:32:15 -0700801#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Devin Jeanpierre93e800e2023-05-08 12:55:53 -0700802#[serde(deny_unknown_fields)]
803pub struct TypeMapOverride {
Devin Jeanpierreb7f8e282023-05-26 16:03:12 -0700804 pub rs_name: Rc<str>,
805 pub cc_name: Rc<str>,
Devin Jeanpierre93e800e2023-05-08 12:55:53 -0700806 pub owning_target: BazelLabel,
Devin Jeanpierre1e2d3242023-05-15 12:21:59 -0700807 pub size_align: Option<SizeAlign>,
Devin Jeanpierrec850c772023-05-30 17:14:19 -0700808 pub is_same_abi: bool,
Devin Jeanpierre93e800e2023-05-08 12:55:53 -0700809 pub id: ItemId,
810}
811
812impl GenericItem for TypeMapOverride {
813 fn id(&self) -> ItemId {
814 self.id
815 }
816 fn debug_name(&self, _: &IR) -> Rc<str> {
Devin Jeanpierreb7f8e282023-05-26 16:03:12 -0700817 self.cc_name.clone()
Devin Jeanpierre93e800e2023-05-08 12:55:53 -0700818 }
819 fn source_loc(&self) -> Option<Rc<str>> {
820 None
821 }
822}
823
824#[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
Michael Forster7ef80732021-10-01 18:12:19 +0000825pub enum Item {
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700826 Func(Rc<Func>),
827 IncompleteRecord(Rc<IncompleteRecord>),
828 Record(Rc<Record>),
829 Enum(Rc<Enum>),
830 TypeAlias(Rc<TypeAlias>),
831 UnsupportedItem(Rc<UnsupportedItem>),
832 Comment(Rc<Comment>),
833 Namespace(Rc<Namespace>),
Devin Jeanpierre96bf0bd2022-10-04 20:32:15 -0700834 UseMod(Rc<UseMod>),
Devin Jeanpierre93e800e2023-05-08 12:55:53 -0700835 TypeMapOverride(Rc<TypeMapOverride>),
Michael Forster7ef80732021-10-01 18:12:19 +0000836}
837
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700838macro_rules! forward_item {
839 (match $item:ident { _($item_name:ident) => $expr:expr $(,)? }) => {
840 match $item {
Devin Jeanpierre93e800e2023-05-08 12:55:53 -0700841 Item::Func($item_name) => $expr,
842 Item::IncompleteRecord($item_name) => $expr,
843 Item::Record($item_name) => $expr,
844 Item::Enum($item_name) => $expr,
845 Item::TypeAlias($item_name) => $expr,
846 Item::UnsupportedItem($item_name) => $expr,
847 Item::Comment($item_name) => $expr,
848 Item::Namespace($item_name) => $expr,
849 Item::UseMod($item_name) => $expr,
850 Item::TypeMapOverride($item_name) => $expr,
851 }
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700852 };
853}
854
855impl GenericItem for Item {
Rosica Dejanovska10accf12022-03-31 04:47:58 -0700856 fn id(&self) -> ItemId {
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700857 forward_item! {
858 match self {
859 _(x) => x.id()
860 }
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +0000861 }
862 }
Devin Jeanpierreab8732a2023-03-22 19:09:03 -0700863 fn debug_name(&self, ir: &IR) -> Rc<str> {
864 forward_item! {
865 match self {
866 _(x) => x.debug_name(ir)
867 }
868 }
869 }
870 fn source_loc(&self) -> Option<Rc<str>> {
871 forward_item! {
872 match self {
873 _(x) => x.source_loc()
874 }
875 }
876 }
877}
878
879impl Item {
Rosica Dejanovskae91d2992022-05-05 05:31:39 -0700880 pub fn enclosing_namespace_id(&self) -> Option<ItemId> {
881 match self {
882 Item::Record(record) => record.enclosing_namespace_id,
883 Item::IncompleteRecord(record) => record.enclosing_namespace_id,
884 Item::Enum(enum_) => enum_.enclosing_namespace_id,
885 Item::Func(func) => func.enclosing_namespace_id,
886 Item::Namespace(namespace) => namespace.enclosing_namespace_id,
887 Item::TypeAlias(type_alias) => type_alias.enclosing_namespace_id,
Devin Jeanpierreec88b692023-02-14 07:03:08 -0800888 Item::Comment(..) => None,
889 Item::UnsupportedItem(..) => None,
890 Item::UseMod(..) => None,
Devin Jeanpierre93e800e2023-05-08 12:55:53 -0700891 Item::TypeMapOverride(..) => None,
Devin Jeanpierreec88b692023-02-14 07:03:08 -0800892 }
893 }
894
Devin Jeanpierre3f0d0682023-04-13 14:47:28 -0700895 /// Returns the target that this was defined in, if it was defined somewhere
896 /// other than `owning_target()`.
Devin Jeanpierredff65282023-03-14 20:32:28 -0700897 pub fn defining_target(&self) -> Option<&BazelLabel> {
Devin Jeanpierre3f0d0682023-04-13 14:47:28 -0700898 match self {
899 Item::Record(record) => record.defining_target.as_ref(),
900 _ => None,
901 }
Devin Jeanpierredff65282023-03-14 20:32:28 -0700902 }
903
Devin Jeanpierreec88b692023-02-14 07:03:08 -0800904 /// Returns the target that this should generate source code in.
905 pub fn owning_target(&self) -> Option<&BazelLabel> {
906 match self {
Devin Jeanpierre6b1d71a2023-03-14 17:50:38 -0700907 Item::Func(func) => Some(&func.owning_target),
Devin Jeanpierreec88b692023-02-14 07:03:08 -0800908 Item::IncompleteRecord(record) => Some(&record.owning_target),
909 Item::Record(record) => Some(&record.owning_target),
910 Item::Enum(e) => Some(&e.owning_target),
911 Item::TypeAlias(type_alias) => Some(&type_alias.owning_target),
912 Item::UnsupportedItem(..) => None,
913 Item::Comment(..) => None,
914 Item::Namespace(..) => None,
915 Item::UseMod(..) => None,
Devin Jeanpierre93e800e2023-05-08 12:55:53 -0700916 Item::TypeMapOverride(type_override) => Some(&type_override.owning_target),
Rosica Dejanovskae91d2992022-05-05 05:31:39 -0700917 }
918 }
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +0000919}
920
Devin Jeanpierreccfefc82021-10-27 10:54:00 +0000921impl From<Func> for Item {
922 fn from(func: Func) -> Item {
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700923 Item::Func(Rc::new(func))
Devin Jeanpierreccfefc82021-10-27 10:54:00 +0000924 }
925}
926
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700927impl<'a> TryFrom<&'a Item> for &'a Rc<Func> {
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700928 type Error = Error;
Devin Jeanpierre7eb04042021-12-03 07:19:22 +0000929 fn try_from(value: &'a Item) -> Result<Self, Self::Error> {
Devin Jeanpierre3a0cc5a2022-07-12 09:36:34 -0700930 if let Item::Func(f) = value { Ok(f) } else { bail!("Not a Func: {:#?}", value) }
Devin Jeanpierre7eb04042021-12-03 07:19:22 +0000931 }
932}
933
Devin Jeanpierreccfefc82021-10-27 10:54:00 +0000934impl From<Record> for Item {
935 fn from(record: Record) -> Item {
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700936 Item::Record(Rc::new(record))
Devin Jeanpierreccfefc82021-10-27 10:54:00 +0000937 }
938}
939
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700940impl<'a> TryFrom<&'a Item> for &'a Rc<Record> {
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700941 type Error = Error;
Devin Jeanpierre7eb04042021-12-03 07:19:22 +0000942 fn try_from(value: &'a Item) -> Result<Self, Self::Error> {
Devin Jeanpierre7ed8c6f2022-08-01 13:41:02 -0700943 if let Item::Record(r) = value { Ok(r) } else { bail!("Not a Record: {:#?}", value) }
Devin Jeanpierre7eb04042021-12-03 07:19:22 +0000944 }
945}
946
Devin Jeanpierreccfefc82021-10-27 10:54:00 +0000947impl From<UnsupportedItem> for Item {
948 fn from(unsupported: UnsupportedItem) -> Item {
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700949 Item::UnsupportedItem(Rc::new(unsupported))
Devin Jeanpierreccfefc82021-10-27 10:54:00 +0000950 }
951}
952
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700953impl<'a> TryFrom<&'a Item> for &'a Rc<UnsupportedItem> {
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700954 type Error = Error;
Devin Jeanpierre7eb04042021-12-03 07:19:22 +0000955 fn try_from(value: &'a Item) -> Result<Self, Self::Error> {
956 if let Item::UnsupportedItem(u) = value {
957 Ok(u)
958 } else {
Devin Jeanpierre3a0cc5a2022-07-12 09:36:34 -0700959 bail!("Not an UnsupportedItem: {:#?}", value)
Devin Jeanpierre7eb04042021-12-03 07:19:22 +0000960 }
961 }
962}
963
Devin Jeanpierreccfefc82021-10-27 10:54:00 +0000964impl From<Comment> for Item {
965 fn from(comment: Comment) -> Item {
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700966 Item::Comment(Rc::new(comment))
Devin Jeanpierreccfefc82021-10-27 10:54:00 +0000967 }
968}
969
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -0700970impl<'a> TryFrom<&'a Item> for &'a Rc<Comment> {
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -0700971 type Error = Error;
Devin Jeanpierre7eb04042021-12-03 07:19:22 +0000972 fn try_from(value: &'a Item) -> Result<Self, Self::Error> {
Devin Jeanpierre7ed8c6f2022-08-01 13:41:02 -0700973 if let Item::Comment(c) = value { Ok(c) } else { bail!("Not a Comment: {:#?}", value) }
Devin Jeanpierre7eb04042021-12-03 07:19:22 +0000974 }
975}
976
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -0800977flagset::flags! {
978 pub enum CrubitFeature : u8 {
979 Supported,
980 /// Experimental is never *set* without also setting Supported, but we allow it to be
981 /// *required* without also requiring Supported, so that error messages can be more direct.
982 Experimental,
983 }
984}
985
986impl CrubitFeature {
987 /// The name of this feature.
988 pub fn short_name(&self) -> &'static str {
989 match self {
990 Self::Supported => "supported",
991 Self::Experimental => "experimental",
992 }
993 }
Devin Jeanpierredff65282023-03-14 20:32:28 -0700994
995 /// The aspect hint required to enable this feature.
996 pub fn aspect_hint(&self) -> &'static str {
997 match self {
Lukasz Anforowiczaaa2a0f2023-04-11 09:01:14 -0700998 Self::Supported => "//:supported",
999 Self::Experimental => "//:experimental",
Devin Jeanpierredff65282023-03-14 20:32:28 -07001000 }
1001 }
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -08001002}
1003
1004/// A newtype around a flagset of features, so that it can be deserialized from
1005/// an array of strings instead of an integer.
1006#[derive(Debug, Default, PartialEq, Eq, Clone)]
1007struct CrubitFeaturesIR(pub(crate) flagset::FlagSet<CrubitFeature>);
1008
1009impl<'de> serde::Deserialize<'de> for CrubitFeaturesIR {
1010 fn deserialize<D>(deserializer: D) -> Result<CrubitFeaturesIR, D::Error>
1011 where
1012 D: serde::Deserializer<'de>,
1013 {
1014 let mut features = flagset::FlagSet::<CrubitFeature>::default();
1015 for feature in <Vec<String> as serde::Deserialize<'de>>::deserialize(deserializer)? {
1016 features |= match &*feature {
1017 "experimental" => CrubitFeature::Experimental,
1018 "supported" => CrubitFeature::Supported,
1019 other => {
1020 return Err(<D::Error as serde::de::Error>::custom(format!(
1021 "Unexpected Crubit feature: {other}"
1022 )));
1023 }
1024 };
1025 }
1026 Ok(CrubitFeaturesIR(features))
1027 }
1028}
1029
Devin Jeanpierre319bcac2023-03-14 17:49:08 -07001030#[derive(PartialEq, Eq, Clone, Deserialize)]
Devin Jeanpierref2384032023-03-10 14:26:27 -08001031#[serde(deny_unknown_fields, rename(deserialize = "IR"))]
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001032struct FlatIR {
1033 #[serde(default)]
Lukasz Anforowicz121338a2022-11-01 14:28:32 -07001034 public_headers: Vec<HeaderName>,
Googler6c3de122022-03-28 11:40:41 +00001035 current_target: BazelLabel,
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001036 #[serde(default)]
1037 items: Vec<Item>,
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -07001038 #[serde(default)]
1039 top_level_item_ids: Vec<ItemId>,
Marcel Hlopkob4d5d8e2022-11-16 03:15:00 -08001040 #[serde(default)]
Googler841386c2022-11-29 07:42:32 -08001041 crate_root_path: Option<Rc<str>>,
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -08001042 #[serde(default)]
1043 crubit_features: HashMap<BazelLabel, CrubitFeaturesIR>,
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001044}
1045
Devin Jeanpierre319bcac2023-03-14 17:49:08 -07001046/// A custom debug impl that wraps the HashMap in rustfmt-friendly notation.
1047///
1048/// See b/272530008.
Devin Jeanpierreab8732a2023-03-22 19:09:03 -07001049impl Debug for FlatIR {
1050 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Devin Jeanpierre319bcac2023-03-14 17:49:08 -07001051 struct DebugHashMap<T: Debug>(pub T);
Devin Jeanpierreab8732a2023-03-22 19:09:03 -07001052 impl<T: Debug> Debug for DebugHashMap<T> {
1053 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Devin Jeanpierre319bcac2023-03-14 17:49:08 -07001054 // prefix the hash map with `hash_map!` so that the output can be fed to
1055 // rustfmt. The end result is something like `hash_map!{k:v,
1056 // k2:v2}`, which reads well.
1057 write!(f, "hash_map!")?;
Devin Jeanpierreab8732a2023-03-22 19:09:03 -07001058 Debug::fmt(&self.0, f)
Devin Jeanpierre319bcac2023-03-14 17:49:08 -07001059 }
1060 }
1061 // exhaustive-match so we don't forget to add fields to Debug when we add to
1062 // FlatIR.
1063 let FlatIR {
1064 public_headers,
1065 current_target,
1066 items,
1067 top_level_item_ids,
1068 crate_root_path,
1069 crubit_features,
1070 } = self;
1071 f.debug_struct("FlatIR")
1072 .field("public_headers", public_headers)
1073 .field("current_target", current_target)
1074 .field("items", items)
1075 .field("top_level_item_ids", top_level_item_ids)
1076 .field("crate_root_path", crate_root_path)
1077 .field("crubit_features", &DebugHashMap(crubit_features))
1078 .finish()
1079 }
1080}
1081
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001082/// Struct providing the necessary information about the API of a C++ target to
1083/// enable generation of Rust bindings source code (both `rs_api.rs` and
1084/// `rs_api_impl.cc` files).
1085#[derive(PartialEq, Debug)]
Marcel Hlopko42abfc82021-08-09 07:03:17 +00001086pub struct IR {
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001087 flat_ir: FlatIR,
1088 // A map from a `decl_id` to an index of an `Item` in the `flat_ir.items` vec.
Rosica Dejanovskad638cf52022-03-23 15:45:01 +00001089 item_id_to_item_idx: HashMap<ItemId, usize>,
Marcel Hlopkoaf682a02022-04-08 07:27:14 -07001090 lifetimes: HashMap<LifetimeId, LifetimeName>,
Rosica Dejanovska93aeafb2022-06-01 07:05:31 -07001091 namespace_id_to_number_of_reopened_namespaces: HashMap<ItemId, usize>,
1092 reopened_namespace_id_to_idx: HashMap<ItemId, usize>,
Felipe de A. Mello Pereira3a953722023-03-02 05:37:36 -08001093 function_name_to_functions: HashMap<UnqualifiedIdentifier, Vec<Rc<Func>>>,
Michael Forster7ef80732021-10-01 18:12:19 +00001094}
1095
1096impl IR {
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001097 pub fn items(&self) -> impl Iterator<Item = &Item> {
1098 self.flat_ir.items.iter()
1099 }
1100
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -07001101 pub fn top_level_item_ids(&self) -> impl Iterator<Item = &ItemId> {
1102 self.flat_ir.top_level_item_ids.iter()
1103 }
1104
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001105 pub fn items_mut(&mut self) -> impl Iterator<Item = &mut Item> {
1106 self.flat_ir.items.iter_mut()
1107 }
1108
Lukasz Anforowicz121338a2022-11-01 14:28:32 -07001109 pub fn public_headers(&self) -> impl Iterator<Item = &HeaderName> {
1110 self.flat_ir.public_headers.iter()
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001111 }
1112
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -07001113 pub fn functions(&self) -> impl Iterator<Item = &Rc<Func>> {
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001114 self.items().filter_map(|item| match item {
Michael Forster7ef80732021-10-01 18:12:19 +00001115 Item::Func(func) => Some(func),
1116 _ => None,
1117 })
1118 }
1119
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -07001120 pub fn records(&self) -> impl Iterator<Item = &Rc<Record>> {
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001121 self.items().filter_map(|item| match item {
Michael Forster7ef80732021-10-01 18:12:19 +00001122 Item::Record(func) => Some(func),
1123 _ => None,
1124 })
1125 }
Marcel Hlopkoc0956cf2021-11-29 08:31:28 +00001126
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -07001127 pub fn unsupported_items(&self) -> impl Iterator<Item = &Rc<UnsupportedItem>> {
Marcel Hlopko4c660dd2021-12-02 09:52:47 +00001128 self.items().filter_map(|item| match item {
1129 Item::UnsupportedItem(unsupported_item) => Some(unsupported_item),
1130 _ => None,
1131 })
1132 }
1133
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -07001134 pub fn comments(&self) -> impl Iterator<Item = &Rc<Comment>> {
Rosica Dejanovskad638cf52022-03-23 15:45:01 +00001135 self.items().filter_map(|item| match item {
1136 Item::Comment(comment) => Some(comment),
1137 _ => None,
1138 })
1139 }
1140
Devin Jeanpierre8cd8ae72022-06-29 18:59:40 -07001141 pub fn namespaces(&self) -> impl Iterator<Item = &Rc<Namespace>> {
Rosica Dejanovskadd9a9032022-04-12 07:34:41 -07001142 self.items().filter_map(|item| match item {
1143 Item::Namespace(ns) => Some(ns),
1144 _ => None,
1145 })
1146 }
1147
Googler6a0a5252022-01-11 14:08:09 +00001148 pub fn item_for_type<T>(&self, ty: &T) -> Result<&Item>
Marcel Hlopkoc0956cf2021-11-29 08:31:28 +00001149 where
Michael VanBemmelf5cbdf42022-10-14 17:00:11 -07001150 T: TypeWithDeclId + Debug,
Marcel Hlopkoc0956cf2021-11-29 08:31:28 +00001151 {
Marcel Hlopko264b9ad2021-12-02 21:06:44 +00001152 if let Some(decl_id) = ty.decl_id() {
Lukasz Anforowicze1ade882023-05-15 11:23:47 -07001153 Ok(self.find_untyped_decl(decl_id))
Marcel Hlopkoc0956cf2021-11-29 08:31:28 +00001154 } else {
Googler6a0a5252022-01-11 14:08:09 +00001155 bail!("Type {:?} does not have an associated item.", ty)
Marcel Hlopkoc0956cf2021-11-29 08:31:28 +00001156 }
1157 }
Devin Jeanpierre7eb04042021-12-03 07:19:22 +00001158
Rosica Dejanovskad638cf52022-03-23 15:45:01 +00001159 pub fn find_decl<'a, T>(&'a self, decl_id: ItemId) -> Result<&'a T>
Lukasz Anforowicz44047252022-03-23 13:04:48 +00001160 where
1161 &'a T: TryFrom<&'a Item>,
1162 {
Lukasz Anforowicze1ade882023-05-15 11:23:47 -07001163 self.find_untyped_decl(decl_id).try_into().map_err(|_| {
1164 anyhow!("DeclId {:?} doesn't refer to a {}", decl_id, std::any::type_name::<T>())
Lukasz Anforowicz44047252022-03-23 13:04:48 +00001165 })
1166 }
1167
Lukasz Anforowicze1ade882023-05-15 11:23:47 -07001168 fn find_untyped_decl(&self, decl_id: ItemId) -> &Item {
Devin Jeanpierre7eb04042021-12-03 07:19:22 +00001169 let idx = *self
Rosica Dejanovskad638cf52022-03-23 15:45:01 +00001170 .item_id_to_item_idx
Devin Jeanpierre7eb04042021-12-03 07:19:22 +00001171 .get(&decl_id)
Lukasz Anforowicze1ade882023-05-15 11:23:47 -07001172 .unwrap_or_else(|| panic!("Couldn't find decl_id {:?} in the IR.", decl_id));
1173 self.flat_ir
1174 .items
1175 .get(idx)
1176 .unwrap_or_else(|| panic!("Couldn't find an item at idx {}", idx))
Devin Jeanpierre7eb04042021-12-03 07:19:22 +00001177 }
Marcel Hlopkoa0f38662021-12-03 08:45:26 +00001178
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -08001179 /// Returns whether `target` is the current target.
Googler6c3de122022-03-28 11:40:41 +00001180 pub fn is_current_target(&self, target: &BazelLabel) -> bool {
Marcel Hlopkoa0f38662021-12-03 08:45:26 +00001181 // TODO(hlopko): Make this be a pointer comparison, now it's comparing string
1182 // values.
Lukasz Anforowicz5b3f5302022-02-07 01:04:47 +00001183 *target == *self.current_target()
1184 }
1185
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -08001186 /// Returns the Crubit features enabled for the given `target`.
1187 #[must_use]
1188 pub fn target_crubit_features(&self, target: &BazelLabel) -> flagset::FlagSet<CrubitFeature> {
1189 self.flat_ir.crubit_features.get(target).cloned().unwrap_or_default().0
1190 }
1191
Devin Jeanpierre319bcac2023-03-14 17:49:08 -07001192 /// Returns a mutable reference to the Crubit features enabled for the given
1193 /// `target`.
1194 ///
1195 /// Since IR is generally only held immutably, this is only useful for
1196 /// testing.
1197 #[must_use]
1198 pub fn target_crubit_features_mut(
1199 &mut self,
1200 target: &BazelLabel,
1201 ) -> &mut flagset::FlagSet<CrubitFeature> {
1202 // TODO(jeanpierreda): migrate to raw_entry_mut when stable.
1203 // (target is taken by reference exactly because ideally this function would use
1204 // the raw entry API.)
1205 &mut self.flat_ir.crubit_features.entry(target.clone()).or_default().0
1206 }
1207
Googler6c3de122022-03-28 11:40:41 +00001208 pub fn current_target(&self) -> &BazelLabel {
Lukasz Anforowicz5b3f5302022-02-07 01:04:47 +00001209 &self.flat_ir.current_target
Googler6a0a5252022-01-11 14:08:09 +00001210 }
1211
Marcel Hlopko016cab02021-12-16 14:29:35 +00001212 // Returns the standard Debug print string for the `flat_ir`. The reason why we
1213 // don't use the debug print of `Self` is that `Self` contains HashMaps, and
1214 // their debug print produces content that is not valid Rust code.
1215 // `token_stream_matchers` (hacky) implementation parses the debug print and
1216 // chokes on HashMaps. Therefore this method.
1217 //
1218 // Used for `token_stream_matchers`, do not use for anything else.
1219 pub fn flat_ir_debug_print(&self) -> String {
1220 format!("{:?}", self.flat_ir)
1221 }
Devin Jeanpierre9886fb42022-04-01 04:31:20 -07001222
Marcel Hlopkoaf682a02022-04-08 07:27:14 -07001223 pub fn get_lifetime(&self, lifetime_id: LifetimeId) -> Option<&LifetimeName> {
Devin Jeanpierred2b7a8f2022-04-01 04:37:16 -07001224 self.lifetimes.get(&lifetime_id)
Devin Jeanpierre9886fb42022-04-01 04:31:20 -07001225 }
Rosica Dejanovska93aeafb2022-06-01 07:05:31 -07001226
1227 pub fn get_reopened_namespace_idx(&self, id: ItemId) -> Result<usize> {
1228 Ok(*self.reopened_namespace_id_to_idx.get(&id).with_context(|| {
1229 format!("Could not find the reopened namespace index for namespace {:?}.", id)
1230 })?)
1231 }
1232
1233 pub fn is_last_reopened_namespace(&self, id: ItemId, canonical_id: ItemId) -> Result<bool> {
1234 let idx = self.get_reopened_namespace_idx(id)?;
1235 let last_item_idx = self
1236 .namespace_id_to_number_of_reopened_namespaces
1237 .get(&canonical_id)
1238 .with_context(|| {
1239 format!(
1240 "Could not find number of reopened namespaces for namespace {:?}.",
1241 canonical_id
1242 )
1243 })? - 1;
1244 Ok(idx == last_item_idx)
1245 }
Devin Jeanpierrebdfb4d92022-06-17 01:17:01 -07001246
Devin Jeanpierreb7f8e282023-05-26 16:03:12 -07001247 /// Returns the `Item` defining `func`, or `None` if `func` is not a
Devin Jeanpierrebdfb4d92022-06-17 01:17:01 -07001248 /// member function.
1249 ///
Devin Jeanpierreb7f8e282023-05-26 16:03:12 -07001250 /// Note that even if `func` is a member function, the associated record
1251 /// might not be a Record IR Item (e.g. it has its type changed via
1252 /// crubit_internal_rust_type).
1253 pub fn record_for_member_func(&self, func: &Func) -> Option<&Item> {
Devin Jeanpierrebdfb4d92022-06-17 01:17:01 -07001254 if let Some(meta) = func.member_func_metadata.as_ref() {
Devin Jeanpierreb7f8e282023-05-26 16:03:12 -07001255 Some(self.find_untyped_decl(meta.record_id))
Devin Jeanpierrebdfb4d92022-06-17 01:17:01 -07001256 } else {
Devin Jeanpierre95b7c2f2023-03-14 21:01:16 -07001257 None
Devin Jeanpierrebdfb4d92022-06-17 01:17:01 -07001258 }
1259 }
Marcel Hlopkob4d5d8e2022-11-16 03:15:00 -08001260
Lukasz Anforowicz8e5042c2023-01-03 11:19:07 -08001261 pub fn crate_root_path(&self) -> Option<Rc<str>> {
1262 self.flat_ir.crate_root_path.clone()
Marcel Hlopkob4d5d8e2022-11-16 03:15:00 -08001263 }
Felipe de A. Mello Pereira3a953722023-03-02 05:37:36 -08001264
1265 pub fn get_functions_by_name(
1266 &self,
1267 function_name: &UnqualifiedIdentifier,
1268 ) -> impl Iterator<Item = &Rc<Func>> {
1269 self.function_name_to_functions.get(function_name).map_or([].iter(), |v| v.iter())
1270 }
Marcel Hlopko42abfc82021-08-09 07:03:17 +00001271}
1272
1273#[cfg(test)]
1274mod tests {
1275 use super::*;
1276
1277 #[test]
Marcel Hlopkoafdc5022021-12-16 14:31:19 +00001278 fn test_identifier_debug_print() {
Lukasz Anforowicz8c1a6c42022-11-23 16:18:09 -08001279 assert_eq!(format!("{:?}", Identifier { identifier: "hello".into() }), "\"hello\"");
Marcel Hlopkoafdc5022021-12-16 14:31:19 +00001280 }
1281
1282 #[test]
1283 fn test_unqualified_identifier_debug_print() {
1284 assert_eq!(
1285 format!(
1286 "{:?}",
Lukasz Anforowicz8c1a6c42022-11-23 16:18:09 -08001287 UnqualifiedIdentifier::Identifier(Identifier { identifier: "hello".into() })
Marcel Hlopkoafdc5022021-12-16 14:31:19 +00001288 ),
1289 "\"hello\""
1290 );
1291 assert_eq!(format!("{:?}", UnqualifiedIdentifier::Constructor), "Constructor");
1292 assert_eq!(format!("{:?}", UnqualifiedIdentifier::Destructor), "Destructor");
1293 }
1294
1295 #[test]
Googlera9214632021-09-17 08:16:29 +00001296 fn test_used_headers() {
Marcel Hlopko42abfc82021-08-09 07:03:17 +00001297 let input = r#"
1298 {
Lukasz Anforowicz121338a2022-11-01 14:28:32 -07001299 "public_headers": [{ "name": "foo/bar.h" }],
Marcel Hlopko80441c12021-11-12 10:43:18 +00001300 "current_target": "//foo:bar"
Googlera9214632021-09-17 08:16:29 +00001301 }
1302 "#;
1303 let ir = deserialize_ir(input.as_bytes()).unwrap();
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001304 let expected = FlatIR {
Lukasz Anforowicz121338a2022-11-01 14:28:32 -07001305 public_headers: vec![HeaderName { name: "foo/bar.h".into() }],
Marcel Hlopko80441c12021-11-12 10:43:18 +00001306 current_target: "//foo:bar".into(),
Rosica Dejanovskab2bd59e2022-04-11 09:02:03 -07001307 top_level_item_ids: vec![],
Marcel Hlopko80441c12021-11-12 10:43:18 +00001308 items: vec![],
Marcel Hlopkob4d5d8e2022-11-16 03:15:00 -08001309 crate_root_path: None,
Devin Jeanpierre6ed0f602023-03-01 17:22:54 -08001310 crubit_features: Default::default(),
Googlera9214632021-09-17 08:16:29 +00001311 };
Marcel Hlopko3b9bf9e2021-11-29 08:25:14 +00001312 assert_eq!(ir.flat_ir, expected);
Googlera9214632021-09-17 08:16:29 +00001313 }
Marcel Hlopkob4d5d8e2022-11-16 03:15:00 -08001314
1315 #[test]
1316 fn test_empty_crate_root_path() {
1317 let input = "{ \"current_target\": \"//foo:bar\" }";
1318 let ir = deserialize_ir(input.as_bytes()).unwrap();
1319 assert_eq!(ir.crate_root_path(), None);
1320 }
1321
1322 #[test]
1323 fn test_crate_root_path() {
1324 let input = r#"
1325 {
1326 "crate_root_path": "__cc_template_instantiations_rs_api",
1327 "current_target": "//foo:bar"
1328 }
1329 "#;
1330 let ir = deserialize_ir(input.as_bytes()).unwrap();
Lukasz Anforowicz8e5042c2023-01-03 11:19:07 -08001331 assert_eq!(ir.crate_root_path().as_deref(), Some("__cc_template_instantiations_rs_api"));
Marcel Hlopkob4d5d8e2022-11-16 03:15:00 -08001332 }
Devin Jeanpierre89230f32023-03-15 12:27:02 -07001333
1334 #[test]
1335 fn test_bazel_label_target() {
1336 let label: BazelLabel = "//foo:bar".into();
1337 assert_eq!(label.target_name(), "bar");
1338 }
1339
1340 #[test]
1341 fn test_bazel_label_target_dotless() {
1342 let label: BazelLabel = "//foo".into();
1343 assert_eq!(label.target_name(), "foo");
1344 }
1345
1346 #[test]
1347 fn test_bazel_label_dotless_slashless() {
1348 let label: BazelLabel = "foo".into();
1349 assert_eq!(label.target_name(), "foo");
1350 }
1351
1352 /// These are not labels, but there is an unambiguous interpretation of
1353 /// what their target should be that lets us keep going.
1354 #[test]
1355 fn test_bazel_label_empty_target() {
1356 for s in ["foo:", "foo/", ""] {
1357 let label: BazelLabel = s.into();
1358 assert_eq!(label.target_name(), "", "label={s:?}");
1359 }
1360 }
Marcel Hlopko42abfc82021-08-09 07:03:17 +00001361}