1use rustc_hir::def_id::DefId;
2use rustc_middle::ty::{Ty, TyCtxt, TyKind};
3use serde_json::Value;
4use syn::Expr;
5
6pub fn get_cleaned_def_path_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
13 let def_id_str = format!("{:?}", def_id);
14 let mut parts: Vec<&str> = def_id_str.split("::").collect();
15
16 let mut remove_first = false;
17 if let Some(first_part) = parts.get_mut(0) {
18 if first_part.contains("core") {
19 *first_part = "core";
20 } else if first_part.contains("std") {
21 *first_part = "std";
22 } else if first_part.contains("alloc") {
23 *first_part = "alloc";
24 } else {
25 remove_first = true;
26 }
27 }
28 if remove_first && !parts.is_empty() {
29 parts.remove(0);
30 }
31
32 let new_parts: Vec<String> = parts
33 .into_iter()
34 .filter_map(|s| {
35 if s.contains("{") {
36 if remove_first {
37 get_struct_name(tcx, def_id)
38 } else {
39 None
40 }
41 } else {
42 Some(s.to_string())
43 }
44 })
45 .collect();
46
47 let mut cleaned_path = new_parts.join("::");
48 cleaned_path = cleaned_path.trim_end_matches(')').to_string();
49 cleaned_path
50}
51
52pub fn get_struct_name(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
55 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
56 if let Some(impl_id) = assoc_item.impl_container(tcx) {
57 let ty = tcx.type_of(impl_id).skip_binder();
58 let type_name = ty.to_string();
59 let struct_name = type_name
60 .split('<')
61 .next()
62 .unwrap_or("")
63 .split("::")
64 .last()
65 .unwrap_or("")
66 .to_string();
67
68 return Some(struct_name);
69 }
70 }
71 None
72}
73
74pub fn get_struct_self_ty<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Ty<'tcx>> {
77 let assoc_item = tcx.opt_associated_item(def_id)?;
78 let impl_id = assoc_item.impl_container(tcx)?;
79 let self_ty = tcx.type_of(impl_id).skip_binder();
80 match self_ty.kind() {
81 TyKind::Adt(_, _) => Some(self_ty),
82 _ => None,
83 }
84}
85
86pub fn get_std_api_signature_json() -> Value {
89 serde_json::from_str(include_str!("data/std_sig.json")).expect("Unable to parse JSON")
90}
91
92pub fn get_known_std_names<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Vec<String>> {
98 let std_func_name = get_cleaned_def_path_name(tcx, def_id);
99 let json_data = get_std_api_signature_json();
100
101 if let Some(arg_info) = json_data.get(&std_func_name) {
102 if let Some(args_name) = arg_info.as_array() {
103 if args_name.is_empty() {
104 return Some(vec!["0".to_string()]);
105 }
106 let mut result = Vec::new();
107 for arg in args_name {
108 if let Some(sp_name) = arg.as_str() {
109 result.push(sp_name.to_string());
110 }
111 }
112 return Some(result);
113 }
114 }
115 None
116}
117
118fn extract_pat_ident(pat: &rustc_hir::Pat<'_>) -> Option<rustc_span::symbol::Ident> {
122 match &pat.kind {
123 rustc_hir::PatKind::Binding(_, _, ident, _) => Some(*ident),
124 rustc_hir::PatKind::Ref(inner, ..) => extract_pat_ident(inner),
125 _ => None,
126 }
127}
128
129pub fn parse_local_signature<'tcx>(
130 tcx: TyCtxt<'tcx>,
131 def_id: DefId,
132) -> (Vec<String>, Vec<Ty<'tcx>>) {
133 let local_def_id = def_id.as_local().unwrap();
134 let hir_body = tcx.hir_body_owned_by(local_def_id);
135 if hir_body.params.is_empty() {
136 return (vec!["0".to_string()], Vec::new());
137 }
138
139 let params = hir_body.params;
140 let typeck_results = tcx.typeck_body(hir_body.id());
141 let mut param_names = Vec::new();
142 let mut param_tys = Vec::new();
143 for param in params {
144 let ident = extract_pat_ident(¶m.pat);
145 match ident {
146 Some(name) => {
147 param_names.push(name.name.to_string());
148 }
149 None => {
150 param_names.push(String::new());
151 }
152 }
153 param_tys.push(typeck_results.pat_ty(param.pat));
154 }
155 (param_names, param_tys)
156}
157
158pub fn parse_outside_signature<'tcx>(
163 tcx: TyCtxt<'tcx>,
164 def_id: DefId,
165) -> (Vec<String>, Vec<Ty<'tcx>>) {
166 let sig = tcx.fn_sig(def_id).skip_binder();
167 let param_tys: Vec<Ty<'tcx>> = sig.inputs().skip_binder().iter().copied().collect();
168
169 if let Some(args_name) = get_known_std_names(tcx, def_id) {
170 return (args_name, param_tys);
171 }
172
173 let args_name = (0..param_tys.len()).map(|i| format!("{}", i)).collect();
174 (args_name, param_tys)
175}
176
177pub fn parse_signature<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> (Vec<String>, Vec<Ty<'tcx>>) {
180 if def_id.as_local().is_some() && tcx.is_mir_available(def_id) {
181 parse_local_signature(tcx, def_id)
182 } else if def_id.is_local() {
183 (vec!["0".to_string()], Vec::new())
184 } else {
185 parse_outside_signature(tcx, def_id)
186 }
187}
188
189pub fn access_ident_recursive(expr: &Expr) -> Option<(String, Vec<String>)> {
197 match expr {
198 Expr::Path(syn::ExprPath { path, .. }) => {
199 if path.segments.len() == 1 {
200 rap_debug!("expr2 {:?}", expr);
201 let ident = path.segments[0].ident.to_string();
202 Some((ident, Vec::new()))
203 } else {
204 None
205 }
206 }
207 Expr::Field(syn::ExprField { base, member, .. }) => {
208 let (base_ident, mut fields) =
209 if let Some((base_ident, fields)) = access_ident_recursive(base) {
210 (base_ident, fields)
211 } else {
212 return None;
213 };
214 let field_name = match member {
215 syn::Member::Named(ident) => ident.to_string(),
216 syn::Member::Unnamed(index) => index.index.to_string(),
217 };
218 fields.push(field_name);
219 Some((base_ident, fields))
220 }
221 _ => None,
222 }
223}
224
225pub fn match_ty_with_ident<'tcx>(
231 tcx: TyCtxt<'tcx>,
232 def_id: DefId,
233 type_ident: String,
234) -> Option<Ty<'tcx>> {
235 if let Some(primitive_ty) = match_primitive_type(tcx, type_ident.clone()) {
236 return Some(primitive_ty);
237 }
238 if let Some(param_ty) = find_declared_generic_param(tcx, def_id, &type_ident) {
239 return Some(param_ty);
240 }
241 find_generic_param(tcx, def_id, type_ident)
242}
243
244fn find_declared_generic_param<'tcx>(
245 tcx: TyCtxt<'tcx>,
246 def_id: DefId,
247 type_ident: &str,
248) -> Option<Ty<'tcx>> {
249 tcx.generics_of(def_id)
250 .own_params
251 .iter()
252 .find(|param| param.name.as_str() == type_ident)
253 .map(|param| {
254 tcx.mk_ty_from_kind(TyKind::Param(rustc_middle::ty::ParamTy {
255 index: param.index,
256 name: param.name,
257 }))
258 })
259}
260
261pub fn match_primitive_type<'tcx>(tcx: TyCtxt<'tcx>, type_ident: String) -> Option<Ty<'tcx>> {
264 match type_ident.as_str() {
265 "i8" => Some(tcx.types.i8),
266 "i16" => Some(tcx.types.i16),
267 "i32" => Some(tcx.types.i32),
268 "i64" => Some(tcx.types.i64),
269 "i128" => Some(tcx.types.i128),
270 "isize" => Some(tcx.types.isize),
271 "u8" => Some(tcx.types.u8),
272 "u16" => Some(tcx.types.u16),
273 "u32" => Some(tcx.types.u32),
274 "u64" => Some(tcx.types.u64),
275 "u128" => Some(tcx.types.u128),
276 "usize" => Some(tcx.types.usize),
277 "f16" => Some(tcx.types.f16),
278 "f32" => Some(tcx.types.f32),
279 "f64" => Some(tcx.types.f64),
280 "f128" => Some(tcx.types.f128),
281 "bool" => Some(tcx.types.bool),
282 "char" => Some(tcx.types.char),
283 "str" => Some(tcx.types.str_),
284 _ => None,
285 }
286}
287
288pub fn find_generic_param<'tcx>(
291 tcx: TyCtxt<'tcx>,
292 def_id: DefId,
293 type_ident: String,
294) -> Option<Ty<'tcx>> {
295 rap_debug!(
296 "Searching for generic param: {} in {:?}",
297 type_ident,
298 def_id
299 );
300 let (_, param_tys) = parse_signature(tcx, def_id);
301 rap_debug!("Function parameter types: {:?} of {:?}", param_tys, def_id);
302 for &ty in ¶m_tys {
303 if let Some(found) = find_generic_in_ty(tcx, ty, &type_ident) {
304 return Some(found);
305 }
306 }
307
308 if let Some(struct_ty) = get_struct_self_ty(tcx, def_id) {
309 if let Some(found) = find_generic_in_ty(tcx, struct_ty, &type_ident) {
310 return Some(found);
311 }
312 }
313
314 None
315}
316
317pub fn find_generic_in_ty<'tcx>(
323 tcx: TyCtxt<'tcx>,
324 ty: Ty<'tcx>,
325 type_ident: &str,
326) -> Option<Ty<'tcx>> {
327 match ty.kind() {
328 TyKind::Param(param_ty) => {
329 if param_ty.name.as_str() == type_ident {
330 return Some(ty);
331 }
332 }
333 TyKind::RawPtr(ty, _)
334 | TyKind::Ref(_, ty, _)
335 | TyKind::Slice(ty)
336 | TyKind::Array(ty, _) => {
337 if let Some(found) = find_generic_in_ty(tcx, *ty, type_ident) {
338 return Some(found);
339 }
340 }
341 TyKind::Tuple(tys) => {
342 for tuple_ty in tys.iter() {
343 if let Some(found) = find_generic_in_ty(tcx, tuple_ty, type_ident) {
344 return Some(found);
345 }
346 }
347 }
348 TyKind::Adt(adt_def, substs) => {
349 let name = tcx.item_name(adt_def.did()).to_string();
350 if name == type_ident {
351 return Some(ty);
352 }
353 for field in adt_def.all_fields() {
354 #[cfg(not(rapx_rustc_ge_198))]
355 let field_ty = field.ty(tcx, substs);
356 #[cfg(rapx_rustc_ge_198)]
357 let field_ty = field.ty(tcx, substs).skip_norm_wip();
358 if let Some(found) = find_generic_in_ty(tcx, field_ty, type_ident) {
359 return Some(found);
360 }
361 }
362 }
363 _ => {}
364 }
365 None
366}