1use std::fmt;
2use std::fmt::Write;
3use std::option::Option;
4
5use cairo_lang_defs::ids::{
6 ConstantId, EnumId, ExternFunctionId, ExternTypeId, FreeFunctionId, ImplAliasId,
7 ImplConstantDefId, ImplDefId, ImplFunctionId, ImplItemId, ImplTypeDefId, LanguageElementId,
8 LookupItemId, MacroDeclarationId, MemberId, ModuleItemId, ModuleTypeAliasId,
9 NamedLanguageElementId, StructId, TopLevelLanguageElementId, TraitConstantId, TraitFunctionId,
10 TraitId, TraitItemId, TraitTypeId, VariantId,
11};
12use cairo_lang_filesystem::ids::Tracked;
13use cairo_lang_semantic::items::constant::{ConstValue, ConstantSemantic};
14use cairo_lang_semantic::items::enm::EnumSemantic;
15use cairo_lang_semantic::items::extern_function::ExternFunctionSemantic;
16use cairo_lang_semantic::items::generics::GenericArgumentId;
17use cairo_lang_semantic::items::imp::ImplSemantic;
18use cairo_lang_semantic::items::macro_declaration::MacroDeclarationSemantic;
19use cairo_lang_semantic::items::modifiers::get_relevant_modifier;
20use cairo_lang_semantic::types::TypeId;
21use cairo_lang_semantic::{Expr, TypeLongId};
22use cairo_lang_syntax::node::ast::WrappedMacro;
23use cairo_lang_syntax::node::kind::SyntaxKind;
24use cairo_lang_syntax::node::{SyntaxNode, TypedSyntaxNode};
25use itertools::Itertools;
26use salsa::Database;
27
28use crate::documentable_item::DocumentableItemId;
29use crate::helpers::{
30 extract_and_format, format_resolver_generic_params, get_generic_params,
31 get_struct_attributes_syntax, get_syntactic_evaluation, get_syntactic_visibility, resolve_type,
32};
33use crate::location_links::{LocationLink, format_signature};
34use crate::signature_data::{DocumentableItemSignatureData, SignatureDataRetriever};
35use crate::signature_errors::SignatureError;
36
37const INDENT: &str = " ";
39pub(crate) const MISSING: &str = "<missing>";
41
42#[salsa::tracked]
45pub fn get_item_signature_with_links<'db>(
46 db: &'db dyn Database,
47 _tracked: Tracked,
48 item_id: DocumentableItemId<'db>,
49) -> (Option<String>, Vec<LocationLink<'db>>) {
50 let mut f = HirFormatter::new(db);
51 match item_id {
52 DocumentableItemId::LookupItem(item_id) => match item_id {
53 LookupItemId::ModuleItem(item_id) => match item_id {
54 ModuleItemId::Struct(item_id) => item_id.get_signature_with_links(&mut f),
55 ModuleItemId::Enum(item_id) => item_id.get_signature_with_links(&mut f),
56 ModuleItemId::Constant(item_id) => item_id.get_signature_with_links(&mut f),
57 ModuleItemId::FreeFunction(item_id) => item_id.get_signature_with_links(&mut f),
58 ModuleItemId::TypeAlias(item_id) => item_id.get_signature_with_links(&mut f),
59 ModuleItemId::ImplAlias(item_id) => item_id.get_signature_with_links(&mut f),
60 ModuleItemId::Trait(item_id) => item_id.get_signature_with_links(&mut f),
61 ModuleItemId::Impl(item_id) => item_id.get_signature_with_links(&mut f),
62 ModuleItemId::ExternType(item_id) => item_id.get_signature_with_links(&mut f),
63 ModuleItemId::ExternFunction(item_id) => item_id.get_signature_with_links(&mut f),
64 ModuleItemId::Submodule(_) => (None, vec![]),
65 ModuleItemId::Use(_) => (None, vec![]),
66 ModuleItemId::MacroDeclaration(item_id) => item_id.get_signature_with_links(&mut f),
67 },
68 LookupItemId::TraitItem(item_id) => match item_id {
69 TraitItemId::Function(item_id) => item_id.get_signature_with_links(&mut f),
70 TraitItemId::Constant(item_id) => item_id.get_signature_with_links(&mut f),
71 TraitItemId::Type(item_id) => item_id.get_signature_with_links(&mut f),
72 TraitItemId::Impl(_) => (None, vec![]),
73 },
74 LookupItemId::ImplItem(item_id) => match item_id {
75 ImplItemId::Function(item_id) => item_id.get_signature_with_links(&mut f),
76 ImplItemId::Constant(item_id) => item_id.get_signature_with_links(&mut f),
77 ImplItemId::Type(item_id) => item_id.get_signature_with_links(&mut f),
78 ImplItemId::Impl(_) => (None, vec![]),
79 },
80 },
81 DocumentableItemId::Member(item_id) => item_id.get_signature_with_links(&mut f),
82 DocumentableItemId::Variant(item_id) => item_id.get_signature_with_links(&mut f),
83 DocumentableItemId::Crate(_) => (None, vec![]),
84 }
85}
86
87pub trait HirDisplay<'db> {
88 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError>;
90
91 fn get_signature(&self, f: &mut HirFormatter<'db>) -> Option<String> {
93 match self.hir_fmt(f) {
94 Ok(_) => Some(f.buf.clone()),
95 Err(_) => None,
96 }
97 }
98
99 fn get_signature_with_links(
102 &self,
103 f: &mut HirFormatter<'db>,
104 ) -> (Option<String>, Vec<LocationLink<'db>>) {
105 let signature = self.get_signature(f);
106 (signature, f.location_links.clone())
107 }
108}
109
110pub struct HirFormatter<'db> {
112 db: &'db dyn Database,
114 buf: String,
116 location_links: Vec<LocationLink<'db>>,
118}
119
120impl<'db> fmt::Write for HirFormatter<'db> {
121 fn write_str(&mut self, s: &str) -> fmt::Result {
122 self.buf.push_str(s);
123 Ok(())
124 }
125}
126
127impl<'db> HirFormatter<'db> {
129 pub fn new(db: &'db dyn Database) -> Self {
131 Self { db, buf: String::new(), location_links: Vec::new() }
132 }
133
134 fn add_location_link(&mut self, start: usize, end: usize, item_id: DocumentableItemId<'db>) {
136 self.location_links.push(LocationLink { start, end, item_id })
137 }
138
139 fn hir_write(&mut self, s: &str) -> Result<(), SignatureError> {
141 self.write_str(s)?;
142 Ok(())
143 }
144
145 fn write_type(
148 &mut self,
149 prefix: Option<&str>,
150 element_type: TypeId<'db>,
151 postfix: Option<&str>,
152 full_path: &String,
153 ) -> Result<(), SignatureError> {
154 self.write_str(prefix.unwrap_or_default())?;
155 let formatted_element_type = element_type.format(self.db);
156
157 if let TypeLongId::Tuple(vec_types) = element_type.long(self.db) {
158 self.write_str("(")?;
159 let mut count = vec_types.len();
160 for t in vec_types {
161 self.write_type(None, *t, if count == 1 { None } else { Some(", ") }, full_path)?;
162 count -= 1;
163 }
164 self.write_str(")")?;
165 } else if is_the_same_root(full_path, &formatted_element_type) {
166 let documentable_id = resolve_type(self.db, element_type);
167 match documentable_id {
168 Some(documentable_id) => {
169 let start_offset = self.buf.len();
170 self.write_str(&extract_and_format(&formatted_element_type))?;
171 let end_offset = self.buf.len();
172 self.add_location_link(start_offset, end_offset, documentable_id);
173 }
174 None => {
175 self.write_str(&extract_and_format(&formatted_element_type))?;
176 }
177 }
178 } else {
179 self.write_str(&extract_and_format(&formatted_element_type))?;
180 }
181 self.hir_write(postfix.unwrap_or_default())
182 }
183
184 fn write_link(
187 &mut self,
188 name: String,
189 documentable_id: Option<DocumentableItemId<'db>>,
190 ) -> fmt::Result {
191 match documentable_id {
192 Some(documentable_id) => {
193 let start_offset = self.buf.len();
194 self.write_str(&name)?;
195 let end_offset = self.buf.len();
196 self.add_location_link(start_offset, end_offset, documentable_id);
197 Ok(())
198 }
199 None => self.write_str(&extract_and_format(&name)),
200 }
201 }
202
203 fn format(&mut self) {
207 let (formatted_signature, moved_location_links) = format_signature(
208 self.db,
209 std::mem::take(&mut self.buf),
210 std::mem::take(&mut self.location_links),
211 );
212 self.buf = formatted_signature;
213 self.location_links = moved_location_links;
214 }
215
216 fn write_chunk(
218 &mut self,
219 text: &str,
220 location_links: Vec<LocationLink<'db>>,
221 ) -> Result<(), SignatureError> {
222 let offset = self.buf.len();
223 self.buf.push_str(text);
224 for location_link in location_links {
225 self.add_location_link(
226 offset + location_link.start,
227 offset + location_link.end,
228 location_link.item_id,
229 );
230 }
231 Ok(())
232 }
233}
234
235impl<'db> HirDisplay<'db> for VariantId<'db> {
236 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
237 let name = self.name(f.db);
238 let variant_semantic = f.db.variant_semantic(self.enum_id(f.db), *self)?;
239 if !variant_semantic.ty.is_unit(f.db) {
240 f.write_type(
241 Some(&format!("{}: ", name.long(f.db))),
242 variant_semantic.ty,
243 None,
244 &self.full_path(f.db),
245 )
246 } else {
247 f.hir_write(name.long(f.db))
248 }
249 }
250}
251
252impl<'db> HirDisplay<'db> for EnumId<'db> {
253 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
254 let enum_full_signature = Self::retrieve_signature_data(f.db, *self)?;
255 write!(
256 f,
257 "{}enum {} {{",
258 get_syntactic_visibility(&enum_full_signature.visibility),
259 enum_full_signature.name.long(f.db),
260 )?;
261 let variants = enum_full_signature.variants;
262 if let Some(variants) = variants {
263 let is_variants_empty = variants.is_empty();
264 for (name, variant_type) in variants {
265 if !variant_type.is_unit(f.db) {
266 f.write_type(
267 Some(&format!("\n{INDENT}{}: ", name.long(f.db))),
268 variant_type,
269 Some(","),
270 &enum_full_signature.full_path,
271 )
272 } else {
273 f.hir_write(&format!("\n{INDENT}{},", name.long(f.db)))
274 }?;
275 }
276 f.hir_write(if is_variants_empty { "}" } else { "\n}" })
277 } else {
278 f.hir_write("}")
279 }?;
280 f.format();
281 Ok(())
282 }
283}
284
285impl<'db> HirDisplay<'db> for MemberId<'db> {
286 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
287 let member_full_signature = Self::retrieve_signature_data(f.db, *self)?;
288 if let Some(return_type) = member_full_signature.return_type {
289 if return_type.is_unit(f.db) {
290 f.hir_write(&format!(
291 "{}{} = ",
292 get_syntactic_visibility(&member_full_signature.visibility),
293 member_full_signature.name.long(f.db),
294 ))
295 } else {
296 f.write_type(
297 Some(&format!(
298 "{}{}: ",
299 get_syntactic_visibility(&member_full_signature.visibility),
300 member_full_signature.name.long(f.db),
301 )),
302 return_type,
303 None,
304 &member_full_signature.full_path,
305 )
306 }
307 } else {
308 Err(SignatureError::FailedWritingSignature(member_full_signature.full_path.clone()))
309 }
310 }
311}
312
313impl<'db> HirDisplay<'db> for StructId<'db> {
314 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
315 let struct_full_signature = Self::retrieve_signature_data(f.db, *self)?;
316 if let Some(attributes) = struct_full_signature.attributes {
317 let stx = get_struct_attributes_syntax(attributes, f.db)?;
318 f.hir_write(&stx)?;
319 }
320 write!(
321 f,
322 "{}struct {}",
323 get_syntactic_visibility(&struct_full_signature.visibility),
324 struct_full_signature.name.long(f.db),
325 )?;
326 if let Some(generic_params) = struct_full_signature.generic_params {
327 let (stx, lls) = get_generic_params(generic_params, f.db)?;
328 f.write_chunk(&stx, lls)?;
329 }
330
331 f.hir_write(" {")?;
332
333 if let Some(members) = struct_full_signature.members {
334 let is_members_empty = members.is_empty();
335 for member in members {
336 let (name, member_type, visibility) = member;
337 f.write_type(
338 Some(&format!(
339 "\n{INDENT}{}{}: ",
340 get_syntactic_visibility(&visibility),
341 name.long(f.db),
342 )),
343 member_type,
344 Some(","),
345 &struct_full_signature.full_path,
346 )?;
347 }
348 f.hir_write(if is_members_empty { "}" } else { "\n}" })?;
349 };
350 f.format();
351 Ok(())
352 }
353}
354
355impl<'db> HirDisplay<'db> for FreeFunctionId<'db> {
356 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
357 let free_function_full_signature = Self::retrieve_signature_data(f.db, *self)?;
358 write_function_signature(f, free_function_full_signature, "".to_string())?;
359 f.format();
360 Ok(())
361 }
362}
363
364impl<'db> HirDisplay<'db> for ConstantId<'db> {
365 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
366 let constant_full_signature = Self::retrieve_signature_data(f.db, *self)?;
367 write!(
368 f,
369 "{}const {}: ",
370 get_syntactic_visibility(&constant_full_signature.visibility),
371 constant_full_signature.name.long(f.db),
372 )?;
373 if let Some(return_type) = constant_full_signature.return_type {
374 f.write_type(None, return_type, Some(" = "), &constant_full_signature.full_path)?;
375 }
376 if let Some(return_value_expr) = constant_full_signature.return_value_expr {
377 match return_value_expr {
378 Expr::Literal(v) => write!(f, "{};", v.value),
379 Expr::FunctionCall(_) => {
380 let const_value_id = f.db.constant_const_value(*self)?;
381 let constant_value = const_value_id.long(f.db);
382 if let ConstValue::Int(value, _) = constant_value {
383 let stx = get_syntactic_evaluation(constant_full_signature.item_id, f.db)?;
384 write!(f, "{stx} // = {value}")
385 } else {
386 let stx = get_syntactic_evaluation(constant_full_signature.item_id, f.db)?;
387 write!(f, "{stx};")
388 }
389 }
390 _ => write!(
391 f,
392 "{}",
393 get_syntactic_evaluation(constant_full_signature.item_id, f.db)?
394 ),
395 }
396 } else {
397 write!(f, "{}", get_syntactic_evaluation(constant_full_signature.item_id, f.db)?)
398 }?;
399 f.format();
400 Ok(())
401 }
402}
403
404impl<'db> HirDisplay<'db> for ImplConstantDefId<'db> {
405 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
406 let constant_full_signature = Self::retrieve_signature_data(f.db, *self)?;
407 if let Some(return_type) = constant_full_signature.return_type {
408 f.write_type(
409 Some(&format!("const {}: ", constant_full_signature.name.long(f.db))),
410 return_type,
411 Some(" = "),
412 &constant_full_signature.full_path,
413 )?;
414 }
415 let stx = get_syntactic_evaluation(constant_full_signature.item_id, f.db)?;
416 f.hir_write(&stx)?;
417 f.format();
418 Ok(())
419 }
420}
421
422impl<'db> HirDisplay<'db> for TraitFunctionId<'db> {
423 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
424 let trait_function_full_signature = Self::retrieve_signature_data(f.db, *self)?;
425 write_function_signature(f, trait_function_full_signature, "".to_string())?;
426 f.format();
427 Ok(())
428 }
429}
430
431impl<'db> HirDisplay<'db> for ImplFunctionId<'db> {
432 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
433 let impl_function_full_signature = Self::retrieve_signature_data(f.db, *self)?;
434 write_function_signature(f, impl_function_full_signature, "".to_string())?;
435 f.format();
436 Ok(())
437 }
438}
439
440impl<'db> HirDisplay<'db> for TraitId<'db> {
441 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
442 let trait_full_signature = Self::retrieve_signature_data(f.db, *self)?;
443 write!(
444 f,
445 "{}trait {}",
446 get_syntactic_visibility(&trait_full_signature.visibility),
447 trait_full_signature.name.long(f.db),
448 )?;
449 if let Some(generic_params) = trait_full_signature.generic_params {
450 let (stx, lls) = get_generic_params(generic_params, f.db)?;
451 f.write_chunk(&stx, lls)?;
452 };
453 f.format();
454 Ok(())
455 }
456}
457
458impl<'db> HirDisplay<'db> for TraitConstantId<'db> {
459 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
460 let trait_const_full_signature = Self::retrieve_signature_data(f.db, *self)?;
461 let return_type = trait_const_full_signature.return_type.ok_or(
462 SignatureError::FailedRetrievingSemanticData(trait_const_full_signature.full_path),
463 )?;
464 write!(
465 f,
466 "const {}: {};",
467 trait_const_full_signature.name.long(f.db),
468 extract_and_format(&return_type.format(f.db)),
469 )?;
470
471 f.format();
472 Ok(())
473 }
474}
475
476impl<'db> HirDisplay<'db> for ImplDefId<'db> {
477 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
478 let impl_def_full_signature = Self::retrieve_signature_data(f.db, *self)?;
479 let trait_id = f.db.impl_def_trait(*self)?;
480
481 if let Some(resolver_generic_params) = impl_def_full_signature.resolver_generic_params {
482 let resolver_generic_params =
483 format_resolver_generic_params(f.db, resolver_generic_params);
484 write!(
485 f,
486 "{}impl {}{} of {}",
487 get_syntactic_visibility(&impl_def_full_signature.visibility),
488 impl_def_full_signature.name.long(f.db),
489 resolver_generic_params,
490 trait_id.name(f.db).long(f.db),
491 )?;
492 }
493 if let Some(generic_args) = impl_def_full_signature.generic_args {
494 write_generic_args(generic_args, f)?;
495 }
496 f.hir_write(";")?;
497 f.format();
498 Ok(())
499 }
500}
501
502impl<'db> HirDisplay<'db> for ImplAliasId<'db> {
503 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
504 let impl_alias_full_signature = Self::retrieve_signature_data(f.db, *self)?;
505 write!(
506 f,
507 "{}impl {} = ",
508 get_syntactic_visibility(&impl_alias_full_signature.visibility),
509 self.name(f.db).long(f.db),
510 )?;
511 let stx = get_syntactic_evaluation(impl_alias_full_signature.item_id, f.db)?;
512 write!(f, "{}", stx)?;
513 f.format();
514 Ok(())
515 }
516}
517
518impl<'db> HirDisplay<'db> for ModuleTypeAliasId<'db> {
519 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
520 let module_type_alias_full_signature = Self::retrieve_signature_data(f.db, *self)?;
521 write_type_signature(f, module_type_alias_full_signature, false)?;
522 f.format();
523 Ok(())
524 }
525}
526
527impl<'db> HirDisplay<'db> for TraitTypeId<'db> {
528 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
529 let trait_type_full_signature = Self::retrieve_signature_data(f.db, *self)?;
530 write_type_signature(f, trait_type_full_signature, false)?;
531 f.format();
532 Ok(())
533 }
534}
535
536impl<'db> HirDisplay<'db> for ImplTypeDefId<'db> {
537 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
538 let impl_type_def_full_signature = Self::retrieve_signature_data(f.db, *self)?;
539 write_type_signature(f, impl_type_def_full_signature, false)?;
540 f.format();
541 Ok(())
542 }
543}
544
545impl<'db> HirDisplay<'db> for ExternTypeId<'db> {
546 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
547 let extern_type_full_signature = Self::retrieve_signature_data(f.db, *self)?;
548 write_type_signature(f, extern_type_full_signature, true)?;
549 f.format();
550 Ok(())
551 }
552}
553
554impl<'db> HirDisplay<'db> for ExternFunctionId<'db> {
555 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
556 let extern_function_full_signature = Self::retrieve_signature_data(f.db, *self)?;
557 let signature = f.db.extern_function_signature(*self)?;
558 write_function_signature(f, extern_function_full_signature, "extern ".to_string())?;
559 if !signature.implicits.is_empty() {
560 f.write_str(" implicits(")?;
561 let mut count = signature.implicits.len();
562 for type_id in &signature.implicits {
563 write!(
564 f,
565 "{}{}",
566 extract_and_format(&type_id.format(f.db)),
567 if count == 1 { ")".to_string() } else { ", ".to_string() }
568 )?;
569 count -= 1;
570 }
571 }
572 if !signature.panicable {
573 f.write_str(" nopanic")?;
574 };
575 f.hir_write(";")
576 }
577}
578
579impl<'db> HirDisplay<'db> for MacroDeclarationId<'db> {
580 fn hir_fmt(&self, f: &mut HirFormatter<'db>) -> Result<(), SignatureError> {
581 let module_item_id = ModuleItemId::MacroDeclaration(*self);
582 f.write_str(&format!("macro {} {{", module_item_id.name(f.db).long(f.db)))?;
583 let macro_rules_data = f.db.macro_declaration_rules(*self)?;
584
585 for rule_data in macro_rules_data {
586 let (left_bracket, elements, right_bracket) = match rule_data.pattern {
587 WrappedMacro::Braced(m) => ("{", m.elements(f.db), "}"),
588 WrappedMacro::Bracketed(m) => ("[", m.elements(f.db), "]"),
589 WrappedMacro::Parenthesized(m) => ("(", m.elements(f.db), ")"),
590 };
591 let macro_match = elements
592 .elements_vec(f.db)
593 .iter()
594 .map(|element| element.as_syntax_node().get_text(f.db))
595 .join("")
596 .split_whitespace()
597 .join(" ");
598 f.write_str(
599 format!("\n {}{}{} => {{ ... }};", left_bracket, macro_match, right_bracket)
600 .as_str(),
601 )?;
602 }
603 f.hir_write("\n}")
604 }
605}
606
607fn is_the_same_root(path1: &str, path2: &str) -> bool {
609 fn extract_root(input: &str) -> &str {
610 if let Some(index) = input.find("::") { &input[..index] } else { input }
611 }
612 extract_root(path1) == extract_root(path2)
613}
614
615fn write_function_signature<'db>(
620 f: &mut HirFormatter<'db>,
621 documentable_signature: DocumentableItemSignatureData<'db>,
622 syntactic_kind: String,
623) -> Result<(), SignatureError> {
624 let resolver_generic_params = match documentable_signature.resolver_generic_params {
625 Some(params) => format_resolver_generic_params(f.db, params),
626 None => "".to_string(),
627 };
628
629 write!(
630 f,
631 "{}{}fn {}{}",
632 get_syntactic_visibility(&documentable_signature.visibility),
633 syntactic_kind,
634 documentable_signature.name.long(f.db),
635 resolver_generic_params,
636 )?;
637 if let Some(generic_args) = documentable_signature.generic_args {
638 write_generic_args(generic_args, f)?;
639 }
640 f.write_str("(")?;
641 if let Some(params) = documentable_signature.params {
642 let mut count = params.len();
643 let mut postfix = String::from(", ");
644 for param in params {
645 if count == 1 {
646 postfix = "".to_string();
647 }
648 let syntax_node = param.id.stable_location(f.db).syntax_node(f.db);
649 let modifier = get_relevant_modifier(¶m.mutability);
650 let modifier_postfix = if modifier.is_empty() { "" } else { " " };
651 if param.ty.is_fully_concrete(f.db) {
652 f.write_type(
653 Some(&format!("{modifier}{modifier_postfix}{}: ", param.name.long(f.db))),
654 param.ty,
655 Some(&postfix),
656 &documentable_signature.full_path,
657 )?;
658 } else {
659 let type_definition = get_type_clause(syntax_node, f.db).unwrap_or_default();
660 write!(
661 f,
662 "{modifier}{modifier_postfix}{}{type_definition}{postfix}",
663 param.name.long(f.db)
664 )?;
665 }
666 count -= 1;
667 }
668 }
669 f.write_str(")")?;
670
671 if let Some(return_type) = documentable_signature.return_type
672 && !return_type.is_unit(f.db)
673 {
674 f.write_type(Some(" -> "), return_type, None, &documentable_signature.full_path)?;
675 }
676 Ok(())
677}
678
679fn get_type_clause<'db>(syntax_node: SyntaxNode<'db>, db: &'db dyn Database) -> Option<String> {
681 for child in syntax_node.get_children(db).iter() {
682 if child.kind(db) == SyntaxKind::TypeClause {
683 return Some(child.get_text_without_all_comment_trivia(db));
684 }
685 }
686 Some(String::from(MISSING))
687}
688
689fn write_generic_args<'db>(
691 generic_args: Vec<GenericArgumentId<'db>>,
692 f: &mut HirFormatter<'db>,
693) -> Result<(), fmt::Error> {
694 let mut count = generic_args.len();
695 if !generic_args.is_empty() {
696 f.write_str("<")?;
697 }
698 for arg in &generic_args {
699 let documentable_id = resolve_generic_arg(*arg, f.db);
700 let _ = f.write_link(extract_and_format(&arg.format(f.db)), documentable_id);
701 let _ = f.write_str(if count == 1 { ">" } else { ", " });
702 count -= 1;
703 }
704 Ok(())
705}
706
707fn write_type_signature<'db>(
711 f: &mut HirFormatter<'db>,
712 documentable_signature: DocumentableItemSignatureData<'db>,
713 is_extern_type: bool,
714) -> Result<(), fmt::Error> {
715 write!(
716 f,
717 "{}{}type {}",
718 get_syntactic_visibility(&documentable_signature.visibility),
719 if is_extern_type { "extern " } else { "" },
720 documentable_signature.name.long(f.db)
721 )?;
722 if let Some(generic_params) = documentable_signature.generic_params {
723 let (stx, lls) = get_generic_params(generic_params, f.db)?;
724 f.write_chunk(&stx, lls)?;
725 }
726 if let Some(return_type) = documentable_signature.return_type {
727 write!(f, " = ")?;
728 f.write_type(None, return_type, None, &documentable_signature.full_path)?;
729 };
730 write!(f, ";")?;
731 Ok(())
732}
733
734fn resolve_generic_arg<'db>(
736 generic_arg_id: GenericArgumentId<'db>,
737 db: &'db dyn Database,
738) -> Option<DocumentableItemId<'db>> {
739 match generic_arg_id {
740 GenericArgumentId::Type(type_id) => resolve_type(db, type_id),
741 GenericArgumentId::Constant(constant_value_id) => match constant_value_id.ty(db) {
742 Ok(type_id) => resolve_type(db, type_id),
743 Err(_) => None,
744 },
745 GenericArgumentId::Impl(impl_id) => match impl_id.concrete_trait(db) {
746 Ok(concrete_trait) => {
747 let trait_id = concrete_trait.trait_id(db);
748 Some(DocumentableItemId::from(LookupItemId::ModuleItem(ModuleItemId::Trait(
749 trait_id,
750 ))))
751 }
752 Err(_) => None,
753 },
754 GenericArgumentId::NegImpl(_) => None,
755 }
756}