From 5a59bc9fcbbacb3d214e5bb9490f66ccb0abf5cb Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 19:12:21 -0400 Subject: WIP: Expand signature help This is hacky but works for tuple structs. Proof of concept. --- crates/ra_ide_api/src/call_info.rs | 39 ++++++++++++++++++---- .../ra_ide_api/src/display/function_signature.rs | 29 +++++++++++++++- 2 files changed, 60 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index c95133343..dfd6e69c5 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -20,24 +20,27 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { //FIXME: apply subst let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; match callable_def { - hir::CallableDef::Function(it) => it, + hir::CallableDef::Function(it) => { + (CallInfo::with_fn(db, it), it.data(db).has_self_param()) + } + hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it), false), //FIXME: handle other callables _ => return None, } } - FnCallNode::MethodCallExpr(expr) => analyzer.resolve_method_call(&expr)?, + FnCallNode::MethodCallExpr(expr) => { + let function = analyzer.resolve_method_call(&expr)?; + (CallInfo::with_fn(db, function), function.data(db).has_self_param()) + } }; - let mut call_info = CallInfo::new(db, function); - // If we have a calling expression let's find which argument we are on let num_params = call_info.parameters().len(); - let has_self = function.data(db).has_self_param(); if num_params == 1 { if !has_self { @@ -115,12 +118,18 @@ impl FnCallNode { } impl CallInfo { - fn new(db: &RootDatabase, function: hir::Function) -> Self { + fn with_fn(db: &RootDatabase, function: hir::Function) -> Self { let signature = FunctionSignature::from_hir(db, function); CallInfo { signature, active_parameter: None } } + fn with_struct(db: &RootDatabase, st: hir::Struct) -> Self { + let signature = FunctionSignature::from_struct(db, st); + + CallInfo { signature, active_parameter: None } + } + fn parameters(&self) -> &[String] { &self.signature.parameters } @@ -462,4 +471,20 @@ fn main() { assert_eq!(info.active_parameter, Some(1)); assert_eq!(info.label(), "fn bar(&self, _: u32)"); } + + fn works_for_tuple_structs() { + let info = call_info( + r#" +/// A cool tuple struct +struct TS(String, i32); +fn main() { + let s = TS("".into(), <|>); +}"#, + ); + + //assert_eq!(info.label(), "struct TS(String, i32)"); + assert_eq!(info.label(), "fn TS(0: {unknown}, 1: i32) -> TS"); + assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); + assert_eq!(info.active_parameter, Some(1)); + } } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 43f022ccd..0697a0727 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display}; -use hir::{Docs, Documentation, HasSource}; +use hir::{Docs, Documentation, HasSource, HirDisplay}; use join_to_string::join; use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; use std::convert::From; @@ -42,6 +42,33 @@ impl FunctionSignature { let ast_node = function.source(db).ast; FunctionSignature::from(&ast_node).with_doc_opt(doc) } + + pub(crate) fn from_struct(db: &db::RootDatabase, st: hir::Struct) -> Self { + let doc = st.docs(db); + + let node: ast::StructDef = st.source(db).ast; + + let params = st + .fields(db) + .into_iter() + .map(|field: hir::StructField| { + let name = field.name(db); + let ty = field.ty(db); + format!("{}: {}", name, ty.display(db)) + }) + .collect(); + + FunctionSignature { + visibility: node.visibility().map(|n| n.syntax().text().to_string()), + name: node.name().map(|n| n.text().to_string()), + ret_type: node.name().map(|n| n.text().to_string()), + parameters: /*param_list(node)*/ params, + generic_parameters: generic_parameters(&node), + where_predicates: where_predicates(&node), + doc: None, + } + .with_doc_opt(doc) + } } impl From<&'_ ast::FnDef> for FunctionSignature { -- cgit v1.2.3 From 55d4b06a53246c144be900877e6ac03237d6f8b4 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 20:11:02 -0400 Subject: Add disciminant --- crates/ra_ide_api/src/call_info.rs | 10 ++++------ crates/ra_ide_api/src/display/function_signature.rs | 14 +++++++++++++- 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index dfd6e69c5..29ae2f552 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -29,8 +29,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option (CallInfo::with_struct(db, it), false), - //FIXME: handle other callables - _ => return None, + hir::CallableDef::EnumVariant(_it) => return None, } } FnCallNode::MethodCallExpr(expr) => { @@ -476,14 +475,13 @@ fn main() { let info = call_info( r#" /// A cool tuple struct -struct TS(String, i32); +struct TS(u32, i32); fn main() { - let s = TS("".into(), <|>); + let s = TS(0, <|>); }"#, ); - //assert_eq!(info.label(), "struct TS(String, i32)"); - assert_eq!(info.label(), "fn TS(0: {unknown}, 1: i32) -> TS"); + assert_eq!(info.label(), "struct TS(0: u32, 1: i32) -> TS"); assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); assert_eq!(info.active_parameter, Some(1)); } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 0697a0727..6555f8619 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -12,9 +12,16 @@ use crate::{ display::{generic_parameters, where_predicates}, }; +#[derive(Debug)] +pub enum SigKind { + Function, + Struct, +} + /// Contains information about a function signature #[derive(Debug)] pub struct FunctionSignature { + pub kind: SigKind, /// Optional visibility pub visibility: Option, /// Name of the function @@ -59,6 +66,7 @@ impl FunctionSignature { .collect(); FunctionSignature { + kind: SigKind::Struct, visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node.name().map(|n| n.text().to_string()), @@ -86,6 +94,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature { } FunctionSignature { + kind: SigKind::Function, visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node @@ -108,7 +117,10 @@ impl Display for FunctionSignature { } if let Some(name) = &self.name { - write!(f, "fn {}", name)?; + match self.kind { + SigKind::Function => write!(f, "fn {}", name)?, + SigKind::Struct => write!(f, "struct {}", name)?, + } } if !self.generic_parameters.is_empty() { -- cgit v1.2.3 From 49e89772f63e10ebeb3c8720bd0b0ef8244f6c4a Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 21:26:12 -0400 Subject: Preliminary enum variant support --- crates/ra_ide_api/src/call_info.rs | 32 ++++++++++++++++++- .../ra_ide_api/src/display/function_signature.rs | 37 +++++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 29ae2f552..e6bdaae6a 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -29,7 +29,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option (CallInfo::with_struct(db, it), false), - hir::CallableDef::EnumVariant(_it) => return None, + hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it), false), } } FnCallNode::MethodCallExpr(expr) => { @@ -129,6 +129,12 @@ impl CallInfo { CallInfo { signature, active_parameter: None } } + fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Self { + let signature = FunctionSignature::from_enum_variant(db, variant); + + CallInfo { signature, active_parameter: None } + } + fn parameters(&self) -> &[String] { &self.signature.parameters } @@ -485,4 +491,28 @@ fn main() { assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); assert_eq!(info.active_parameter, Some(1)); } + + #[test] + fn works_for_enum_variants() { + let info = call_info( + r#" +enum E { + /// A Variant + A(i32), + /// Another + B, + /// And C + C(a: i32, b: i32) +} + +fn main() { + let a = E::A(<|>); +} + "#, + ); + + assert_eq!(info.label(), "E::A(0: i32)"); + assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); + assert_eq!(info.active_parameter, Some(0)); + } } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 6555f8619..6b169b3ae 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -16,6 +16,7 @@ use crate::{ pub enum SigKind { Function, Struct, + EnumVariant, } /// Contains information about a function signature @@ -70,13 +71,46 @@ impl FunctionSignature { visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node.name().map(|n| n.text().to_string()), - parameters: /*param_list(node)*/ params, + parameters: params, generic_parameters: generic_parameters(&node), where_predicates: where_predicates(&node), doc: None, } .with_doc_opt(doc) } + + pub(crate) fn from_enum_variant(db: &db::RootDatabase, variant: hir::EnumVariant) -> Self { + let doc = variant.docs(db); + + let parent_name = match variant.parent_enum(db).name(db) { + Some(name) => name.to_string(), + None => "missing".into(), + }; + + let name = format!("{}::{}", parent_name, variant.name(db).unwrap()); + + let params = variant + .fields(db) + .into_iter() + .map(|field: hir::StructField| { + let name = field.name(db); + let ty = field.ty(db); + format!("{}: {}", name, ty.display(db)) + }) + .collect(); + + FunctionSignature { + kind: SigKind::EnumVariant, + visibility: None, + name: Some(name), + ret_type: None, + parameters: params, + generic_parameters: vec![], + where_predicates: vec![], + doc: None, + } + .with_doc_opt(doc) + } } impl From<&'_ ast::FnDef> for FunctionSignature { @@ -120,6 +154,7 @@ impl Display for FunctionSignature { match self.kind { SigKind::Function => write!(f, "fn {}", name)?, SigKind::Struct => write!(f, "struct {}", name)?, + SigKind::EnumVariant => write!(f, "{}", name)?, } } -- cgit v1.2.3 From 44f2805fee20893865039f70b97105cac2baa994 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Sun, 27 Oct 2019 22:03:58 -0400 Subject: Fix syntax --- crates/ra_ide_api/src/call_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index e6bdaae6a..faae12e54 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -502,7 +502,7 @@ enum E { /// Another B, /// And C - C(a: i32, b: i32) + C { a: i32, b: i32 } } fn main() { -- cgit v1.2.3 From ddf25e9481d79abb6b583a195fd26b8ca1b9f060 Mon Sep 17 00:00:00 2001 From: Jeremy Kolb Date: Mon, 28 Oct 2019 08:42:17 -0400 Subject: formatting --- crates/ra_ide_api/src/call_info.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index faae12e54..25363a1d9 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -476,7 +476,7 @@ fn main() { assert_eq!(info.active_parameter, Some(1)); assert_eq!(info.label(), "fn bar(&self, _: u32)"); } - + fn works_for_tuple_structs() { let info = call_info( r#" -- cgit v1.2.3 From 01238a6fd7d89f97ea05d90b95d3244f1596dc93 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Mon, 28 Oct 2019 10:48:40 -0400 Subject: Filter out non callable versions of Struct/EnumVariant --- crates/ra_ide_api/src/call_info.rs | 52 +++++++++++++--- .../ra_ide_api/src/display/function_signature.rs | 70 +++++++++++++--------- 2 files changed, 84 insertions(+), 38 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index 25363a1d9..d947ac50c 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs @@ -28,8 +28,8 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { (CallInfo::with_fn(db, it), it.data(db).has_self_param()) } - hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it), false), - hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it), false), + hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it)?, false), + hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it)?, false), } } FnCallNode::MethodCallExpr(expr) => { @@ -123,16 +123,16 @@ impl CallInfo { CallInfo { signature, active_parameter: None } } - fn with_struct(db: &RootDatabase, st: hir::Struct) -> Self { - let signature = FunctionSignature::from_struct(db, st); + fn with_struct(db: &RootDatabase, st: hir::Struct) -> Option { + let signature = FunctionSignature::from_struct(db, st)?; - CallInfo { signature, active_parameter: None } + Some(CallInfo { signature, active_parameter: None }) } - fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Self { - let signature = FunctionSignature::from_enum_variant(db, variant); + fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option { + let signature = FunctionSignature::from_enum_variant(db, variant)?; - CallInfo { signature, active_parameter: None } + Some(CallInfo { signature, active_parameter: None }) } fn parameters(&self) -> &[String] { @@ -477,6 +477,7 @@ fn main() { assert_eq!(info.label(), "fn bar(&self, _: u32)"); } + #[test] fn works_for_tuple_structs() { let info = call_info( r#" @@ -487,11 +488,23 @@ fn main() { }"#, ); - assert_eq!(info.label(), "struct TS(0: u32, 1: i32) -> TS"); + assert_eq!(info.label(), "struct TS(u32, i32) -> TS"); assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); assert_eq!(info.active_parameter, Some(1)); } + #[test] + #[should_panic] + fn cant_call_named_structs() { + let _ = call_info( + r#" +struct TS { x: u32, y: i32 } +fn main() { + let s = TS(<|>); +}"#, + ); + } + #[test] fn works_for_enum_variants() { let info = call_info( @@ -515,4 +528,25 @@ fn main() { assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); assert_eq!(info.active_parameter, Some(0)); } + + #[test] + #[should_panic] + fn cant_call_enum_records() { + let _ = call_info( + r#" +enum E { + /// A Variant + A(i32), + /// Another + B, + /// And C + C { a: i32, b: i32 } +} + +fn main() { + let a = E::C(<|>); +} + "#, + ); + } } diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 6b169b3ae..736b5d3db 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -51,36 +51,46 @@ impl FunctionSignature { FunctionSignature::from(&ast_node).with_doc_opt(doc) } - pub(crate) fn from_struct(db: &db::RootDatabase, st: hir::Struct) -> Self { - let doc = st.docs(db); - + pub(crate) fn from_struct(db: &db::RootDatabase, st: hir::Struct) -> Option { let node: ast::StructDef = st.source(db).ast; + match node.kind() { + ast::StructKind::Named(_) => return None, + _ => (), + }; let params = st .fields(db) .into_iter() .map(|field: hir::StructField| { - let name = field.name(db); let ty = field.ty(db); - format!("{}: {}", name, ty.display(db)) + format!("{}", ty.display(db)) }) .collect(); - FunctionSignature { - kind: SigKind::Struct, - visibility: node.visibility().map(|n| n.syntax().text().to_string()), - name: node.name().map(|n| n.text().to_string()), - ret_type: node.name().map(|n| n.text().to_string()), - parameters: params, - generic_parameters: generic_parameters(&node), - where_predicates: where_predicates(&node), - doc: None, - } - .with_doc_opt(doc) + Some( + FunctionSignature { + kind: SigKind::Struct, + visibility: node.visibility().map(|n| n.syntax().text().to_string()), + name: node.name().map(|n| n.text().to_string()), + ret_type: node.name().map(|n| n.text().to_string()), + parameters: params, + generic_parameters: generic_parameters(&node), + where_predicates: where_predicates(&node), + doc: None, + } + .with_doc_opt(st.docs(db)), + ) } - pub(crate) fn from_enum_variant(db: &db::RootDatabase, variant: hir::EnumVariant) -> Self { - let doc = variant.docs(db); + pub(crate) fn from_enum_variant( + db: &db::RootDatabase, + variant: hir::EnumVariant, + ) -> Option { + let node: ast::EnumVariant = variant.source(db).ast; + match node.kind() { + ast::StructKind::Named(_) | ast::StructKind::Unit => return None, + _ => (), + }; let parent_name = match variant.parent_enum(db).name(db) { Some(name) => name.to_string(), @@ -99,17 +109,19 @@ impl FunctionSignature { }) .collect(); - FunctionSignature { - kind: SigKind::EnumVariant, - visibility: None, - name: Some(name), - ret_type: None, - parameters: params, - generic_parameters: vec![], - where_predicates: vec![], - doc: None, - } - .with_doc_opt(doc) + Some( + FunctionSignature { + kind: SigKind::EnumVariant, + visibility: None, + name: Some(name), + ret_type: None, + parameters: params, + generic_parameters: vec![], + where_predicates: vec![], + doc: None, + } + .with_doc_opt(variant.docs(db)), + ) } } -- cgit v1.2.3 From b915bf2d05e3edf7e23e595b2b95bdcdaa0907fd Mon Sep 17 00:00:00 2001 From: kjeremy Date: Tue, 29 Oct 2019 09:46:55 -0400 Subject: SigKind -> CallableKind --- crates/ra_ide_api/src/display/function_signature.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 736b5d3db..e21f8378d 100644 --- a/crates/ra_ide_api/src/display/function_signature.rs +++ b/crates/ra_ide_api/src/display/function_signature.rs @@ -13,16 +13,16 @@ use crate::{ }; #[derive(Debug)] -pub enum SigKind { +pub enum CallableKind { Function, - Struct, - EnumVariant, + StructConstructor, + VariantConstructor, } /// Contains information about a function signature #[derive(Debug)] pub struct FunctionSignature { - pub kind: SigKind, + pub kind: CallableKind, /// Optional visibility pub visibility: Option, /// Name of the function @@ -69,7 +69,7 @@ impl FunctionSignature { Some( FunctionSignature { - kind: SigKind::Struct, + kind: CallableKind::StructConstructor, visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node.name().map(|n| n.text().to_string()), @@ -111,7 +111,7 @@ impl FunctionSignature { Some( FunctionSignature { - kind: SigKind::EnumVariant, + kind: CallableKind::VariantConstructor, visibility: None, name: Some(name), ret_type: None, @@ -140,7 +140,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature { } FunctionSignature { - kind: SigKind::Function, + kind: CallableKind::Function, visibility: node.visibility().map(|n| n.syntax().text().to_string()), name: node.name().map(|n| n.text().to_string()), ret_type: node @@ -164,9 +164,9 @@ impl Display for FunctionSignature { if let Some(name) = &self.name { match self.kind { - SigKind::Function => write!(f, "fn {}", name)?, - SigKind::Struct => write!(f, "struct {}", name)?, - SigKind::EnumVariant => write!(f, "{}", name)?, + CallableKind::Function => write!(f, "fn {}", name)?, + CallableKind::StructConstructor => write!(f, "struct {}", name)?, + CallableKind::VariantConstructor => write!(f, "{}", name)?, } } -- cgit v1.2.3