1use std::fmt;
2use std::fmt::Write;
3use std::option::Option;
4
5use cairo_lang_defs::ids::TraitItemId::Function;
6use cairo_lang_defs::ids::{
7 ConstantId, EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, GenericImplItemId,
8 GenericItemId, GenericKind, GenericModuleItemId, GenericParamId, GenericTraitItemId,
9 ImplAliasId, ImplConstantDefId, ImplDefId, ImplFunctionId, ImplItemId, ImplTypeDefId,
10 LanguageElementId, LookupItemId, MemberId, ModuleId, ModuleItemId, ModuleTypeAliasId,
11 NamedLanguageElementId, StructId, TopLevelLanguageElementId, TraitConstantId, TraitFunctionId,
12 TraitId, TraitItemId, TraitTypeId, VariantId,
13};
14use cairo_lang_semantic::expr::inference::InferenceId;
15use cairo_lang_semantic::items::constant::ConstValue;
16use cairo_lang_semantic::items::functions::GenericFunctionId;
17use cairo_lang_semantic::items::generics::GenericArgumentId;
18use cairo_lang_semantic::items::modifiers::get_relevant_modifier;
19use cairo_lang_semantic::items::visibility::Visibility;
20use cairo_lang_semantic::types::TypeId;
21use cairo_lang_semantic::{ConcreteTypeId, Expr, GenericParam, TypeLongId};
22use cairo_lang_syntax::attribute::structured::Attribute;
23use cairo_lang_syntax::node::kind::SyntaxKind;
24use cairo_lang_syntax::node::{SyntaxNode, TypedStablePtr, TypedSyntaxNode, green};
25use cairo_lang_utils::LookupIntern;
26use itertools::Itertools;
27
28use crate::db::DocGroup;
29use crate::documentable_item::DocumentableItemId;
30use crate::location_links::{LocationLink, format_signature};
31use crate::signature_data::{
32 DocumentableItemSignatureData, get_constant_signature_data, get_enum_signature_data,
33 get_extern_function_full_signature, get_extern_type_full_signature,
34 get_free_function_signature_data, get_impl_alias_signature_data,
35 get_impl_constant_signature_data, get_impl_def_signature_data,
36 get_impl_function_signature_data, get_impl_type_def_full_signature, get_member_signature_data,
37 get_module_type_alias_full_signature, get_struct_signature_data,
38 get_trait_const_signature_data, get_trait_function_signature_data, get_trait_signature_data,
39 get_trait_type_full_signature,
40};
41use crate::signature_errors::SignatureError;
42
43const INDENT: &str = " ";
45const MISSING: &str = "<missing>";
47
48pub fn get_item_signature(db: &dyn DocGroup, item_id: DocumentableItemId) -> Option<String> {
50 get_item_signature_with_links(db, item_id).0
51}
52
53pub fn get_item_signature_with_links(
56 db: &dyn DocGroup,
57 item_id: DocumentableItemId,
58) -> (Option<String>, Vec<LocationLink>) {
59 let mut f = HirFormatter::new(db);
60 match item_id {
61 DocumentableItemId::LookupItem(item_id) => match item_id {
62 LookupItemId::ModuleItem(item_id) => match item_id {
63 ModuleItemId::Struct(item_id) => item_id.get_signature_with_links(&mut f),
64 ModuleItemId::Enum(item_id) => item_id.get_signature_with_links(&mut f),
65 ModuleItemId::Constant(item_id) => item_id.get_signature_with_links(&mut f),
66 ModuleItemId::FreeFunction(item_id) => item_id.get_signature_with_links(&mut f),
67 ModuleItemId::TypeAlias(item_id) => item_id.get_signature_with_links(&mut f),
68 ModuleItemId::ImplAlias(item_id) => item_id.get_signature_with_links(&mut f),
69 ModuleItemId::Trait(item_id) => item_id.get_signature_with_links(&mut f),
70 ModuleItemId::Impl(item_id) => item_id.get_signature_with_links(&mut f),
71 ModuleItemId::ExternType(item_id) => item_id.get_signature_with_links(&mut f),
72 ModuleItemId::ExternFunction(item_id) => item_id.get_signature_with_links(&mut f),
73 ModuleItemId::Submodule(_) => (None, vec![]),
74 ModuleItemId::Use(_) => (None, vec![]),
75 ModuleItemId::MacroDeclaration(_) => (None, vec![]),
76 },
77 LookupItemId::TraitItem(item_id) => match item_id {
78 TraitItemId::Function(item_id) => item_id.get_signature_with_links(&mut f),
79 TraitItemId::Constant(item_id) => item_id.get_signature_with_links(&mut f),
80 TraitItemId::Type(item_id) => item_id.get_signature_with_links(&mut f),
81 TraitItemId::Impl(_) => (None, vec![]),
82 },
83 LookupItemId::ImplItem(item_id) => match item_id {
84 ImplItemId::Function(item_id) => item_id.get_signature_with_links(&mut f),
85 ImplItemId::Constant(item_id) => item_id.get_signature_with_links(&mut f),
86 ImplItemId::Type(item_id) => item_id.get_signature_with_links(&mut f),
87 ImplItemId::Impl(_) => (None, vec![]),
88 },
89 },
90 DocumentableItemId::Member(item_id) => item_id.get_signature_with_links(&mut f),
91 DocumentableItemId::Variant(item_id) => item_id.get_signature_with_links(&mut f),
92 DocumentableItemId::Crate(_) => (None, vec![]),
93 }
94}
95
96pub trait HirDisplay {
97 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError>;
99
100 fn get_signature(&self, f: &mut HirFormatter<'_>) -> Option<String> {
102 match self.hir_fmt(f) {
103 Ok(_) => Some(f.buf.clone()),
104 Err(_) => None,
105 }
106 }
107
108 fn get_signature_with_links(
111 &self,
112 f: &mut HirFormatter<'_>,
113 ) -> (Option<String>, Vec<LocationLink>) {
114 let signature = self.get_signature(f);
115 (signature, f.location_links.clone())
116 }
117}
118
119pub struct HirFormatter<'a> {
121 db: &'a dyn DocGroup,
123 buf: String,
125 location_links: Vec<LocationLink>,
127}
128
129impl fmt::Write for HirFormatter<'_> {
130 fn write_str(&mut self, s: &str) -> fmt::Result {
131 self.buf.push_str(s);
132 Ok(())
133 }
134}
135
136impl<'a> HirFormatter<'a> {
138 pub fn new(db: &'a dyn DocGroup) -> Self {
140 Self { db, buf: String::new(), location_links: Vec::new() }
141 }
142
143 fn add_location_link(&mut self, start: usize, end: usize, item_id: DocumentableItemId) {
145 self.location_links.push(LocationLink { start, end, item_id })
146 }
147
148 fn write_type(
151 &mut self,
152 prefix: Option<&str>,
153 element_type: TypeId,
154 postfix: Option<&str>,
155 full_path: &String,
156 ) -> fmt::Result {
157 self.write_str(prefix.unwrap_or_default())?;
158 let formatted_element_type = element_type.format(self.db);
159
160 if let TypeLongId::Tuple(vec_types) = element_type.lookup_intern(self.db) {
161 self.write_str("(")?;
162 let mut count = vec_types.len();
163 for t in vec_types {
164 self.write_type(None, t, if count == 1 { None } else { Some(", ") }, full_path)?;
165 count -= 1;
166 }
167 self.write_str(")")?;
168 } else if is_the_same_root(full_path, &formatted_element_type) {
169 let documentable_id = resolve_type(self.db, element_type);
170 match documentable_id {
171 Some(documentable_id) => {
172 let start_offset = self.buf.len();
173 self.write_str(&extract_and_format(&formatted_element_type))?;
174 let end_offset = self.buf.len();
175 self.add_location_link(start_offset, end_offset, documentable_id);
176 }
177 None => {
178 self.write_str(&extract_and_format(&formatted_element_type))?;
179 }
180 }
181 } else {
182 self.write_str(&extract_and_format(&formatted_element_type))?;
183 }
184 self.write_str(postfix.unwrap_or_default())
185 }
186
187 fn write_link(
190 &mut self,
191 name: String,
192 documentable_id: Option<DocumentableItemId>,
193 ) -> fmt::Result {
194 match documentable_id {
195 Some(documentable_id) => {
196 let start_offset = self.buf.len();
197 self.write_str(&name)?;
198 let end_offset = self.buf.len();
199 self.add_location_link(start_offset, end_offset, documentable_id);
200 Ok(())
201 }
202 None => self.write_str(&extract_and_format(&name)),
203 }
204 }
205
206 fn format(&mut self) {
210 let (formatted_signature, moved_location_links) = format_signature(
211 std::mem::take(&mut self.buf),
212 std::mem::take(&mut self.location_links),
213 );
214 self.buf = formatted_signature;
215 self.location_links = moved_location_links;
216 }
217}
218
219impl HirDisplay for VariantId {
220 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
221 let name = self.name(f.db);
222 let variant_semantic =
223 f.db.variant_semantic(self.enum_id(f.db), *self)
224 .map_err(|_| SignatureError::FailedRetrievingSemanticData(self.full_path(f.db)))?;
225 if !variant_semantic.ty.is_unit(f.db) {
226 f.write_type(
227 Some(&format!("{name}: ")),
228 variant_semantic.ty,
229 None,
230 &self.full_path(f.db),
231 )
232 } else {
233 f.write_str(name.as_str())
234 }
235 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))
236 }
237}
238
239impl HirDisplay for EnumId {
240 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
241 let enum_full_signature = get_enum_signature_data(f.db, *self)?;
242 write!(
243 f,
244 "{}enum {} {{",
245 get_syntactic_visibility(&enum_full_signature.visibility),
246 enum_full_signature.name,
247 )
248 .map_err(|_| {
249 SignatureError::FailedWritingSignature(enum_full_signature.full_path.clone())
250 })?;
251 let variants = enum_full_signature.variants;
252 if let Some(variants) = variants {
253 let is_variants_empty = variants.is_empty();
254 for (name, variant_type) in variants {
255 if !variant_type.is_unit(f.db) {
256 f.write_type(
257 Some(&format!("\n{INDENT}{name}: ",)),
258 variant_type,
259 Some(","),
260 &enum_full_signature.full_path,
261 )
262 } else {
263 write!(f, "\n{INDENT}{name},")
264 }
265 .map_err(|_| {
266 SignatureError::FailedWritingSignature(enum_full_signature.full_path.clone())
267 })?;
268 }
269 f.write_str(if is_variants_empty { "}" } else { "\n}" })
270 } else {
271 f.write_str("}")
272 }
273 .map_err(|_| {
274 SignatureError::FailedWritingSignature(enum_full_signature.full_path.clone())
275 })?;
276 f.format();
277 Ok(())
278 }
279}
280
281impl HirDisplay for MemberId {
282 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
283 let member_full_signature = get_member_signature_data(f.db, *self)?;
284 if let Some(return_type) = member_full_signature.return_type {
285 if return_type.is_unit(f.db) {
286 write!(
287 f,
288 "{}{}",
289 get_syntactic_visibility(&member_full_signature.visibility),
290 member_full_signature.name
291 )
292 } else {
293 f.write_type(
294 Some(&format!(
295 "{}{}: ",
296 get_syntactic_visibility(&member_full_signature.visibility),
297 member_full_signature.name,
298 )),
299 return_type,
300 None,
301 &member_full_signature.full_path,
302 )
303 }
304 .map_err(|_| SignatureError::FailedWritingType(member_full_signature.full_path.clone()))
305 } else {
306 Err(SignatureError::FailedRetrievingSemanticData(self.full_path(f.db)))
307 }
308 }
309}
310
311impl HirDisplay for StructId {
312 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
313 let struct_full_signature = get_struct_signature_data(f.db, *self)?;
314 if let Some(attributes) = struct_full_signature.attributes {
315 write_struct_attributes_syntax(attributes, f).map_err(|_| {
316 SignatureError::FailedWritingSignature(struct_full_signature.full_path.clone())
317 })?;
318 }
319 write!(
320 f,
321 "{}struct {}",
322 get_syntactic_visibility(&struct_full_signature.visibility),
323 struct_full_signature.name,
324 )
325 .map_err(|_| {
326 SignatureError::FailedWritingSignature(struct_full_signature.full_path.clone())
327 })?;
328 if let Some(generic_params) = struct_full_signature.generic_params {
329 write_generic_params(generic_params, f).map_err(|_| {
330 SignatureError::FailedWritingSignature(struct_full_signature.full_path.clone())
331 })?;
332 }
333 f.write_str(" {").map_err(|_| {
334 SignatureError::FailedWritingSignature(struct_full_signature.full_path.clone())
335 })?;
336
337 if let Some(members) = struct_full_signature.members {
338 let is_members_empty = members.is_empty();
339 for member in members {
340 let (name, member_type, visibility) = member;
341 f.write_type(
342 Some(
343 &format!("\n{INDENT}{}{}: ", get_syntactic_visibility(&visibility), name,),
344 ),
345 member_type,
346 Some(","),
347 &struct_full_signature.full_path,
348 )
349 .map_err(|_| {
350 SignatureError::FailedWritingSignature(struct_full_signature.full_path.clone())
351 })?;
352 }
353 f.write_str(if is_members_empty { "}" } else { "\n}" }).map_err(|_| {
354 SignatureError::FailedWritingSignature(struct_full_signature.full_path.clone())
355 })?;
356 };
357 f.format();
358 Ok(())
359 }
360}
361
362impl HirDisplay for FreeFunctionId {
363 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
364 let free_function_full_signature = get_free_function_signature_data(f.db, *self)?;
365 write_function_signature(f, free_function_full_signature, "".to_string())
366 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
367 f.format();
368 Ok(())
369 }
370}
371
372impl HirDisplay for ConstantId {
373 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
374 let constant_full_signature = get_constant_signature_data(f.db, *self)?;
375 write!(
376 f,
377 "{}const {}: ",
378 get_syntactic_visibility(&constant_full_signature.visibility),
379 constant_full_signature.name,
380 )
381 .map_err(|_| {
382 SignatureError::FailedWritingSignature(constant_full_signature.full_path.clone())
383 })?;
384 if let Some(return_type) = constant_full_signature.return_type {
385 f.write_type(None, return_type, Some(" = "), &constant_full_signature.full_path)
386 .map_err(|_| {
387 SignatureError::FailedWritingSignature(
388 constant_full_signature.full_path.clone(),
389 )
390 })?;
391 }
392 if let Some(return_value_expr) = constant_full_signature.return_value_expr {
393 match return_value_expr {
394 Expr::Literal(v) => write!(f, "{};", v.value,).map_err(|_| {
395 SignatureError::FailedWritingSignature(
396 constant_full_signature.full_path.clone(),
397 )
398 }),
399 Expr::FunctionCall(_) => {
400 let const_value_id = f.db.constant_const_value(*self).map_err(|_| {
401 SignatureError::FailedRetrievingSemanticData(
402 constant_full_signature.full_path.clone(),
403 )
404 })?;
405 let constant_value = f.db.lookup_intern_const_value(const_value_id);
406 if let ConstValue::Int(value, _) = constant_value {
407 write_syntactic_evaluation(f, constant_full_signature.item_id).map_err(
408 |_| {
409 SignatureError::FailedWritingSignature(
410 constant_full_signature.full_path.clone(),
411 )
412 },
413 )?;
414 write!(f, " // = {value}")
415 } else {
416 write_syntactic_evaluation(f, constant_full_signature.item_id)
417 }
418 .map_err(|_| {
419 SignatureError::FailedWritingSignature(
420 constant_full_signature.full_path.clone(),
421 )
422 })
423 }
424 _ => write_syntactic_evaluation(f, constant_full_signature.item_id).map_err(|_| {
425 SignatureError::FailedWritingSignature(
426 constant_full_signature.full_path.clone(),
427 )
428 }),
429 }
430 } else {
431 Err(SignatureError::FailedRetrievingSemanticData(self.full_path(f.db)))
432 }
433 }
434}
435
436impl HirDisplay for ImplConstantDefId {
437 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
438 let constant_full_signature = get_impl_constant_signature_data(f.db, *self)?;
439 if let Some(return_type) = constant_full_signature.return_type {
440 f.write_type(
441 Some(&format!("const {}: ", constant_full_signature.name,)),
442 return_type,
443 Some(" = "),
444 &constant_full_signature.full_path,
445 )
446 .map_err(|_| {
447 SignatureError::FailedWritingSignature(constant_full_signature.full_path.clone())
448 })?;
449 }
450 write_syntactic_evaluation(f, constant_full_signature.item_id).map_err(|_| {
451 SignatureError::FailedWritingSignature(constant_full_signature.full_path)
452 })?;
453 f.format();
454 Ok(())
455 }
456}
457
458impl HirDisplay for TraitFunctionId {
459 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
460 let free_function_full_signature = get_trait_function_signature_data(f.db, *self)?;
461 write_function_signature(f, free_function_full_signature, "".to_string())
462 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
463 f.format();
464 Ok(())
465 }
466}
467
468impl HirDisplay for ImplFunctionId {
469 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
470 let impl_function_full_signature = get_impl_function_signature_data(f.db, *self)?;
471 write_function_signature(f, impl_function_full_signature, "".to_string())
472 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
473 f.format();
474 Ok(())
475 }
476}
477
478impl HirDisplay for TraitId {
479 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
480 let trait_full_signature = get_trait_signature_data(f.db, *self)?;
481 write!(
482 f,
483 "{}trait {}",
484 get_syntactic_visibility(&trait_full_signature.visibility),
485 trait_full_signature.name,
486 )
487 .map_err(|_| {
488 SignatureError::FailedWritingSignature(trait_full_signature.full_path.clone())
489 })?;
490 if let Some(generic_params) = trait_full_signature.generic_params {
491 write_generic_params(generic_params, f).map_err(|_| {
492 SignatureError::FailedWritingSignature(trait_full_signature.full_path)
493 })?
494 };
495 f.format();
496 Ok(())
497 }
498}
499
500impl HirDisplay for TraitConstantId {
501 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
502 let trait_const_full_signature = get_trait_const_signature_data(f.db, *self)?;
503 if let Some(return_type) = trait_const_full_signature.return_type {
504 write!(
505 f,
506 "const {}: {};",
507 trait_const_full_signature.name,
508 extract_and_format(&return_type.format(f.db)),
509 )
510 .map_err(|_| {
511 SignatureError::FailedWritingSignature(trait_const_full_signature.full_path)
512 })?;
513 } else {
514 Err(SignatureError::FailedRetrievingSemanticData(self.full_path(f.db)))?;
515 }
516 f.format();
517 Ok(())
518 }
519}
520
521impl HirDisplay for ImplDefId {
522 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
523 let impl_def_full_signature = get_impl_def_signature_data(f.db, *self)?;
524 let trait_id = f.db.impl_def_trait(*self).map_err(|_| {
525 SignatureError::FailedRetrievingSemanticData(impl_def_full_signature.full_path.clone())
526 })?;
527 if let Some(resolver_generic_params) = impl_def_full_signature.resolver_generic_params {
528 let resolver_generic_params =
529 format_resolver_generic_params(f.db, resolver_generic_params);
530 write!(
531 f,
532 "{}impl {}{} of {}",
533 get_syntactic_visibility(&impl_def_full_signature.visibility),
534 impl_def_full_signature.name,
535 resolver_generic_params,
536 trait_id.name(f.db),
537 )
538 .map_err(|_| {
539 SignatureError::FailedWritingSignature(impl_def_full_signature.full_path.clone())
540 })?;
541 }
542 if let Some(generic_args) = impl_def_full_signature.generic_args {
543 write_generic_args(generic_args, f).map_err(|_| {
544 SignatureError::FailedWritingSignature(impl_def_full_signature.full_path.clone())
545 })?;
546 }
547 f.write_str(";").map_err(|_| {
548 SignatureError::FailedWritingSignature(impl_def_full_signature.full_path)
549 })?;
550 f.format();
551 Ok(())
552 }
553}
554
555impl HirDisplay for ImplAliasId {
556 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
557 let impl_alias_full_signature = get_impl_alias_signature_data(f.db, *self)?;
558 write!(
559 f,
560 "{}impl {} = ",
561 get_syntactic_visibility(&impl_alias_full_signature.visibility),
562 self.name(f.db),
563 )
564 .map_err(|_| {
565 SignatureError::FailedWritingSignature(impl_alias_full_signature.full_path.clone())
566 })?;
567 write_syntactic_evaluation(f, impl_alias_full_signature.item_id).map_err(|_| {
568 SignatureError::FailedWritingSignature(impl_alias_full_signature.full_path)
569 })?;
570 f.format();
571 Ok(())
572 }
573}
574
575impl HirDisplay for ModuleTypeAliasId {
576 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
577 let module_type_alias_full_signature = get_module_type_alias_full_signature(f.db, *self)?;
578 write_type_signature(f, module_type_alias_full_signature, false)
579 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
580 f.format();
581 Ok(())
582 }
583}
584
585impl HirDisplay for TraitTypeId {
586 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
587 let trait_type_full_signature = get_trait_type_full_signature(f.db, *self)?;
588 write_type_signature(f, trait_type_full_signature, false)
589 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
590 f.format();
591 Ok(())
592 }
593}
594
595impl HirDisplay for ImplTypeDefId {
596 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
597 let impl_type_def_full_signature = get_impl_type_def_full_signature(f.db, *self)?;
598 write_type_signature(f, impl_type_def_full_signature, false)
599 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
600 f.format();
601 Ok(())
602 }
603}
604
605impl HirDisplay for ExternTypeId {
606 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
607 let extern_type_full_signature = get_extern_type_full_signature(f.db, *self)?;
608 write_type_signature(f, extern_type_full_signature, true)
609 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
610 f.format();
611 Ok(())
612 }
613}
614
615impl HirDisplay for ExternFunctionId {
616 fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), SignatureError> {
617 let extern_function_full_signature = get_extern_function_full_signature(f.db, *self)?;
618 let signature = match f.db.extern_function_signature(*self) {
619 Ok(signature) => signature,
620 _ => {
621 return Err(SignatureError::FailedRetrievingSemanticData(
622 extern_function_full_signature.full_path,
623 ));
624 }
625 };
626 write_function_signature(f, extern_function_full_signature, "extern ".to_string())
627 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
628 if !signature.implicits.is_empty() {
629 f.write_str(" implicits(")
630 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
631 let mut count = signature.implicits.len();
632 for type_id in &signature.implicits {
633 write!(
634 f,
635 "{}{}",
636 extract_and_format(&type_id.format(f.db)),
637 if count == 1 { ")".to_string() } else { ", ".to_string() }
638 )
639 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
640 count -= 1;
641 }
642 }
643 if !signature.panicable {
644 f.write_str(" nopanic")
645 .map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))?;
646 };
647 f.write_str(";").map_err(|_| SignatureError::FailedWritingSignature(self.full_path(f.db)))
648 }
649}
650
651pub fn get_syntactic_visibility(semantic_visibility: &Visibility) -> &str {
653 match semantic_visibility {
654 Visibility::Public => "pub ",
655 Visibility::PublicInCrate => "pub(crate) ",
656 Visibility::Private => "",
657 }
658}
659
660fn is_the_same_root(path1: &str, path2: &str) -> bool {
662 fn extract_root(input: &str) -> &str {
663 if let Some(index) = input.find("::") { &input[..index] } else { input }
664 }
665 extract_root(path1) == extract_root(path2)
666}
667
668fn extract_and_format(input: &str) -> String {
671 let delimiters = [',', '<', '>', '(', ')', '[', ']'];
672 let mut output = String::new();
673 let mut slice_start = 0;
674 let mut in_slice = false;
675
676 for (i, c) in input.char_indices() {
677 if delimiters.contains(&c) {
678 if in_slice {
679 let slice = &input[slice_start..i];
680 output.push_str(&format_final_part(slice));
681 in_slice = false;
682 }
683 output.push(c);
684 slice_start = i + 1;
685 } else {
686 in_slice = true;
687 }
688 }
689 if in_slice {
690 let slice = &input[slice_start..];
691 output.push_str(&format_final_part(slice));
692 }
693 output
694}
695
696fn format_final_part(slice: &str) -> String {
698 let parts: Vec<&str> = slice.split("::").collect();
699 let ensure_whitespace =
700 if let Some(first) = parts.first() { first.starts_with(" ") } else { false };
701 let result = {
702 match parts[..] {
703 [.., before_last, ""] => before_last.to_string(),
704 [.., last] => last.to_string(),
705 _ => slice.to_string(),
706 }
707 };
708 if ensure_whitespace && !result.starts_with(' ') { format!(" {result}") } else { result }
709}
710
711fn format_resolver_generic_params(db: &dyn DocGroup, params: Vec<GenericParamId>) -> String {
714 if !params.is_empty() {
715 format!(
716 "<{}>",
717 params
718 .iter()
719 .map(|param| {
720 if matches!(param.kind(db), GenericKind::Impl) {
721 let param_formatted = param.format(db);
722 if param_formatted.starts_with("+") {
723 param_formatted
724 } else {
725 match db.generic_param_semantic(*param) {
726 Ok(generic_param) => match generic_param {
727 GenericParam::Impl(generic_param_impl) => {
728 match generic_param_impl.concrete_trait {
729 Ok(concrete_trait) => {
730 format!(
731 "impl {param_formatted}: {}<{}>",
732 concrete_trait.name(db),
733 concrete_trait
734 .generic_args(db)
735 .iter()
736 .map(|arg| arg.format(db))
737 .collect::<Vec<_>>()
738 .join(", "),
739 )
740 }
741 Err(_) => param_formatted,
742 }
743 }
744 _ => param_formatted,
745 },
746 Err(_) => param_formatted,
747 }
748 }
749 } else {
750 param.format(db)
751 }
752 })
753 .join(", ")
754 )
755 } else {
756 "".to_string()
757 }
758}
759
760fn write_function_signature(
765 f: &mut HirFormatter<'_>,
766 documentable_signature: DocumentableItemSignatureData,
767 syntactic_kind: String,
768) -> Result<(), fmt::Error> {
769 let resolver_generic_params = match documentable_signature.resolver_generic_params {
770 Some(params) => format_resolver_generic_params(f.db, params),
771 None => "".to_string(),
772 };
773
774 write!(
775 f,
776 "{}{}fn {}{}",
777 get_syntactic_visibility(&documentable_signature.visibility),
778 syntactic_kind,
779 documentable_signature.name,
780 resolver_generic_params,
781 )?;
782 if let Some(generic_args) = documentable_signature.generic_args {
783 write_generic_args(generic_args, f)?;
784 }
785 f.write_str("(")?;
786 if let Some(params) = documentable_signature.params {
787 let mut count = params.len();
788 let mut postfix = String::from(", ");
789 for param in params {
790 if count == 1 {
791 postfix = "".to_string();
792 }
793 let syntax_node = param.id.stable_location(f.db).syntax_node(f.db);
794 let modifier = get_relevant_modifier(¶m.mutability);
795 let modifier_postfix = if modifier.is_empty() { "" } else { " " };
796 if param.ty.is_fully_concrete(f.db) {
797 f.write_type(
798 Some(&format!("{modifier}{modifier_postfix}{}: ", param.name)),
799 param.ty,
800 Some(&postfix),
801 &documentable_signature.full_path,
802 )?;
803 } else {
804 let type_definition = get_type_clause(syntax_node, f.db).unwrap_or_default();
805 write!(f, "{modifier}{modifier_postfix}{}{type_definition}{postfix}", param.name,)?;
806 }
807 count -= 1;
808 }
809 }
810 f.write_str(")")?;
811
812 if let Some(return_type) = documentable_signature.return_type {
813 if !return_type.is_unit(f.db) {
814 f.write_type(Some(" -> "), return_type, None, &documentable_signature.full_path)?;
815 }
816 }
817 Ok(())
818}
819
820fn get_type_clause(syntax_node: SyntaxNode, db: &dyn DocGroup) -> Option<String> {
822 for child in syntax_node.get_children(db).iter() {
823 if child.kind(db) == SyntaxKind::TypeClause {
824 return Some(child.get_text_without_all_comment_trivia(db));
825 }
826 }
827 Some(String::from(MISSING))
828}
829
830fn write_generic_params(
832 generic_params: Vec<GenericParam>,
833 f: &mut HirFormatter<'_>,
834) -> Result<(), fmt::Error> {
835 if !generic_params.is_empty() {
836 let mut count = generic_params.len();
837 f.write_str("<")?;
838 for param in generic_params {
839 match param {
840 GenericParam::Type(param_type) => {
841 let name = extract_and_format(¶m_type.id.format(f.db));
842 write!(f, "{}{}", name, if count == 1 { "" } else { ", " })?;
843 }
844 GenericParam::Const(param_const) => {
845 let name = extract_and_format(¶m_const.id.format(f.db));
846 write!(f, "const {}{}", name, if count == 1 { "" } else { ", " })?;
847 }
848 GenericParam::Impl(param_impl) => {
849 let name = extract_and_format(¶m_impl.id.format(f.db));
850 match param_impl.concrete_trait {
851 Ok(concrete_trait) => {
852 let documentable_id =
853 DocumentableItemId::from(LookupItemId::ModuleItem(
854 ModuleItemId::Trait(concrete_trait.trait_id(f.db)),
855 ));
856 if name.starts_with("+") {
857 f.write_link(name, Some(documentable_id))?;
858 } else {
859 write!(f, "impl {name}: ")?;
860 let concrete_trait_name = concrete_trait.name(f.db);
861 let concrete_trait_generic_args_formatted = concrete_trait
862 .generic_args(f.db)
863 .iter()
864 .map(|arg| extract_and_format(&arg.format(f.db)))
865 .collect::<Vec<_>>()
866 .join(", ");
867 f.write_link(
868 concrete_trait_name.to_string(),
869 Some(documentable_id),
870 )?;
871 if !concrete_trait_generic_args_formatted.is_empty() {
872 write!(f, "<{concrete_trait_generic_args_formatted}>")?;
873 }
874 }
875 }
876 Err(_) => {
877 write!(f, "{}{}", name, if count == 1 { "" } else { ", " })?;
878 }
879 }
880 }
881 GenericParam::NegImpl(_) => f.write_str(MISSING)?,
882 };
883 count -= 1;
884 }
885 f.write_str(">")
886 } else {
887 Ok(())
888 }
889}
890
891fn write_generic_args(
893 generic_args: Vec<GenericArgumentId>,
894 f: &mut HirFormatter<'_>,
895) -> Result<(), fmt::Error> {
896 let mut count = generic_args.len();
897 if !generic_args.is_empty() {
898 f.write_str("<")?;
899 }
900 for arg in &generic_args {
901 let documentable_id = resolve_generic_arg(*arg, f.db);
902 let _ = f.write_link(extract_and_format(&arg.format(f.db)), documentable_id);
903 let _ = f.write_str(if count == 1 { ">" } else { ", " });
904 count -= 1;
905 }
906 Ok(())
907}
908
909fn write_struct_attributes_syntax(
911 attributes: Vec<Attribute>,
912 f: &mut HirFormatter<'_>,
913) -> Result<(), fmt::Error> {
914 for attribute in attributes {
915 let syntax_node = attribute.stable_ptr.lookup(f.db).as_syntax_node();
916 for child in syntax_node.get_children(f.db).iter() {
917 let to_text = child.get_text_without_all_comment_trivia(f.db);
918 let cleaned_text = to_text.replace("\n", "");
919 f.write_str(&cleaned_text)?;
920 }
921 f.write_str("\n")?;
922 }
923 Ok(())
924}
925
926fn write_syntactic_evaluation(
928 f: &mut HirFormatter<'_>,
929 item_id: DocumentableItemId,
930) -> Result<(), fmt::Error> {
931 if let Some(stable_location) = item_id.stable_location(f.db) {
932 let syntax_node = stable_location.syntax_node(f.db);
933 if matches!(&syntax_node.green_node(f.db).details, green::GreenNodeDetails::Node { .. }) {
934 let mut is_after_evaluation_value = false;
935 for child in syntax_node.get_children(f.db).iter() {
936 let kind = child.kind(f.db);
937 if !matches!(kind, SyntaxKind::Trivia) {
938 if matches!(kind, SyntaxKind::TerminalSemicolon) {
939 f.buf.write_str(";")?;
940 return Ok(());
941 }
942 if is_after_evaluation_value {
943 f.buf.write_str(&SyntaxNode::get_text_without_all_comment_trivia(
944 child, f.db,
945 ))?;
946 };
947 if matches!(kind, SyntaxKind::TerminalEq) {
948 is_after_evaluation_value = true;
949 }
950 }
951 }
952 };
953 Ok(())
954 } else {
955 Err(fmt::Error)
956 }
957}
958
959fn write_type_signature(
963 f: &mut HirFormatter<'_>,
964 documentable_signature: DocumentableItemSignatureData,
965 is_extern_type: bool,
966) -> Result<(), fmt::Error> {
967 write!(
968 f,
969 "{}{}type {}",
970 get_syntactic_visibility(&documentable_signature.visibility),
971 if is_extern_type { "extern " } else { "" },
972 documentable_signature.name
973 )?;
974 if let Some(generic_params) = documentable_signature.generic_params {
975 write_generic_params(generic_params, f)?;
976 }
977 if let Some(return_type) = documentable_signature.return_type {
978 write!(f, " = ")?;
979 f.write_type(None, return_type, None, &documentable_signature.full_path)?;
980 };
981 write!(f, ";")?;
982 Ok(())
983}
984
985fn resolve_generic_item(
987 generic_item_id: GenericItemId,
988 db: &dyn DocGroup,
989) -> Option<DocumentableItemId> {
990 match generic_item_id {
991 GenericItemId::ModuleItem(module_item_id) => {
992 Some(resolve_generic_module_item(module_item_id))
993 }
994 GenericItemId::TraitItem(generic_trait_item_id) => match generic_trait_item_id {
995 GenericTraitItemId::Type(trait_type_id) => Some(DocumentableItemId::from(
996 LookupItemId::ModuleItem(ModuleItemId::Trait(trait_type_id.trait_id(db))),
997 )),
998 },
999 GenericItemId::ImplItem(generic_impl_item_id) => match generic_impl_item_id {
1000 GenericImplItemId::Type(impl_type_def_id) => Some(DocumentableItemId::from(
1001 LookupItemId::ModuleItem(ModuleItemId::Impl(impl_type_def_id.impl_def_id(db))),
1002 )),
1003 },
1004 }
1005}
1006
1007fn resolve_generic_module_item(generic_module_item_id: GenericModuleItemId) -> DocumentableItemId {
1009 match generic_module_item_id {
1010 GenericModuleItemId::FreeFunc(id) => {
1011 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::FreeFunction(id)))
1012 }
1013 GenericModuleItemId::ExternFunc(id) => {
1014 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::ExternFunction(id)))
1015 }
1016 GenericModuleItemId::TraitFunc(id) => {
1017 DocumentableItemId::from(LookupItemId::TraitItem(TraitItemId::Function(id)))
1018 }
1019 GenericModuleItemId::ImplFunc(id) => {
1020 DocumentableItemId::from(LookupItemId::ImplItem(ImplItemId::Function(id)))
1021 }
1022 GenericModuleItemId::Trait(id) => {
1023 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::Trait(id)))
1024 }
1025 GenericModuleItemId::Impl(id) => {
1026 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::Impl(id)))
1027 }
1028 GenericModuleItemId::Struct(id) => {
1029 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::Struct(id)))
1030 }
1031 GenericModuleItemId::Enum(id) => {
1032 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::Enum(id)))
1033 }
1034 GenericModuleItemId::ExternType(id) => {
1035 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::ExternType(id)))
1036 }
1037 GenericModuleItemId::TypeAlias(id) => {
1038 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::TypeAlias(id)))
1039 }
1040 GenericModuleItemId::ImplAlias(id) => {
1041 DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::ImplAlias(id)))
1042 }
1043 }
1044}
1045
1046fn resolve_generic_arg(
1048 generic_arg_id: GenericArgumentId,
1049 db: &dyn DocGroup,
1050) -> Option<DocumentableItemId> {
1051 match generic_arg_id {
1052 GenericArgumentId::Type(type_id) => resolve_type(db, type_id),
1053 GenericArgumentId::Constant(constant_value_id) => match constant_value_id.ty(db) {
1054 Ok(type_id) => resolve_type(db, type_id),
1055 Err(_) => None,
1056 },
1057 GenericArgumentId::Impl(impl_id) => match impl_id.concrete_trait(db) {
1058 Ok(concrete_trait) => {
1059 let trait_id = concrete_trait.trait_id(db);
1060 Some(DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::Trait(
1061 trait_id,
1062 ))))
1063 }
1064 Err(_) => None,
1065 },
1066 GenericArgumentId::NegImpl => None,
1067 }
1068}
1069
1070fn resolve_type(db: &dyn DocGroup, type_id: TypeId) -> Option<DocumentableItemId> {
1072 let intern = type_id.lookup_intern(db);
1073 match intern {
1074 TypeLongId::Concrete(concrete_type_id) => match concrete_type_id {
1075 ConcreteTypeId::Struct(struct_id) => Some(DocumentableItemId::from(
1076 LookupItemId::ModuleItem(ModuleItemId::Struct(struct_id.struct_id(db))),
1077 )),
1078 ConcreteTypeId::Enum(enum_id) => Some(DocumentableItemId::from(
1079 LookupItemId::ModuleItem(ModuleItemId::Enum(enum_id.enum_id(db))),
1080 )),
1081 ConcreteTypeId::Extern(extern_id) => Some(DocumentableItemId::from(
1082 LookupItemId::ModuleItem(ModuleItemId::ExternType(extern_id.extern_type_id(db))),
1083 )),
1084 },
1085 TypeLongId::Tuple(_) => None,
1086 TypeLongId::Snapshot(type_id) => resolve_type(db, type_id),
1087 TypeLongId::GenericParameter(generic_param_id) => {
1088 let item = generic_param_id.generic_item(db);
1089 resolve_generic_item(item, db)
1090 }
1091 TypeLongId::Var(type_var) => match type_var.inference_id {
1092 InferenceId::LookupItemDeclaration(lookup_item_id)
1093 | InferenceId::LookupItemGenerics(lookup_item_id)
1094 | InferenceId::LookupItemDefinition(lookup_item_id) => {
1095 Some(DocumentableItemId::from(lookup_item_id))
1096 }
1097 InferenceId::ImplDefTrait(impl_def_id) => Some(DocumentableItemId::from(
1098 LookupItemId::ModuleItem(ModuleItemId::Impl(impl_def_id)),
1099 )),
1100 InferenceId::ImplAliasImplDef(impl_alias_id) => Some(DocumentableItemId::from(
1101 LookupItemId::ModuleItem(ModuleItemId::ImplAlias(impl_alias_id)),
1102 )),
1103 InferenceId::GenericParam(generic_param_id) => {
1104 let item = generic_param_id.generic_item(db);
1105 resolve_generic_item(item, db)
1106 }
1107 InferenceId::GenericImplParamTrait(generic_param_id) => {
1108 let item = generic_param_id.generic_item(db);
1109 resolve_generic_item(item, db)
1110 }
1111 InferenceId::GlobalUseStar(global_use_id) => {
1112 match db.priv_global_use_imported_module(global_use_id) {
1113 Ok(module_id) => match module_id {
1114 ModuleId::CrateRoot(crate_id) => Some(DocumentableItemId::from(crate_id)),
1115 ModuleId::Submodule(submodule_id) => Some(DocumentableItemId::from(
1116 LookupItemId::ModuleItem(ModuleItemId::Submodule(submodule_id)),
1117 )),
1118 },
1119 Err(_) => None,
1120 }
1121 }
1122 InferenceId::Canonical => None,
1123 InferenceId::NoContext => None,
1124 },
1125 TypeLongId::Coupon(function_id) => {
1126 let concrete_function = function_id.get_concrete(db);
1127 match concrete_function.generic_function {
1128 GenericFunctionId::Free(function_id) => Some(DocumentableItemId::from(
1129 LookupItemId::ModuleItem(ModuleItemId::FreeFunction(function_id)),
1130 )),
1131 GenericFunctionId::Extern(function_id) => Some(DocumentableItemId::from(
1132 LookupItemId::ModuleItem(ModuleItemId::ExternFunction(function_id)),
1133 )),
1134 GenericFunctionId::Impl(function_id) => Some(DocumentableItemId::from(
1135 LookupItemId::TraitItem(Function(function_id.function)),
1136 )),
1137 }
1138 }
1139 TypeLongId::FixedSizeArray { type_id: _, size: _ } => resolve_type(db, type_id),
1140 TypeLongId::ImplType(impl_type_id) => match impl_type_id.impl_id().concrete_trait(db) {
1141 Ok(concrete_trait_id) => Some(DocumentableItemId::from(LookupItemId::ModuleItem(
1142 ModuleItemId::Trait(concrete_trait_id.trait_id(db)),
1143 ))),
1144 Err(_) => None,
1145 },
1146 TypeLongId::Closure(closure_type_id) => resolve_type(db, closure_type_id.ret_ty),
1147 TypeLongId::Missing(_) => None,
1148 }
1149}