diff options
-rw-r--r-- | Cargo.lock | 18 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/add_import.rs | 12 | ||||
-rw-r--r-- | crates/ra_ide_api/src/call_info.rs | 142 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display/function_signature.rs | 112 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 19 |
5 files changed, 277 insertions, 26 deletions
diff --git a/Cargo.lock b/Cargo.lock index 18d2fb9d5..c7ec98226 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -455,7 +455,7 @@ name = "heck" | |||
455 | version = "0.3.1" | 455 | version = "0.3.1" |
456 | source = "registry+https://github.com/rust-lang/crates.io-index" | 456 | source = "registry+https://github.com/rust-lang/crates.io-index" |
457 | dependencies = [ | 457 | dependencies = [ |
458 | "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | 458 | "unicode-segmentation 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
459 | ] | 459 | ] |
460 | 460 | ||
461 | [[package]] | 461 | [[package]] |
@@ -802,7 +802,7 @@ dependencies = [ | |||
802 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", | 802 | "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", |
803 | "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", | 803 | "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", |
804 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", | 804 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", |
805 | "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", | 805 | "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", |
806 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", | 806 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", |
807 | ] | 807 | ] |
808 | 808 | ||
@@ -1091,7 +1091,7 @@ dependencies = [ | |||
1091 | "ra_syntax 0.1.0", | 1091 | "ra_syntax 0.1.0", |
1092 | "ra_tt 0.1.0", | 1092 | "ra_tt 0.1.0", |
1093 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1093 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1094 | "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", | 1094 | "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", |
1095 | "test_utils 0.1.0", | 1095 | "test_utils 0.1.0", |
1096 | ] | 1096 | ] |
1097 | 1097 | ||
@@ -1456,7 +1456,7 @@ dependencies = [ | |||
1456 | "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", | 1456 | "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", |
1457 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1457 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1458 | "salsa-macros 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", | 1458 | "salsa-macros 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", |
1459 | "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", | 1459 | "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", |
1460 | ] | 1460 | ] |
1461 | 1461 | ||
1462 | [[package]] | 1462 | [[package]] |
@@ -1553,7 +1553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
1553 | 1553 | ||
1554 | [[package]] | 1554 | [[package]] |
1555 | name = "smallvec" | 1555 | name = "smallvec" |
1556 | version = "0.6.10" | 1556 | version = "0.6.11" |
1557 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1558 | 1558 | ||
1559 | [[package]] | 1559 | [[package]] |
@@ -1673,12 +1673,12 @@ name = "unicode-normalization" | |||
1673 | version = "0.1.8" | 1673 | version = "0.1.8" |
1674 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1674 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1675 | dependencies = [ | 1675 | dependencies = [ |
1676 | "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", | 1676 | "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", |
1677 | ] | 1677 | ] |
1678 | 1678 | ||
1679 | [[package]] | 1679 | [[package]] |
1680 | name = "unicode-segmentation" | 1680 | name = "unicode-segmentation" |
1681 | version = "1.3.0" | 1681 | version = "1.4.0" |
1682 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1682 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1683 | 1683 | ||
1684 | [[package]] | 1684 | [[package]] |
@@ -1955,7 +1955,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
1955 | "checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" | 1955 | "checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" |
1956 | "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" | 1956 | "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" |
1957 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | 1957 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" |
1958 | "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" | 1958 | "checksum smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cefaa50e76a6f10b86f36e640eb1739eafbd4084865067778463913e43a77ff3" |
1959 | "checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" | 1959 | "checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" |
1960 | "checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a" | 1960 | "checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a" |
1961 | "checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" | 1961 | "checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" |
@@ -1969,7 +1969,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
1969 | "checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" | 1969 | "checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" |
1970 | "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" | 1970 | "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" |
1971 | "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" | 1971 | "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" |
1972 | "checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" | 1972 | "checksum unicode-segmentation 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc5415c074426c7c65db13bd647c23d78c0fb2e10dca0b8fb0f40058a59bccdf" |
1973 | "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" | 1973 | "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" |
1974 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" | 1974 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" |
1975 | "checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" | 1975 | "checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" |
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs index c8b9809f4..363ade016 100644 --- a/crates/ra_assists/src/assists/add_import.rs +++ b/crates/ra_assists/src/assists/add_import.rs | |||
@@ -545,7 +545,7 @@ fn make_assist_add_nested_import( | |||
545 | if add_colon_colon { | 545 | if add_colon_colon { |
546 | buf.push_str("::"); | 546 | buf.push_str("::"); |
547 | } | 547 | } |
548 | buf.push_str("{ "); | 548 | buf.push_str("{"); |
549 | if add_self { | 549 | if add_self { |
550 | buf.push_str("self, "); | 550 | buf.push_str("self, "); |
551 | } | 551 | } |
@@ -734,7 +734,7 @@ impl std::io<|> for Foo { | |||
734 | } | 734 | } |
735 | ", | 735 | ", |
736 | " | 736 | " |
737 | use std::{ io, fmt}; | 737 | use std::{io, fmt}; |
738 | 738 | ||
739 | impl io<|> for Foo { | 739 | impl io<|> for Foo { |
740 | } | 740 | } |
@@ -753,7 +753,7 @@ impl std::fmt::Debug<|> for Foo { | |||
753 | } | 753 | } |
754 | ", | 754 | ", |
755 | " | 755 | " |
756 | use std::fmt::{ self, Debug, }; | 756 | use std::fmt::{self, Debug, }; |
757 | 757 | ||
758 | impl Debug<|> for Foo { | 758 | impl Debug<|> for Foo { |
759 | } | 759 | } |
@@ -772,7 +772,7 @@ impl std::fmt<|> for Foo { | |||
772 | } | 772 | } |
773 | ", | 773 | ", |
774 | " | 774 | " |
775 | use std::fmt::{ self, Debug}; | 775 | use std::fmt::{self, Debug}; |
776 | 776 | ||
777 | impl fmt<|> for Foo { | 777 | impl fmt<|> for Foo { |
778 | } | 778 | } |
@@ -848,7 +848,7 @@ impl std::fmt::nested::Display<|> for Foo { | |||
848 | } | 848 | } |
849 | ", | 849 | ", |
850 | " | 850 | " |
851 | use std::fmt::{ nested::Display, Debug}; | 851 | use std::fmt::{nested::Display, Debug}; |
852 | 852 | ||
853 | impl Display<|> for Foo { | 853 | impl Display<|> for Foo { |
854 | } | 854 | } |
@@ -867,7 +867,7 @@ impl std::fmt::Display<|> for Foo { | |||
867 | } | 867 | } |
868 | ", | 868 | ", |
869 | " | 869 | " |
870 | use std::fmt::{ Display, nested::Debug}; | 870 | use std::fmt::{Display, nested::Debug}; |
871 | 871 | ||
872 | impl Display<|> for Foo { | 872 | impl Display<|> for Foo { |
873 | } | 873 | } |
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs index c95133343..175af3fd9 100644 --- a/crates/ra_ide_api/src/call_info.rs +++ b/crates/ra_ide_api/src/call_info.rs | |||
@@ -20,24 +20,30 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal | |||
20 | let name_ref = calling_node.name_ref()?; | 20 | let name_ref = calling_node.name_ref()?; |
21 | 21 | ||
22 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); | 22 | let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); |
23 | let function = match &calling_node { | 23 | let (mut call_info, has_self) = match &calling_node { |
24 | FnCallNode::CallExpr(expr) => { | 24 | FnCallNode::CallExpr(expr) => { |
25 | //FIXME: apply subst | 25 | //FIXME: apply subst |
26 | let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; | 26 | let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; |
27 | match callable_def { | 27 | match callable_def { |
28 | hir::CallableDef::Function(it) => it, | 28 | hir::CallableDef::Function(it) => { |
29 | //FIXME: handle other callables | 29 | (CallInfo::with_fn(db, it), it.data(db).has_self_param()) |
30 | _ => return None, | 30 | } |
31 | hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it)?, false), | ||
32 | hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it)?, false), | ||
31 | } | 33 | } |
32 | } | 34 | } |
33 | FnCallNode::MethodCallExpr(expr) => analyzer.resolve_method_call(&expr)?, | 35 | FnCallNode::MethodCallExpr(expr) => { |
36 | let function = analyzer.resolve_method_call(&expr)?; | ||
37 | (CallInfo::with_fn(db, function), function.data(db).has_self_param()) | ||
38 | } | ||
39 | FnCallNode::MacroCallExpr(expr) => { | ||
40 | let macro_def = analyzer.resolve_macro_call(db, &expr)?; | ||
41 | (CallInfo::with_macro(db, macro_def)?, false) | ||
42 | } | ||
34 | }; | 43 | }; |
35 | 44 | ||
36 | let mut call_info = CallInfo::new(db, function); | ||
37 | |||
38 | // If we have a calling expression let's find which argument we are on | 45 | // If we have a calling expression let's find which argument we are on |
39 | let num_params = call_info.parameters().len(); | 46 | let num_params = call_info.parameters().len(); |
40 | let has_self = function.data(db).has_self_param(); | ||
41 | 47 | ||
42 | if num_params == 1 { | 48 | if num_params == 1 { |
43 | if !has_self { | 49 | if !has_self { |
@@ -75,9 +81,11 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal | |||
75 | Some(call_info) | 81 | Some(call_info) |
76 | } | 82 | } |
77 | 83 | ||
84 | #[derive(Debug)] | ||
78 | enum FnCallNode { | 85 | enum FnCallNode { |
79 | CallExpr(ast::CallExpr), | 86 | CallExpr(ast::CallExpr), |
80 | MethodCallExpr(ast::MethodCallExpr), | 87 | MethodCallExpr(ast::MethodCallExpr), |
88 | MacroCallExpr(ast::MacroCall), | ||
81 | } | 89 | } |
82 | 90 | ||
83 | impl FnCallNode { | 91 | impl FnCallNode { |
@@ -87,6 +95,8 @@ impl FnCallNode { | |||
87 | Some(FnCallNode::CallExpr(expr)) | 95 | Some(FnCallNode::CallExpr(expr)) |
88 | } else if let Some(expr) = ast::MethodCallExpr::cast(node.clone()) { | 96 | } else if let Some(expr) = ast::MethodCallExpr::cast(node.clone()) { |
89 | Some(FnCallNode::MethodCallExpr(expr)) | 97 | Some(FnCallNode::MethodCallExpr(expr)) |
98 | } else if let Some(expr) = ast::MacroCall::cast(node.clone()) { | ||
99 | Some(FnCallNode::MacroCallExpr(expr)) | ||
90 | } else { | 100 | } else { |
91 | None | 101 | None |
92 | } | 102 | } |
@@ -103,6 +113,8 @@ impl FnCallNode { | |||
103 | FnCallNode::MethodCallExpr(call_expr) => { | 113 | FnCallNode::MethodCallExpr(call_expr) => { |
104 | call_expr.syntax().children().filter_map(ast::NameRef::cast).nth(0) | 114 | call_expr.syntax().children().filter_map(ast::NameRef::cast).nth(0) |
105 | } | 115 | } |
116 | |||
117 | FnCallNode::MacroCallExpr(call_expr) => call_expr.path()?.segment()?.name_ref(), | ||
106 | } | 118 | } |
107 | } | 119 | } |
108 | 120 | ||
@@ -110,17 +122,36 @@ impl FnCallNode { | |||
110 | match self { | 122 | match self { |
111 | FnCallNode::CallExpr(expr) => expr.arg_list(), | 123 | FnCallNode::CallExpr(expr) => expr.arg_list(), |
112 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), | 124 | FnCallNode::MethodCallExpr(expr) => expr.arg_list(), |
125 | FnCallNode::MacroCallExpr(_) => None, | ||
113 | } | 126 | } |
114 | } | 127 | } |
115 | } | 128 | } |
116 | 129 | ||
117 | impl CallInfo { | 130 | impl CallInfo { |
118 | fn new(db: &RootDatabase, function: hir::Function) -> Self { | 131 | fn with_fn(db: &RootDatabase, function: hir::Function) -> Self { |
119 | let signature = FunctionSignature::from_hir(db, function); | 132 | let signature = FunctionSignature::from_hir(db, function); |
120 | 133 | ||
121 | CallInfo { signature, active_parameter: None } | 134 | CallInfo { signature, active_parameter: None } |
122 | } | 135 | } |
123 | 136 | ||
137 | fn with_struct(db: &RootDatabase, st: hir::Struct) -> Option<Self> { | ||
138 | let signature = FunctionSignature::from_struct(db, st)?; | ||
139 | |||
140 | Some(CallInfo { signature, active_parameter: None }) | ||
141 | } | ||
142 | |||
143 | fn with_enum_variant(db: &RootDatabase, variant: hir::EnumVariant) -> Option<Self> { | ||
144 | let signature = FunctionSignature::from_enum_variant(db, variant)?; | ||
145 | |||
146 | Some(CallInfo { signature, active_parameter: None }) | ||
147 | } | ||
148 | |||
149 | fn with_macro(db: &RootDatabase, macro_def: hir::MacroDef) -> Option<Self> { | ||
150 | let signature = FunctionSignature::from_macro(db, macro_def)?; | ||
151 | |||
152 | Some(CallInfo { signature, active_parameter: None }) | ||
153 | } | ||
154 | |||
124 | fn parameters(&self) -> &[String] { | 155 | fn parameters(&self) -> &[String] { |
125 | &self.signature.parameters | 156 | &self.signature.parameters |
126 | } | 157 | } |
@@ -417,6 +448,7 @@ pub fn foo(mut r: WriteHandler<()>) { | |||
417 | "#, | 448 | "#, |
418 | ); | 449 | ); |
419 | 450 | ||
451 | assert_eq!(info.label(), "fn finished(&mut self, ctx: &mut Self::Context)".to_string()); | ||
420 | assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]); | 452 | assert_eq!(info.parameters(), ["&mut self", "ctx: &mut Self::Context"]); |
421 | assert_eq!(info.active_parameter, Some(1)); | 453 | assert_eq!(info.active_parameter, Some(1)); |
422 | assert_eq!( | 454 | assert_eq!( |
@@ -462,4 +494,96 @@ fn main() { | |||
462 | assert_eq!(info.active_parameter, Some(1)); | 494 | assert_eq!(info.active_parameter, Some(1)); |
463 | assert_eq!(info.label(), "fn bar(&self, _: u32)"); | 495 | assert_eq!(info.label(), "fn bar(&self, _: u32)"); |
464 | } | 496 | } |
497 | |||
498 | #[test] | ||
499 | fn works_for_tuple_structs() { | ||
500 | let info = call_info( | ||
501 | r#" | ||
502 | /// A cool tuple struct | ||
503 | struct TS(u32, i32); | ||
504 | fn main() { | ||
505 | let s = TS(0, <|>); | ||
506 | }"#, | ||
507 | ); | ||
508 | |||
509 | assert_eq!(info.label(), "struct TS(u32, i32) -> TS"); | ||
510 | assert_eq!(info.doc().map(|it| it.into()), Some("A cool tuple struct".to_string())); | ||
511 | assert_eq!(info.active_parameter, Some(1)); | ||
512 | } | ||
513 | |||
514 | #[test] | ||
515 | #[should_panic] | ||
516 | fn cant_call_named_structs() { | ||
517 | let _ = call_info( | ||
518 | r#" | ||
519 | struct TS { x: u32, y: i32 } | ||
520 | fn main() { | ||
521 | let s = TS(<|>); | ||
522 | }"#, | ||
523 | ); | ||
524 | } | ||
525 | |||
526 | #[test] | ||
527 | fn works_for_enum_variants() { | ||
528 | let info = call_info( | ||
529 | r#" | ||
530 | enum E { | ||
531 | /// A Variant | ||
532 | A(i32), | ||
533 | /// Another | ||
534 | B, | ||
535 | /// And C | ||
536 | C { a: i32, b: i32 } | ||
537 | } | ||
538 | |||
539 | fn main() { | ||
540 | let a = E::A(<|>); | ||
541 | } | ||
542 | "#, | ||
543 | ); | ||
544 | |||
545 | assert_eq!(info.label(), "E::A(0: i32)"); | ||
546 | assert_eq!(info.doc().map(|it| it.into()), Some("A Variant".to_string())); | ||
547 | assert_eq!(info.active_parameter, Some(0)); | ||
548 | } | ||
549 | |||
550 | #[test] | ||
551 | #[should_panic] | ||
552 | fn cant_call_enum_records() { | ||
553 | let _ = call_info( | ||
554 | r#" | ||
555 | enum E { | ||
556 | /// A Variant | ||
557 | A(i32), | ||
558 | /// Another | ||
559 | B, | ||
560 | /// And C | ||
561 | C { a: i32, b: i32 } | ||
562 | } | ||
563 | |||
564 | fn main() { | ||
565 | let a = E::C(<|>); | ||
566 | } | ||
567 | "#, | ||
568 | ); | ||
569 | } | ||
570 | |||
571 | #[test] | ||
572 | fn fn_signature_for_macro() { | ||
573 | let info = call_info( | ||
574 | r#" | ||
575 | /// empty macro | ||
576 | macro_rules! foo { | ||
577 | () => {} | ||
578 | } | ||
579 | |||
580 | fn f() { | ||
581 | foo!(<|>); | ||
582 | } | ||
583 | "#, | ||
584 | ); | ||
585 | |||
586 | assert_eq!(info.label(), "foo!()"); | ||
587 | assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); | ||
588 | } | ||
465 | } | 589 | } |
diff --git a/crates/ra_ide_api/src/display/function_signature.rs b/crates/ra_ide_api/src/display/function_signature.rs index 43f022ccd..9075ca443 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 @@ | |||
2 | 2 | ||
3 | use std::fmt::{self, Display}; | 3 | use std::fmt::{self, Display}; |
4 | 4 | ||
5 | use hir::{Docs, Documentation, HasSource}; | 5 | use hir::{Docs, Documentation, HasSource, HirDisplay}; |
6 | use join_to_string::join; | 6 | use join_to_string::join; |
7 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; | 7 | use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner}; |
8 | use std::convert::From; | 8 | use std::convert::From; |
@@ -12,9 +12,18 @@ use crate::{ | |||
12 | display::{generic_parameters, where_predicates}, | 12 | display::{generic_parameters, where_predicates}, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | #[derive(Debug)] | ||
16 | pub enum CallableKind { | ||
17 | Function, | ||
18 | StructConstructor, | ||
19 | VariantConstructor, | ||
20 | Macro, | ||
21 | } | ||
22 | |||
15 | /// Contains information about a function signature | 23 | /// Contains information about a function signature |
16 | #[derive(Debug)] | 24 | #[derive(Debug)] |
17 | pub struct FunctionSignature { | 25 | pub struct FunctionSignature { |
26 | pub kind: CallableKind, | ||
18 | /// Optional visibility | 27 | /// Optional visibility |
19 | pub visibility: Option<String>, | 28 | pub visibility: Option<String>, |
20 | /// Name of the function | 29 | /// Name of the function |
@@ -42,6 +51,99 @@ impl FunctionSignature { | |||
42 | let ast_node = function.source(db).ast; | 51 | let ast_node = function.source(db).ast; |
43 | FunctionSignature::from(&ast_node).with_doc_opt(doc) | 52 | FunctionSignature::from(&ast_node).with_doc_opt(doc) |
44 | } | 53 | } |
54 | |||
55 | pub(crate) fn from_struct(db: &db::RootDatabase, st: hir::Struct) -> Option<Self> { | ||
56 | let node: ast::StructDef = st.source(db).ast; | ||
57 | match node.kind() { | ||
58 | ast::StructKind::Named(_) => 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).ast; | ||
91 | match node.kind() { | ||
92 | ast::StructKind::Named(_) | 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).ast; | ||
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 | } | ||
45 | } | 147 | } |
46 | 148 | ||
47 | impl From<&'_ ast::FnDef> for FunctionSignature { | 149 | impl From<&'_ ast::FnDef> for FunctionSignature { |
@@ -59,6 +161,7 @@ impl From<&'_ ast::FnDef> for FunctionSignature { | |||
59 | } | 161 | } |
60 | 162 | ||
61 | FunctionSignature { | 163 | FunctionSignature { |
164 | kind: CallableKind::Function, | ||
62 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), | 165 | visibility: node.visibility().map(|n| n.syntax().text().to_string()), |
63 | name: node.name().map(|n| n.text().to_string()), | 166 | name: node.name().map(|n| n.text().to_string()), |
64 | ret_type: node | 167 | ret_type: node |
@@ -81,7 +184,12 @@ impl Display for FunctionSignature { | |||
81 | } | 184 | } |
82 | 185 | ||
83 | if let Some(name) = &self.name { | 186 | if let Some(name) = &self.name { |
84 | write!(f, "fn {}", 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 | } | ||
85 | } | 193 | } |
86 | 194 | ||
87 | if !self.generic_parameters.is_empty() { | 195 | if !self.generic_parameters.is_empty() { |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 16fb07266..20f9aee13 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -27,6 +27,7 @@ use crate::{ | |||
27 | }; | 27 | }; |
28 | 28 | ||
29 | pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result<String> { | 29 | pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result<String> { |
30 | let _p = profile("handle_analyzer_status"); | ||
30 | let mut buf = world.status(); | 31 | let mut buf = world.status(); |
31 | writeln!(buf, "\n\nrequests:").unwrap(); | 32 | writeln!(buf, "\n\nrequests:").unwrap(); |
32 | let requests = world.latest_requests.read(); | 33 | let requests = world.latest_requests.read(); |
@@ -38,6 +39,7 @@ pub fn handle_analyzer_status(world: WorldSnapshot, _: ()) -> Result<String> { | |||
38 | } | 39 | } |
39 | 40 | ||
40 | pub fn handle_syntax_tree(world: WorldSnapshot, params: req::SyntaxTreeParams) -> Result<String> { | 41 | pub fn handle_syntax_tree(world: WorldSnapshot, params: req::SyntaxTreeParams) -> Result<String> { |
42 | let _p = profile("handle_syntax_tree"); | ||
41 | let id = params.text_document.try_conv_with(&world)?; | 43 | let id = params.text_document.try_conv_with(&world)?; |
42 | let line_index = world.analysis().file_line_index(id)?; | 44 | let line_index = world.analysis().file_line_index(id)?; |
43 | let text_range = params.range.map(|p| p.conv_with(&line_index)); | 45 | let text_range = params.range.map(|p| p.conv_with(&line_index)); |
@@ -172,6 +174,7 @@ pub fn handle_document_symbol( | |||
172 | world: WorldSnapshot, | 174 | world: WorldSnapshot, |
173 | params: req::DocumentSymbolParams, | 175 | params: req::DocumentSymbolParams, |
174 | ) -> Result<Option<req::DocumentSymbolResponse>> { | 176 | ) -> Result<Option<req::DocumentSymbolResponse>> { |
177 | let _p = profile("handle_document_symbol"); | ||
175 | let file_id = params.text_document.try_conv_with(&world)?; | 178 | let file_id = params.text_document.try_conv_with(&world)?; |
176 | let line_index = world.analysis().file_line_index(file_id)?; | 179 | let line_index = world.analysis().file_line_index(file_id)?; |
177 | 180 | ||
@@ -210,6 +213,7 @@ pub fn handle_workspace_symbol( | |||
210 | world: WorldSnapshot, | 213 | world: WorldSnapshot, |
211 | params: req::WorkspaceSymbolParams, | 214 | params: req::WorkspaceSymbolParams, |
212 | ) -> Result<Option<Vec<SymbolInformation>>> { | 215 | ) -> Result<Option<Vec<SymbolInformation>>> { |
216 | let _p = profile("handle_workspace_symbol"); | ||
213 | let all_symbols = params.query.contains('#'); | 217 | let all_symbols = params.query.contains('#'); |
214 | let libs = params.query.contains('*'); | 218 | let libs = params.query.contains('*'); |
215 | let query = { | 219 | let query = { |
@@ -253,6 +257,7 @@ pub fn handle_goto_definition( | |||
253 | world: WorldSnapshot, | 257 | world: WorldSnapshot, |
254 | params: req::TextDocumentPositionParams, | 258 | params: req::TextDocumentPositionParams, |
255 | ) -> Result<Option<req::GotoDefinitionResponse>> { | 259 | ) -> Result<Option<req::GotoDefinitionResponse>> { |
260 | let _p = profile("handle_goto_definition"); | ||
256 | let position = params.try_conv_with(&world)?; | 261 | let position = params.try_conv_with(&world)?; |
257 | let nav_info = match world.analysis().goto_definition(position)? { | 262 | let nav_info = match world.analysis().goto_definition(position)? { |
258 | None => return Ok(None), | 263 | None => return Ok(None), |
@@ -266,6 +271,7 @@ pub fn handle_goto_implementation( | |||
266 | world: WorldSnapshot, | 271 | world: WorldSnapshot, |
267 | params: req::TextDocumentPositionParams, | 272 | params: req::TextDocumentPositionParams, |
268 | ) -> Result<Option<req::GotoImplementationResponse>> { | 273 | ) -> Result<Option<req::GotoImplementationResponse>> { |
274 | let _p = profile("handle_goto_implementation"); | ||
269 | let position = params.try_conv_with(&world)?; | 275 | let position = params.try_conv_with(&world)?; |
270 | let nav_info = match world.analysis().goto_implementation(position)? { | 276 | let nav_info = match world.analysis().goto_implementation(position)? { |
271 | None => return Ok(None), | 277 | None => return Ok(None), |
@@ -279,6 +285,7 @@ pub fn handle_goto_type_definition( | |||
279 | world: WorldSnapshot, | 285 | world: WorldSnapshot, |
280 | params: req::TextDocumentPositionParams, | 286 | params: req::TextDocumentPositionParams, |
281 | ) -> Result<Option<req::GotoTypeDefinitionResponse>> { | 287 | ) -> Result<Option<req::GotoTypeDefinitionResponse>> { |
288 | let _p = profile("handle_goto_type_definition"); | ||
282 | let position = params.try_conv_with(&world)?; | 289 | let position = params.try_conv_with(&world)?; |
283 | let nav_info = match world.analysis().goto_type_definition(position)? { | 290 | let nav_info = match world.analysis().goto_type_definition(position)? { |
284 | None => return Ok(None), | 291 | None => return Ok(None), |
@@ -292,6 +299,7 @@ pub fn handle_parent_module( | |||
292 | world: WorldSnapshot, | 299 | world: WorldSnapshot, |
293 | params: req::TextDocumentPositionParams, | 300 | params: req::TextDocumentPositionParams, |
294 | ) -> Result<Vec<Location>> { | 301 | ) -> Result<Vec<Location>> { |
302 | let _p = profile("handle_parent_module"); | ||
295 | let position = params.try_conv_with(&world)?; | 303 | let position = params.try_conv_with(&world)?; |
296 | world.analysis().parent_module(position)?.iter().try_conv_with_to_vec(&world) | 304 | world.analysis().parent_module(position)?.iter().try_conv_with_to_vec(&world) |
297 | } | 305 | } |
@@ -300,6 +308,7 @@ pub fn handle_runnables( | |||
300 | world: WorldSnapshot, | 308 | world: WorldSnapshot, |
301 | params: req::RunnablesParams, | 309 | params: req::RunnablesParams, |
302 | ) -> Result<Vec<req::Runnable>> { | 310 | ) -> Result<Vec<req::Runnable>> { |
311 | let _p = profile("handle_runnables"); | ||
303 | let file_id = params.text_document.try_conv_with(&world)?; | 312 | let file_id = params.text_document.try_conv_with(&world)?; |
304 | let line_index = world.analysis().file_line_index(file_id)?; | 313 | let line_index = world.analysis().file_line_index(file_id)?; |
305 | let offset = params.position.map(|it| it.conv_with(&line_index)); | 314 | let offset = params.position.map(|it| it.conv_with(&line_index)); |
@@ -341,6 +350,7 @@ pub fn handle_decorations( | |||
341 | world: WorldSnapshot, | 350 | world: WorldSnapshot, |
342 | params: TextDocumentIdentifier, | 351 | params: TextDocumentIdentifier, |
343 | ) -> Result<Vec<Decoration>> { | 352 | ) -> Result<Vec<Decoration>> { |
353 | let _p = profile("handle_decorations"); | ||
344 | let file_id = params.try_conv_with(&world)?; | 354 | let file_id = params.try_conv_with(&world)?; |
345 | highlight(&world, file_id) | 355 | highlight(&world, file_id) |
346 | } | 356 | } |
@@ -389,6 +399,7 @@ pub fn handle_folding_range( | |||
389 | world: WorldSnapshot, | 399 | world: WorldSnapshot, |
390 | params: FoldingRangeParams, | 400 | params: FoldingRangeParams, |
391 | ) -> Result<Option<Vec<FoldingRange>>> { | 401 | ) -> Result<Option<Vec<FoldingRange>>> { |
402 | let _p = profile("handle_folding_range"); | ||
392 | let file_id = params.text_document.try_conv_with(&world)?; | 403 | let file_id = params.text_document.try_conv_with(&world)?; |
393 | let folds = world.analysis().folding_ranges(file_id)?; | 404 | let folds = world.analysis().folding_ranges(file_id)?; |
394 | let text = world.analysis().file_text(file_id)?; | 405 | let text = world.analysis().file_text(file_id)?; |
@@ -406,6 +417,7 @@ pub fn handle_signature_help( | |||
406 | world: WorldSnapshot, | 417 | world: WorldSnapshot, |
407 | params: req::TextDocumentPositionParams, | 418 | params: req::TextDocumentPositionParams, |
408 | ) -> Result<Option<req::SignatureHelp>> { | 419 | ) -> Result<Option<req::SignatureHelp>> { |
420 | let _p = profile("handle_signature_help"); | ||
409 | let position = params.try_conv_with(&world)?; | 421 | let position = params.try_conv_with(&world)?; |
410 | if let Some(call_info) = world.analysis().call_info(position)? { | 422 | if let Some(call_info) = world.analysis().call_info(position)? { |
411 | let active_parameter = call_info.active_parameter.map(|it| it as i64); | 423 | let active_parameter = call_info.active_parameter.map(|it| it as i64); |
@@ -425,6 +437,7 @@ pub fn handle_hover( | |||
425 | world: WorldSnapshot, | 437 | world: WorldSnapshot, |
426 | params: req::TextDocumentPositionParams, | 438 | params: req::TextDocumentPositionParams, |
427 | ) -> Result<Option<Hover>> { | 439 | ) -> Result<Option<Hover>> { |
440 | let _p = profile("handle_hover"); | ||
428 | let position = params.try_conv_with(&world)?; | 441 | let position = params.try_conv_with(&world)?; |
429 | let info = match world.analysis().hover(position)? { | 442 | let info = match world.analysis().hover(position)? { |
430 | None => return Ok(None), | 443 | None => return Ok(None), |
@@ -523,6 +536,7 @@ pub fn handle_formatting( | |||
523 | world: WorldSnapshot, | 536 | world: WorldSnapshot, |
524 | params: DocumentFormattingParams, | 537 | params: DocumentFormattingParams, |
525 | ) -> Result<Option<Vec<TextEdit>>> { | 538 | ) -> Result<Option<Vec<TextEdit>>> { |
539 | let _p = profile("handle_formatting"); | ||
526 | let file_id = params.text_document.try_conv_with(&world)?; | 540 | let file_id = params.text_document.try_conv_with(&world)?; |
527 | let file = world.analysis().file_text(file_id)?; | 541 | let file = world.analysis().file_text(file_id)?; |
528 | 542 | ||
@@ -645,6 +659,7 @@ pub fn handle_code_lens( | |||
645 | world: WorldSnapshot, | 659 | world: WorldSnapshot, |
646 | params: req::CodeLensParams, | 660 | params: req::CodeLensParams, |
647 | ) -> Result<Option<Vec<CodeLens>>> { | 661 | ) -> Result<Option<Vec<CodeLens>>> { |
662 | let _p = profile("handle_code_lens"); | ||
648 | let file_id = params.text_document.try_conv_with(&world)?; | 663 | let file_id = params.text_document.try_conv_with(&world)?; |
649 | let line_index = world.analysis().file_line_index(file_id)?; | 664 | let line_index = world.analysis().file_line_index(file_id)?; |
650 | 665 | ||
@@ -705,6 +720,7 @@ enum CodeLensResolveData { | |||
705 | } | 720 | } |
706 | 721 | ||
707 | pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { | 722 | pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { |
723 | let _p = profile("handle_code_lens_resolve"); | ||
708 | let data = code_lens.data.unwrap(); | 724 | let data = code_lens.data.unwrap(); |
709 | let resolve = serde_json::from_value(data)?; | 725 | let resolve = serde_json::from_value(data)?; |
710 | match resolve { | 726 | match resolve { |
@@ -776,6 +792,7 @@ pub fn publish_diagnostics( | |||
776 | world: &WorldSnapshot, | 792 | world: &WorldSnapshot, |
777 | file_id: FileId, | 793 | file_id: FileId, |
778 | ) -> Result<req::PublishDiagnosticsParams> { | 794 | ) -> Result<req::PublishDiagnosticsParams> { |
795 | let _p = profile("publish_diagnostics"); | ||
779 | let uri = world.file_id_to_uri(file_id)?; | 796 | let uri = world.file_id_to_uri(file_id)?; |
780 | let line_index = world.analysis().file_line_index(file_id)?; | 797 | let line_index = world.analysis().file_line_index(file_id)?; |
781 | let diagnostics = world | 798 | let diagnostics = world |
@@ -798,6 +815,7 @@ pub fn publish_decorations( | |||
798 | world: &WorldSnapshot, | 815 | world: &WorldSnapshot, |
799 | file_id: FileId, | 816 | file_id: FileId, |
800 | ) -> Result<req::PublishDecorationsParams> { | 817 | ) -> Result<req::PublishDecorationsParams> { |
818 | let _p = profile("publish_decorations"); | ||
801 | let uri = world.file_id_to_uri(file_id)?; | 819 | let uri = world.file_id_to_uri(file_id)?; |
802 | Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? }) | 820 | Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? }) |
803 | } | 821 | } |
@@ -847,6 +865,7 @@ pub fn handle_inlay_hints( | |||
847 | world: WorldSnapshot, | 865 | world: WorldSnapshot, |
848 | params: InlayHintsParams, | 866 | params: InlayHintsParams, |
849 | ) -> Result<Vec<InlayHint>> { | 867 | ) -> Result<Vec<InlayHint>> { |
868 | let _p = profile("handle_inlay_hints"); | ||
850 | let file_id = params.text_document.try_conv_with(&world)?; | 869 | let file_id = params.text_document.try_conv_with(&world)?; |
851 | let analysis = world.analysis(); | 870 | let analysis = world.analysis(); |
852 | let line_index = analysis.file_line_index(file_id)?; | 871 | let line_index = analysis.file_line_index(file_id)?; |