From ed4f13e5c796120cc0c051825116a29374b6745b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 8 Jan 2019 18:38:34 +0300 Subject: remove FnSignatureInfo from hir --- crates/ra_analysis/src/call_info.rs | 122 +++++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 10 deletions(-) (limited to 'crates/ra_analysis/src/call_info.rs') 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 @@ +use std::cmp::{max, min}; + use ra_db::{SyntaxDatabase, Cancelable}; use ra_syntax::{ AstNode, SyntaxNode, TextUnit, TextRange, SyntaxKind::FN_DEF, - ast::{self, ArgListOwner}, + ast::{self, ArgListOwner, DocCommentsOwner}, }; use ra_editor::find_node_at_offset; -use hir::FnSignatureInfo; use crate::{FilePosition, CallInfo, db::RootDatabase}; pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable> { - let (sig_info, active_parameter) = ctry!(call_info_(db, position)?); + let (sig_info, active_parameter) = ctry!(signature_and_active_param(db, position)?); let res = CallInfo { label: sig_info.label, doc: sig_info.doc, @@ -21,7 +22,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Cancelable } /// Computes parameter information for the given call expression. -fn call_info_( +fn signature_and_active_param( db: &RootDatabase, position: FilePosition, ) -> Cancelable)>> { @@ -39,12 +40,7 @@ fn call_info_( let fn_file = db.source_file(symbol.file_id); let fn_def = symbol.ptr.resolve(&fn_file); let fn_def = ast::FnDef::cast(&fn_def).unwrap(); - let descr = ctry!(hir::source_binder::function_from_source( - db, - symbol.file_id, - fn_def - )?); - if let Some(descriptor) = descr.signature_info(db) { + if let Some(descriptor) = FnSignatureInfo::new(fn_def) { // If we have a calling expression let's find which argument we are on let mut current_parameter = None; @@ -129,6 +125,112 @@ impl<'a> FnCallNode<'a> { } } +#[derive(Debug, Clone)] +struct FnSignatureInfo { + label: String, + params: Vec, + doc: Option, +} + +impl FnSignatureInfo { + fn new(node: &ast::FnDef) -> Option { + let mut doc = None; + + // Strip the body out for the label. + let mut label: String = if let Some(body) = node.body() { + let body_range = body.syntax().range(); + let label: String = node + .syntax() + .children() + .filter(|child| !child.range().is_subrange(&body_range)) + .map(|node| node.text().to_string()) + .collect(); + label + } else { + node.syntax().text().to_string() + }; + + if let Some((comment_range, docs)) = FnSignatureInfo::extract_doc_comments(node) { + let comment_range = comment_range + .checked_sub(node.syntax().range().start()) + .unwrap(); + let start = comment_range.start().to_usize(); + let end = comment_range.end().to_usize(); + + // Remove the comment from the label + label.replace_range(start..end, ""); + + // Massage markdown + let mut processed_lines = Vec::new(); + let mut in_code_block = false; + for line in docs.lines() { + if line.starts_with("```") { + in_code_block = !in_code_block; + } + + let line = if in_code_block && line.starts_with("```") && !line.contains("rust") { + "```rust".into() + } else { + line.to_string() + }; + + processed_lines.push(line); + } + + if !processed_lines.is_empty() { + doc = Some(processed_lines.join("\n")); + } + } + + let params = FnSignatureInfo::param_list(node); + + Some(FnSignatureInfo { + params, + label: label.trim().to_owned(), + doc, + }) + } + + fn extract_doc_comments(node: &ast::FnDef) -> Option<(TextRange, String)> { + if node.doc_comments().count() == 0 { + return None; + } + + let comment_text = node.doc_comment_text(); + + let (begin, end) = node + .doc_comments() + .map(|comment| comment.syntax().range()) + .map(|range| (range.start().to_usize(), range.end().to_usize())) + .fold((std::usize::MAX, std::usize::MIN), |acc, range| { + (min(acc.0, range.0), max(acc.1, range.1)) + }); + + let range = TextRange::from_to(TextUnit::from_usize(begin), TextUnit::from_usize(end)); + + Some((range, comment_text)) + } + + fn param_list(node: &ast::FnDef) -> Vec { + let mut res = vec![]; + if let Some(param_list) = node.param_list() { + if let Some(self_param) = param_list.self_param() { + res.push(self_param.syntax().text().to_string()) + } + + // Maybe use param.pat here? See if we can just extract the name? + //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); + res.extend( + param_list + .params() + .filter_map(|p| p.pat()) + .map(|pat| pat.syntax().text().to_string()), + ); + } + res + } +} + #[cfg(test)] mod tests { use super::*; -- cgit v1.2.3