aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/display/function_signature.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/display/function_signature.rs')
-rw-r--r--crates/ra_ide/src/display/function_signature.rs212
1 files changed, 212 insertions, 0 deletions
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
new file mode 100644
index 000000000..324ad9552
--- /dev/null
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -0,0 +1,212 @@
1//! FIXME: write short doc here
2
3use std::fmt::{self, Display};
4
5use hir::{Docs, Documentation, HasSource, HirDisplay};
6use join_to_string::join;
7use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
8use std::convert::From;
9
10use crate::{
11 db,
12 display::{generic_parameters, where_predicates},
13};
14
15#[derive(Debug)]
16pub enum CallableKind {
17 Function,
18 StructConstructor,
19 VariantConstructor,
20 Macro,
21}
22
23/// Contains information about a function signature
24#[derive(Debug)]
25pub struct FunctionSignature {
26 pub kind: CallableKind,
27 /// Optional visibility
28 pub visibility: Option<String>,
29 /// Name of the function
30 pub name: Option<String>,
31 /// Documentation for the function
32 pub doc: Option<Documentation>,
33 /// Generic parameters
34 pub generic_parameters: Vec<String>,
35 /// Parameters of the function
36 pub parameters: Vec<String>,
37 /// Optional return type
38 pub ret_type: Option<String>,
39 /// Where predicates
40 pub where_predicates: Vec<String>,
41}
42
43impl FunctionSignature {
44 pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
45 self.doc = doc;
46 self
47 }
48
49 pub(crate) fn from_hir(db: &db::RootDatabase, function: hir::Function) -> Self {
50 let doc = function.docs(db);
51 let ast_node = function.source(db).value;
52 FunctionSignature::from(&ast_node).with_doc_opt(doc)
53 }
54
55 pub(crate) fn from_struct(db: &db::RootDatabase, st: hir::Struct) -> Option<Self> {
56 let node: ast::StructDef = st.source(db).value;
57 match node.kind() {
58 ast::StructKind::Record(_) => return None,
59 _ => (),
60 };
61
62 let params = st
63 .fields(db)
64 .into_iter()
65 .map(|field: hir::StructField| {
66 let ty = field.ty(db);
67 format!("{}", ty.display(db))
68 })
69 .collect();
70
71 Some(
72 FunctionSignature {
73 kind: CallableKind::StructConstructor,
74 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
75 name: node.name().map(|n| n.text().to_string()),
76 ret_type: node.name().map(|n| n.text().to_string()),
77 parameters: params,
78 generic_parameters: generic_parameters(&node),
79 where_predicates: where_predicates(&node),
80 doc: None,
81 }
82 .with_doc_opt(st.docs(db)),
83 )
84 }
85
86 pub(crate) fn from_enum_variant(
87 db: &db::RootDatabase,
88 variant: hir::EnumVariant,
89 ) -> Option<Self> {
90 let node: ast::EnumVariant = variant.source(db).value;
91 match node.kind() {
92 ast::StructKind::Record(_) | ast::StructKind::Unit => return None,
93 _ => (),
94 };
95
96 let parent_name = variant.parent_enum(db).name(db).to_string();
97
98 let name = format!("{}::{}", parent_name, variant.name(db));
99
100 let params = variant
101 .fields(db)
102 .into_iter()
103 .map(|field: hir::StructField| {
104 let name = field.name(db);
105 let ty = field.ty(db);
106 format!("{}: {}", name, ty.display(db))
107 })
108 .collect();
109
110 Some(
111 FunctionSignature {
112 kind: CallableKind::VariantConstructor,
113 visibility: None,
114 name: Some(name),
115 ret_type: None,
116 parameters: params,
117 generic_parameters: vec![],
118 where_predicates: vec![],
119 doc: None,
120 }
121 .with_doc_opt(variant.docs(db)),
122 )
123 }
124
125 pub(crate) fn from_macro(db: &db::RootDatabase, macro_def: hir::MacroDef) -> Option<Self> {
126 let node: ast::MacroCall = macro_def.source(db).value;
127
128 let params = vec![];
129
130 Some(
131 FunctionSignature {
132 kind: CallableKind::Macro,
133 visibility: None,
134 name: node.name().map(|n| n.text().to_string()),
135 ret_type: None,
136 parameters: params,
137 generic_parameters: vec![],
138 where_predicates: vec![],
139 doc: None,
140 }
141 .with_doc_opt(macro_def.docs(db)),
142 )
143 }
144}
145
146impl From<&'_ ast::FnDef> for FunctionSignature {
147 fn from(node: &ast::FnDef) -> FunctionSignature {
148 fn param_list(node: &ast::FnDef) -> Vec<String> {
149 let mut res = vec![];
150 if let Some(param_list) = node.param_list() {
151 if let Some(self_param) = param_list.self_param() {
152 res.push(self_param.syntax().text().to_string())
153 }
154
155 res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
156 }
157 res
158 }
159
160 FunctionSignature {
161 kind: CallableKind::Function,
162 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
163 name: node.name().map(|n| n.text().to_string()),
164 ret_type: node
165 .ret_type()
166 .and_then(|r| r.type_ref())
167 .map(|n| n.syntax().text().to_string()),
168 parameters: param_list(node),
169 generic_parameters: generic_parameters(node),
170 where_predicates: where_predicates(node),
171 // docs are processed separately
172 doc: None,
173 }
174 }
175}
176
177impl Display for FunctionSignature {
178 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
179 if let Some(t) = &self.visibility {
180 write!(f, "{} ", t)?;
181 }
182
183 if let Some(name) = &self.name {
184 match self.kind {
185 CallableKind::Function => write!(f, "fn {}", name)?,
186 CallableKind::StructConstructor => write!(f, "struct {}", name)?,
187 CallableKind::VariantConstructor => write!(f, "{}", name)?,
188 CallableKind::Macro => write!(f, "{}!", name)?,
189 }
190 }
191
192 if !self.generic_parameters.is_empty() {
193 join(self.generic_parameters.iter())
194 .separator(", ")
195 .surround_with("<", ">")
196 .to_fmt(f)?;
197 }
198
199 join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?;
200
201 if let Some(t) = &self.ret_type {
202 write!(f, " -> {}", t)?;
203 }
204
205 if !self.where_predicates.is_empty() {
206 write!(f, "\nwhere ")?;
207 join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?;
208 }
209
210 Ok(())
211 }
212}