diff options
Diffstat (limited to 'crates/ra_ide/src/display/function_signature.rs')
-rw-r--r-- | crates/ra_ide/src/display/function_signature.rs | 215 |
1 files changed, 215 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..d96de4e4c --- /dev/null +++ b/crates/ra_ide/src/display/function_signature.rs | |||
@@ -0,0 +1,215 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::fmt::{self, Display}; | ||
4 | |||
5 | use hir::{Docs, Documentation, HasSource, HirDisplay}; | ||
6 | use join_to_string::join; | ||
7 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | ||
8 | use std::convert::From; | ||
9 | |||
10 | use crate::{ | ||
11 | db, | ||
12 | display::{generic_parameters, where_predicates}, | ||
13 | }; | ||
14 | |||
15 | #[derive(Debug)] | ||
16 | pub enum CallableKind { | ||
17 | Function, | ||
18 | StructConstructor, | ||
19 | VariantConstructor, | ||
20 | Macro, | ||
21 | } | ||
22 | |||
23 | /// Contains information about a function signature | ||
24 | #[derive(Debug)] | ||
25 | pub 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 | |||
43 | impl 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 = match variant.parent_enum(db).name(db) { | ||
97 | Some(name) => name.to_string(), | ||
98 | None => "missing".into(), | ||
99 | }; | ||
100 | |||
101 | let name = format!("{}::{}", parent_name, variant.name(db).unwrap()); | ||
102 | |||
103 | let params = variant | ||
104 | .fields(db) | ||
105 | .into_iter() | ||
106 | .map(|field: hir::StructField| { | ||
107 | let name = field.name(db); | ||
108 | let ty = field.ty(db); | ||
109 | format!("{}: {}", name, ty.display(db)) | ||
110 | }) | ||
111 | .collect(); | ||
112 | |||
113 | Some( | ||
114 | FunctionSignature { | ||
115 | kind: CallableKind::VariantConstructor, | ||
116 | visibility: None, | ||
117 | name: Some(name), | ||
118 | ret_type: None, | ||
119 | parameters: params, | ||
120 | generic_parameters: vec![], | ||
121 | where_predicates: vec![], | ||
122 | doc: None, | ||
123 | } | ||
124 | .with_doc_opt(variant.docs(db)), | ||
125 | ) | ||
126 | } | ||
127 | |||
128 | pub(crate) fn from_macro(db: &db::RootDatabase, macro_def: hir::MacroDef) -> Option<Self> { | ||
129 | let node: ast::MacroCall = macro_def.source(db).value; | ||
130 | |||
131 | let params = vec![]; | ||
132 | |||
133 | Some( | ||
134 | FunctionSignature { | ||
135 | kind: CallableKind::Macro, | ||
136 | visibility: None, | ||
137 | name: node.name().map(|n| n.text().to_string()), | ||
138 | ret_type: None, | ||
139 | parameters: params, | ||
140 | generic_parameters: vec![], | ||
141 | where_predicates: vec![], | ||
142 | doc: None, | ||
143 | } | ||
144 | .with_doc_opt(macro_def.docs(db)), | ||
145 | ) | ||
146 | } | ||
147 | } | ||
148 | |||
149 | impl From<&'_ ast::FnDef> for FunctionSignature { | ||
150 | fn from(node: &ast::FnDef) -> FunctionSignature { | ||
151 | fn param_list(node: &ast::FnDef) -> Vec<String> { | ||
152 | let mut res = vec![]; | ||
153 | if let Some(param_list) = node.param_list() { | ||
154 | if let Some(self_param) = param_list.self_param() { | ||
155 | res.push(self_param.syntax().text().to_string()) | ||
156 | } | ||
157 | |||
158 | res.extend(param_list.params().map(|param| param.syntax().text().to_string())); | ||
159 | } | ||
160 | res | ||
161 | } | ||
162 | |||
163 | FunctionSignature { | ||
164 | kind: CallableKind::Function, | ||
165 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), | ||
166 | name: node.name().map(|n| n.text().to_string()), | ||
167 | ret_type: node | ||
168 | .ret_type() | ||
169 | .and_then(|r| r.type_ref()) | ||
170 | .map(|n| n.syntax().text().to_string()), | ||
171 | parameters: param_list(node), | ||
172 | generic_parameters: generic_parameters(node), | ||
173 | where_predicates: where_predicates(node), | ||
174 | // docs are processed separately | ||
175 | doc: None, | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | impl Display for FunctionSignature { | ||
181 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
182 | if let Some(t) = &self.visibility { | ||
183 | write!(f, "{} ", t)?; | ||
184 | } | ||
185 | |||
186 | if let Some(name) = &self.name { | ||
187 | match self.kind { | ||
188 | CallableKind::Function => write!(f, "fn {}", name)?, | ||
189 | CallableKind::StructConstructor => write!(f, "struct {}", name)?, | ||
190 | CallableKind::VariantConstructor => write!(f, "{}", name)?, | ||
191 | CallableKind::Macro => write!(f, "{}!", name)?, | ||
192 | } | ||
193 | } | ||
194 | |||
195 | if !self.generic_parameters.is_empty() { | ||
196 | join(self.generic_parameters.iter()) | ||
197 | .separator(", ") | ||
198 | .surround_with("<", ">") | ||
199 | .to_fmt(f)?; | ||
200 | } | ||
201 | |||
202 | join(self.parameters.iter()).separator(", ").surround_with("(", ")").to_fmt(f)?; | ||
203 | |||
204 | if let Some(t) = &self.ret_type { | ||
205 | write!(f, " -> {}", t)?; | ||
206 | } | ||
207 | |||
208 | if !self.where_predicates.is_empty() { | ||
209 | write!(f, "\nwhere ")?; | ||
210 | join(self.where_predicates.iter()).separator(",\n ").to_fmt(f)?; | ||
211 | } | ||
212 | |||
213 | Ok(()) | ||
214 | } | ||
215 | } | ||