+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<Option<CallInfo>> {
- 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,
}
/// Computes parameter information for the given call expression.
-fn call_info_(
+fn signature_and_active_param(
db: &RootDatabase,
position: FilePosition,
) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> {
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;
}
}
+#[derive(Debug, Clone)]
+struct FnSignatureInfo {
+ label: String,
+ params: Vec<String>,
+ doc: Option<String>,
+}
+
+impl FnSignatureInfo {
+ fn new(node: &ast::FnDef) -> Option<Self> {
+ 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<String> {
+ 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::*;
completion::{CompletionItem, CompletionItemKind, InsertText},
runnables::{Runnable, RunnableKind},
};
-pub use hir::FnSignatureInfo;
pub use ra_editor::{Fold, FoldKind, HighlightedRange, LineIndex, Severity, StructureNode};
pub use ra_db::{
mod scope;
-use std::{
- cmp::{max, min},
- sync::Arc,
-};
+use std::sync::Arc;
use ra_db::Cancelable;
use ra_syntax::{
- TextRange, TextUnit, TreePtr,
- ast::{self, AstNode, DocCommentsOwner, NameOwner},
+ TreePtr,
+ ast::{self, AstNode},
};
use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock, expr::{Body, BodySyntaxMapping}, type_ref::{TypeRef, Mutability}, Name};
db.fn_signature(self.def_id)
}
- pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> {
- let syntax = self.syntax(db);
- FnSignatureInfo::new(&syntax)
- }
-
pub fn infer(&self, db: &impl HirDatabase) -> Cancelable<Arc<InferenceResult>> {
db.infer(self.def_id)
}
let sig = FnSignature { args, ret_type };
Arc::new(sig)
}
-
-#[derive(Debug, Clone)]
-pub struct FnSignatureInfo {
- pub name: String,
- pub label: String,
- pub ret_type: Option<String>,
- pub params: Vec<String>,
- pub doc: Option<String>,
-}
-
-impl FnSignatureInfo {
- fn new(node: &ast::FnDef) -> Option<Self> {
- let name = node.name()?.text().to_string();
-
- 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);
- let ret_type = node.ret_type().map(|r| r.syntax().text().to_string());
-
- Some(FnSignatureInfo {
- name,
- ret_type,
- 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<String> {
- 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
- }
-}
impl_block::{ImplBlock, ImplItem},
};
-pub use self::function::FnSignatureInfo;
-
pub use self::code_model_api::{
Crate, CrateDependency,
Module, ModuleSource, Problem,