From 414d8d9c3884cd4144b9dab7eb4a0d72b8f3a496 Mon Sep 17 00:00:00 2001
From: oxalica <oxalicc@pm.me>
Date: Thu, 30 Apr 2020 00:34:46 +0800
Subject: Include function qualifiers in signature

---
 crates/ra_ide/src/display/function_signature.rs | 40 +++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs
index b5e2785fe..db3907fe6 100644
--- a/crates/ra_ide/src/display/function_signature.rs
+++ b/crates/ra_ide/src/display/function_signature.rs
@@ -26,6 +26,8 @@ pub struct FunctionSignature {
     pub kind: CallableKind,
     /// Optional visibility
     pub visibility: Option<String>,
+    /// Qualifiers like `async`, `unsafe`, ...
+    pub qualifier: FunctionQualifier,
     /// Name of the function
     pub name: Option<String>,
     /// Documentation for the function
@@ -46,6 +48,16 @@ pub struct FunctionSignature {
     pub has_self_param: bool,
 }
 
+#[derive(Debug, Default)]
+pub struct FunctionQualifier {
+    // `async` and `const` are mutually exclusive. Do we need to enforcing it here?
+    pub is_async: bool,
+    pub is_const: bool,
+    pub is_unsafe: bool,
+    /// The string `extern ".."`
+    pub extern_abi: Option<String>,
+}
+
 impl FunctionSignature {
     pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
         self.doc = doc;
@@ -83,6 +95,8 @@ impl FunctionSignature {
             FunctionSignature {
                 kind: CallableKind::StructConstructor,
                 visibility: node.visibility().map(|n| n.syntax().text().to_string()),
+                // Do we need `const`?
+                qualifier: Default::default(),
                 name: node.name().map(|n| n.text().to_string()),
                 ret_type: node.name().map(|n| n.text().to_string()),
                 parameters: params,
@@ -128,6 +142,8 @@ impl FunctionSignature {
             FunctionSignature {
                 kind: CallableKind::VariantConstructor,
                 visibility: None,
+                // Do we need `const`?
+                qualifier: Default::default(),
                 name: Some(name),
                 ret_type: None,
                 parameters: params,
@@ -151,6 +167,7 @@ impl FunctionSignature {
             FunctionSignature {
                 kind: CallableKind::Macro,
                 visibility: None,
+                qualifier: Default::default(),
                 name: node.name().map(|n| n.text().to_string()),
                 ret_type: None,
                 parameters: params,
@@ -223,6 +240,12 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
         FunctionSignature {
             kind: CallableKind::Function,
             visibility: node.visibility().map(|n| n.syntax().text().to_string()),
+            qualifier: FunctionQualifier {
+                is_async: node.async_token().is_some(),
+                is_const: node.const_token().is_some(),
+                is_unsafe: node.unsafe_token().is_some(),
+                extern_abi: node.abi().map(|n| n.to_string()),
+            },
             name: node.name().map(|n| n.text().to_string()),
             ret_type: node
                 .ret_type()
@@ -246,6 +269,23 @@ impl Display for FunctionSignature {
             write!(f, "{} ", t)?;
         }
 
+        if self.qualifier.is_async {
+            write!(f, "async ")?;
+        }
+
+        if self.qualifier.is_const {
+            write!(f, "const ")?;
+        }
+
+        if self.qualifier.is_unsafe {
+            write!(f, "unsafe ")?;
+        }
+
+        if let Some(extern_abi) = &self.qualifier.extern_abi {
+            // Keyword `extern` is included in the string.
+            write!(f, "{} ", extern_abi)?;
+        }
+
         if let Some(name) = &self.name {
             match self.kind {
                 CallableKind::Function => write!(f, "fn {}", name)?,
-- 
cgit v1.2.3


From b9b342ff93ad3da659934ccb6dd3c15b6c2e9115 Mon Sep 17 00:00:00 2001
From: oxalica <oxalicc@pm.me>
Date: Thu, 30 Apr 2020 12:54:12 +0800
Subject: Add tests of showing function qualifiers

---
 crates/ra_ide/src/hover.rs | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 58c799eca..a62f598f0 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -844,4 +844,29 @@ fn func(foo: i32) { if true { <|>foo; }; }
             &["fn foo()\n```\n\n<- `\u{3000}` here"],
         );
     }
+
+    #[test]
+    fn test_hover_function_show_qualifiers() {
+        check_hover_result(
+            "
+            //- /lib.rs
+            async fn foo<|>() {}
+            ",
+            &["async fn foo()"],
+        );
+        check_hover_result(
+            "
+            //- /lib.rs
+            pub const unsafe fn foo<|>() {}
+            ",
+            &["pub const unsafe fn foo()"],
+        );
+        check_hover_result(
+            r#"
+            //- /lib.rs
+            pub(crate) async unsafe extern "C" fn foo<|>() {}
+            "#,
+            &[r#"pub(crate) async unsafe extern "C" fn foo()"#],
+        );
+    }
 }
-- 
cgit v1.2.3