aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_analysis/src/call_info.rs122
-rw-r--r--crates/ra_analysis/src/lib.rs1
-rw-r--r--crates/ra_hir/src/function.rs127
-rw-r--r--crates/ra_hir/src/lib.rs2
4 files changed, 115 insertions, 137 deletions
diff --git a/crates/ra_analysis/src/call_info.rs b/crates/ra_analysis/src/call_info.rs
index 2fcd03c9b..911ac3955 100644
--- a/crates/ra_analysis/src/call_info.rs
+++ b/crates/ra_analysis/src/call_info.rs
@@ -1,16 +1,17 @@
1use std::cmp::{max, min};
2
1use ra_db::{SyntaxDatabase, Cancelable}; 3use ra_db::{SyntaxDatabase, Cancelable};
2use ra_syntax::{ 4use ra_syntax::{
3 AstNode, SyntaxNode, TextUnit, TextRange, 5 AstNode, SyntaxNode, TextUnit, TextRange,
4 SyntaxKind::FN_DEF, 6 SyntaxKind::FN_DEF,
5 ast::{self, ArgListOwner}, 7 ast::{self, ArgListOwner, DocCommentsOwner},
6}; 8};
7use ra_editor::find_node_at_offset; 9use ra_editor::find_node_at_offset;
8use hir::FnSignatureInfo;
9 10
10use crate::{FilePosition, CallInfo, db::RootDatabase}; 11use crate::{FilePosition, CallInfo, db::RootDatabase};
11 12
12pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable<Option<CallInfo>> { 13pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable<Option<CallInfo>> {
13 let (sig_info, active_parameter) = ctry!(call_info_(db, position)?); 14 let (sig_info, active_parameter) = ctry!(signature_and_active_param(db, position)?);
14 let res = CallInfo { 15 let res = CallInfo {
15 label: sig_info.label, 16 label: sig_info.label,
16 doc: sig_info.doc, 17 doc: sig_info.doc,
@@ -21,7 +22,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable
21} 22}
22 23
23/// Computes parameter information for the given call expression. 24/// Computes parameter information for the given call expression.
24fn call_info_( 25fn signature_and_active_param(
25 db: &RootDatabase, 26 db: &RootDatabase,
26 position: FilePosition, 27 position: FilePosition,
27) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { 28) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
@@ -39,12 +40,7 @@ fn call_info_(
39 let fn_file = db.source_file(symbol.file_id); 40 let fn_file = db.source_file(symbol.file_id);
40 let fn_def = symbol.ptr.resolve(&fn_file); 41 let fn_def = symbol.ptr.resolve(&fn_file);
41 let fn_def = ast::FnDef::cast(&fn_def).unwrap(); 42 let fn_def = ast::FnDef::cast(&fn_def).unwrap();
42 let descr = ctry!(hir::source_binder::function_from_source( 43 if let Some(descriptor) = FnSignatureInfo::new(fn_def) {
43 db,
44 symbol.file_id,
45 fn_def
46 )?);
47 if let Some(descriptor) = descr.signature_info(db) {
48 // If we have a calling expression let's find which argument we are on 44 // If we have a calling expression let's find which argument we are on
49 let mut current_parameter = None; 45 let mut current_parameter = None;
50 46
@@ -129,6 +125,112 @@ impl<'a> FnCallNode<'a> {
129 } 125 }
130} 126}
131 127
128#[derive(Debug, Clone)]
129struct FnSignatureInfo {
130 label: String,
131 params: Vec<String>,
132 doc: Option<String>,
133}
134
135impl FnSignatureInfo {
136 fn new(node: &ast::FnDef) -> Option<Self> {
137 let mut doc = None;
138
139 // Strip the body out for the label.
140 let mut label: String = if let Some(body) = node.body() {
141 let body_range = body.syntax().range();
142 let label: String = node
143 .syntax()
144 .children()
145 .filter(|child| !child.range().is_subrange(&body_range))
146 .map(|node| node.text().to_string())
147 .collect();
148 label
149 } else {
150 node.syntax().text().to_string()
151 };
152
153 if let Some((comment_range, docs)) = FnSignatureInfo::extract_doc_comments(node) {
154 let comment_range = comment_range
155 .checked_sub(node.syntax().range().start())
156 .unwrap();
157 let start = comment_range.start().to_usize();
158 let end = comment_range.end().to_usize();
159
160 // Remove the comment from the label
161 label.replace_range(start..end, "");
162
163 // Massage markdown
164 let mut processed_lines = Vec::new();
165 let mut in_code_block = false;
166 for line in docs.lines() {
167 if line.starts_with("```") {
168 in_code_block = !in_code_block;
169 }
170
171 let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
172 "```rust".into()
173 } else {
174 line.to_string()
175 };
176
177 processed_lines.push(line);
178 }
179
180 if !processed_lines.is_empty() {
181 doc = Some(processed_lines.join("\n"));
182 }
183 }
184
185 let params = FnSignatureInfo::param_list(node);
186
187 Some(FnSignatureInfo {
188 params,
189 label: label.trim().to_owned(),
190 doc,
191 })
192 }
193
194 fn extract_doc_comments(node: &ast::FnDef) -> Option<(TextRange, String)> {
195 if node.doc_comments().count() == 0 {
196 return None;
197 }
198
199 let comment_text = node.doc_comment_text();
200
201 let (begin, end) = node
202 .doc_comments()
203 .map(|comment| comment.syntax().range())
204 .map(|range| (range.start().to_usize(), range.end().to_usize()))
205 .fold((std::usize::MAX, std::usize::MIN), |acc, range| {
206 (min(acc.0, range.0), max(acc.1, range.1))
207 });
208
209 let range = TextRange::from_to(TextUnit::from_usize(begin), TextUnit::from_usize(end));
210
211 Some((range, comment_text))
212 }
213
214 fn param_list(node: &ast::FnDef) -> Vec<String> {
215 let mut res = vec![];
216 if let Some(param_list) = node.param_list() {
217 if let Some(self_param) = param_list.self_param() {
218 res.push(self_param.syntax().text().to_string())
219 }
220
221 // Maybe use param.pat here? See if we can just extract the name?
222 //res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
223 res.extend(
224 param_list
225 .params()
226 .filter_map(|p| p.pat())
227 .map(|pat| pat.syntax().text().to_string()),
228 );
229 }
230 res
231 }
232}
233
132#[cfg(test)] 234#[cfg(test)]
133mod tests { 235mod tests {
134 use super::*; 236 use super::*;
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 4fa6750aa..771a349c8 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -40,7 +40,6 @@ pub use crate::{
40 completion::{CompletionItem, CompletionItemKind, InsertText}, 40 completion::{CompletionItem, CompletionItemKind, InsertText},
41 runnables::{Runnable, RunnableKind}, 41 runnables::{Runnable, RunnableKind},
42}; 42};
43pub use hir::FnSignatureInfo;
44pub use ra_editor::{Fold, FoldKind, HighlightedRange, LineIndex, Severity, StructureNode}; 43pub use ra_editor::{Fold, FoldKind, HighlightedRange, LineIndex, Severity, StructureNode};
45 44
46pub use ra_db::{ 45pub use ra_db::{
diff --git a/crates/ra_hir/src/function.rs b/crates/ra_hir/src/function.rs
index 81b790c5f..2cfc4caa4 100644
--- a/crates/ra_hir/src/function.rs
+++ b/crates/ra_hir/src/function.rs
@@ -1,14 +1,11 @@
1mod scope; 1mod scope;
2 2
3use std::{ 3use std::sync::Arc;
4 cmp::{max, min},
5 sync::Arc,
6};
7 4
8use ra_db::Cancelable; 5use ra_db::Cancelable;
9use ra_syntax::{ 6use ra_syntax::{
10 TextRange, TextUnit, TreePtr, 7 TreePtr,
11 ast::{self, AstNode, DocCommentsOwner, NameOwner}, 8 ast::{self, AstNode},
12}; 9};
13 10
14use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock, expr::{Body, BodySyntaxMapping}, type_ref::{TypeRef, Mutability}, Name}; 11use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock, expr::{Body, BodySyntaxMapping}, type_ref::{TypeRef, Mutability}, Name};
@@ -57,11 +54,6 @@ impl Function {
57 db.fn_signature(self.def_id) 54 db.fn_signature(self.def_id)
58 } 55 }
59 56
60 pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> {
61 let syntax = self.syntax(db);
62 FnSignatureInfo::new(&syntax)
63 }
64
65 pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> { 57 pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> {
66 db.infer(self.def_id) 58 db.infer(self.def_id)
67 } 59 }
@@ -132,116 +124,3 @@ pub(crate) fn fn_signature(db: &impl HirDatabase, def_id: DefId) -> Arc<FnSignat
132 let sig = FnSignature { args, ret_type }; 124 let sig = FnSignature { args, ret_type };
133 Arc::new(sig) 125 Arc::new(sig)
134} 126}
135
136#[derive(Debug, Clone)]
137pub struct FnSignatureInfo {
138 pub name: String,
139 pub label: String,
140 pub ret_type: Option<String>,
141 pub params: Vec<String>,
142 pub doc: Option<String>,
143}
144
145impl FnSignatureInfo {
146 fn new(node: &ast::FnDef) -> Option<Self> {
147 let name = node.name()?.text().to_string();
148
149 let mut doc = None;
150
151 // Strip the body out for the label.
152 let mut label: String = if let Some(body) = node.body() {
153 let body_range = body.syntax().range();
154 let label: String = node
155 .syntax()
156 .children()
157 .filter(|child| !child.range().is_subrange(&body_range))
158 .map(|node| node.text().to_string())
159 .collect();
160 label
161 } else {
162 node.syntax().text().to_string()
163 };
164
165 if let Some((comment_range, docs)) = FnSignatureInfo::extract_doc_comments(node) {
166 let comment_range = comment_range
167 .checked_sub(node.syntax().range().start())
168 .unwrap();
169 let start = comment_range.start().to_usize();
170 let end = comment_range.end().to_usize();
171
172 // Remove the comment from the label
173 label.replace_range(start..end, "");
174
175 // Massage markdown
176 let mut processed_lines = Vec::new();
177 let mut in_code_block = false;
178 for line in docs.lines() {
179 if line.starts_with("```") {
180 in_code_block = !in_code_block;
181 }
182
183 let line = if in_code_block && line.starts_with("```") && !line.contains("rust") {
184 "```rust".into()
185 } else {
186 line.to_string()
187 };
188
189 processed_lines.push(line);
190 }
191
192 if !processed_lines.is_empty() {
193 doc = Some(processed_lines.join("\n"));
194 }
195 }
196
197 let params = FnSignatureInfo::param_list(node);
198 let ret_type = node.ret_type().map(|r| r.syntax().text().to_string());
199
200 Some(FnSignatureInfo {
201 name,
202 ret_type,
203 params,
204 label: label.trim().to_owned(),
205 doc,
206 })
207 }
208
209 fn extract_doc_comments(node: &ast::FnDef) -> Option<(TextRange, String)> {
210 if node.doc_comments().count() == 0 {
211 return None;
212 }
213
214 let comment_text = node.doc_comment_text();
215
216 let (begin, end) = node
217 .doc_comments()
218 .map(|comment| comment.syntax().range())
219 .map(|range| (range.start().to_usize(), range.end().to_usize()))
220 .fold((std::usize::MAX, std::usize::MIN), |acc, range| {
221 (min(acc.0, range.0), max(acc.1, range.1))
222 });
223
224 let range = TextRange::from_to(TextUnit::from_usize(begin), TextUnit::from_usize(end));
225
226 Some((range, comment_text))
227 }
228
229 fn param_list(node: &ast::FnDef) -> Vec<String> {
230 let mut res = vec![];
231 if let Some(param_list) = node.param_list() {
232 if let Some(self_param) = param_list.self_param() {
233 res.push(self_param.syntax().text().to_string())
234 }
235
236 // Maybe use param.pat here? See if we can just extract the name?
237 //res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
238 res.extend(
239 param_list
240 .params()
241 .filter_map(|p| p.pat())
242 .map(|pat| pat.syntax().text().to_string()),
243 );
244 }
245 res
246 }
247}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index f8ac28cf7..197d8c4fd 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -53,8 +53,6 @@ pub use self::{
53 impl_block::{ImplBlock, ImplItem}, 53 impl_block::{ImplBlock, ImplItem},
54}; 54};
55 55
56pub use self::function::FnSignatureInfo;
57
58pub use self::code_model_api::{ 56pub use self::code_model_api::{
59 Crate, CrateDependency, 57 Crate, CrateDependency,
60 Module, ModuleSource, Problem, 58 Module, ModuleSource, Problem,