4210: Include function qualifiers in signature r=matklad a=oxalica

Fixes #2450

It seems there's no test for `ra_ide/display/{short_label,function_signature}`. I'm not sure how to setup it.

Manually tested:
<img width="428" alt="Screenshot_20200430_004434" src="https://user-images.githubusercontent.com/14816024/80622769-d6f1c200-8a7b-11ea-91f3-e94bfb2703c5.png">


Co-authored-by: oxalica <oxalicc@pm.me>
This commit is contained in:
bors[bot] 2020-04-30 11:09:57 +00:00 committed by GitHub
commit fdaddb98b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 0 deletions

View file

@ -26,6 +26,8 @@ pub struct FunctionSignature {
pub kind: CallableKind, pub kind: CallableKind,
/// Optional visibility /// Optional visibility
pub visibility: Option<String>, pub visibility: Option<String>,
/// Qualifiers like `async`, `unsafe`, ...
pub qualifier: FunctionQualifier,
/// Name of the function /// Name of the function
pub name: Option<String>, pub name: Option<String>,
/// Documentation for the function /// Documentation for the function
@ -46,6 +48,16 @@ pub struct FunctionSignature {
pub has_self_param: bool, 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 { impl FunctionSignature {
pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self { pub(crate) fn with_doc_opt(mut self, doc: Option<Documentation>) -> Self {
self.doc = doc; self.doc = doc;
@ -83,6 +95,8 @@ impl FunctionSignature {
FunctionSignature { FunctionSignature {
kind: CallableKind::StructConstructor, kind: CallableKind::StructConstructor,
visibility: node.visibility().map(|n| n.syntax().text().to_string()), 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()), name: node.name().map(|n| n.text().to_string()),
ret_type: node.name().map(|n| n.text().to_string()), ret_type: node.name().map(|n| n.text().to_string()),
parameters: params, parameters: params,
@ -128,6 +142,8 @@ impl FunctionSignature {
FunctionSignature { FunctionSignature {
kind: CallableKind::VariantConstructor, kind: CallableKind::VariantConstructor,
visibility: None, visibility: None,
// Do we need `const`?
qualifier: Default::default(),
name: Some(name), name: Some(name),
ret_type: None, ret_type: None,
parameters: params, parameters: params,
@ -151,6 +167,7 @@ impl FunctionSignature {
FunctionSignature { FunctionSignature {
kind: CallableKind::Macro, kind: CallableKind::Macro,
visibility: None, visibility: None,
qualifier: Default::default(),
name: node.name().map(|n| n.text().to_string()), name: node.name().map(|n| n.text().to_string()),
ret_type: None, ret_type: None,
parameters: params, parameters: params,
@ -223,6 +240,12 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
FunctionSignature { FunctionSignature {
kind: CallableKind::Function, kind: CallableKind::Function,
visibility: node.visibility().map(|n| n.syntax().text().to_string()), 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()), name: node.name().map(|n| n.text().to_string()),
ret_type: node ret_type: node
.ret_type() .ret_type()
@ -246,6 +269,23 @@ impl Display for FunctionSignature {
write!(f, "{} ", t)?; 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 { if let Some(name) = &self.name {
match self.kind { match self.kind {
CallableKind::Function => write!(f, "fn {}", name)?, CallableKind::Function => write!(f, "fn {}", name)?,

View file

@ -844,4 +844,29 @@ fn func(foo: i32) { if true { <|>foo; }; }
&["fn foo()\n```\n\n<- `\u{3000}` here"], &["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()"#],
);
}
} }