Skip to content

Commit ad9234f

Browse files
bors[bot]Veykril
andauthored
Merge #9140
9140: feat: Render documentation for derive completion r=Veykril a=Veykril ![eEzGiq2wNa](https://user-images.githubusercontent.com/3757771/120847308-9c5a3300-c573-11eb-958d-e0f22f4757ed.gif) Nothing fancy as all the std derives aren't really documented though maybe some 3rd party crates document them equally to their trait counterparts. Co-authored-by: Lukas Wirth <[email protected]>
2 parents 5092d8c + 544eca1 commit ad9234f

File tree

4 files changed

+75
-40
lines changed

4 files changed

+75
-40
lines changed

crates/hir_def/src/attr.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ use crate::{
3636
pub struct Documentation(String);
3737

3838
impl Documentation {
39+
pub fn new(s: impl Into<String>) -> Self {
40+
Documentation(s.into())
41+
}
42+
3943
pub fn as_str(&self) -> &str {
4044
&self.0
4145
}

crates/ide_completion/src/completions/attribute.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! This module uses a bit of static metadata to provide completions
44
//! for built-in attributes.
55
6+
use hir::HasAttrs;
67
use ide_db::helpers::generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES};
78
use once_cell::sync::Lazy;
89
use rustc_hash::{FxHashMap, FxHashSet};
@@ -81,6 +82,24 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
8182
None if is_inner => ATTRIBUTES.iter().for_each(add_completion),
8283
None => ATTRIBUTES.iter().filter(|compl| !compl.prefer_inner).for_each(add_completion),
8384
}
85+
86+
// FIXME: write a test for this when we can
87+
ctx.scope.process_all_names(&mut |name, scope_def| {
88+
if let hir::ScopeDef::MacroDef(mac) = scope_def {
89+
if mac.kind() == hir::MacroKind::Attr {
90+
let mut item = CompletionItem::new(
91+
CompletionKind::Attribute,
92+
ctx.source_range(),
93+
name.to_string(),
94+
);
95+
item.kind(CompletionItemKind::Attribute);
96+
if let Some(docs) = mac.docs(ctx.sema.db) {
97+
item.documentation(docs);
98+
}
99+
acc.add(item.build());
100+
}
101+
}
102+
});
84103
}
85104

86105
struct AttrCompletion {

crates/ide_completion/src/completions/attribute/derive.rs

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Completion for derives
2+
use hir::HasAttrs;
23
use itertools::Itertools;
3-
use rustc_hash::FxHashSet;
4+
use rustc_hash::FxHashMap;
45
use syntax::ast;
56

67
use crate::{
@@ -15,66 +16,64 @@ pub(super) fn complete_derive(
1516
derive_input: ast::TokenTree,
1617
) {
1718
if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) {
18-
for derive_completion in DEFAULT_DERIVE_COMPLETIONS
19-
.iter()
20-
.filter(|completion| !existing_derives.contains(completion.label))
21-
{
22-
let mut components = vec![derive_completion.label];
23-
components.extend(
24-
derive_completion
25-
.dependencies
26-
.iter()
27-
.filter(|&&dependency| !existing_derives.contains(dependency)),
28-
);
29-
let lookup = components.join(", ");
30-
let label = components.iter().rev().join(", ");
19+
for (derive, docs) in get_derive_names_in_scope(ctx) {
20+
let (label, lookup) = if let Some(derive_completion) = DEFAULT_DERIVE_COMPLETIONS
21+
.iter()
22+
.find(|derive_completion| derive_completion.label == derive)
23+
{
24+
let mut components = vec![derive_completion.label];
25+
components.extend(
26+
derive_completion
27+
.dependencies
28+
.iter()
29+
.filter(|&&dependency| !existing_derives.contains(dependency)),
30+
);
31+
let lookup = components.join(", ");
32+
let label = components.iter().rev().join(", ");
33+
(label, Some(lookup))
34+
} else {
35+
(derive, None)
36+
};
3137
let mut item =
3238
CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
33-
item.lookup_by(lookup).kind(CompletionItemKind::Attribute);
34-
item.add_to(acc);
35-
}
36-
37-
for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) {
38-
let mut item = CompletionItem::new(
39-
CompletionKind::Attribute,
40-
ctx.source_range(),
41-
custom_derive_name,
42-
);
4339
item.kind(CompletionItemKind::Attribute);
40+
if let Some(docs) = docs {
41+
item.documentation(docs);
42+
}
43+
if let Some(lookup) = lookup {
44+
item.lookup_by(lookup);
45+
}
4446
item.add_to(acc);
4547
}
4648
}
4749
}
4850

49-
fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
50-
let mut result = FxHashSet::default();
51+
fn get_derive_names_in_scope(
52+
ctx: &CompletionContext,
53+
) -> FxHashMap<String, Option<hir::Documentation>> {
54+
let mut result = FxHashMap::default();
5155
ctx.scope.process_all_names(&mut |name, scope_def| {
5256
if let hir::ScopeDef::MacroDef(mac) = scope_def {
5357
if mac.kind() == hir::MacroKind::Derive {
54-
result.insert(name.to_string());
58+
result.insert(name.to_string(), mac.docs(ctx.db));
5559
}
5660
}
5761
});
5862
result
5963
}
6064

61-
struct DeriveCompletion {
65+
struct DeriveDependencies {
6266
label: &'static str,
6367
dependencies: &'static [&'static str],
6468
}
6569

66-
/// Standard Rust derives and the information about their dependencies
70+
/// Standard Rust derives that have dependencies
6771
/// (the dependencies are needed so that the main derive don't break the compilation when added)
68-
const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
69-
DeriveCompletion { label: "Clone", dependencies: &[] },
70-
DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
71-
DeriveCompletion { label: "Debug", dependencies: &[] },
72-
DeriveCompletion { label: "Default", dependencies: &[] },
73-
DeriveCompletion { label: "Hash", dependencies: &[] },
74-
DeriveCompletion { label: "PartialEq", dependencies: &[] },
75-
DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] },
76-
DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] },
77-
DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
72+
const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[
73+
DeriveDependencies { label: "Copy", dependencies: &["Clone"] },
74+
DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] },
75+
DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
76+
DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] },
7877
];
7978

8079
#[cfg(test)]
@@ -94,6 +93,7 @@ mod tests {
9493
}
9594

9695
#[test]
96+
#[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
9797
fn empty_derive() {
9898
check(
9999
r#"#[derive($0)] struct Test;"#,
@@ -112,6 +112,7 @@ mod tests {
112112
}
113113

114114
#[test]
115+
#[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
115116
fn derive_with_input() {
116117
check(
117118
r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#,
@@ -129,6 +130,7 @@ mod tests {
129130
}
130131

131132
#[test]
133+
#[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
132134
fn derive_with_input2() {
133135
check(
134136
r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#,

crates/ide_completion/src/completions/attribute/lint.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ pub(super) fn complete_lint(
2424
ctx.source_range(),
2525
lint_completion.label,
2626
);
27-
item.kind(CompletionItemKind::Attribute).detail(lint_completion.description);
27+
item.kind(CompletionItemKind::Attribute)
28+
.documentation(hir::Documentation::new(lint_completion.description.to_owned()));
2829
item.add_to(acc)
2930
}
3031
}
@@ -61,4 +62,13 @@ mod tests {
6162
r#"#[allow(keyword_idents, deprecated)] struct Test;"#,
6263
)
6364
}
65+
66+
#[test]
67+
fn check_feature() {
68+
check_edit(
69+
"box_syntax",
70+
r#"#[feature(box_$0)] struct Test;"#,
71+
r#"#[feature(box_syntax)] struct Test;"#,
72+
)
73+
}
6474
}

0 commit comments

Comments
 (0)