aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion')
-rw-r--r--crates/ide_completion/Cargo.toml2
-rw-r--r--crates/ide_completion/src/completions.rs62
-rw-r--r--crates/ide_completion/src/completions/attribute.rs28
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs80
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs139
-rw-r--r--crates/ide_completion/src/completions/dot.rs8
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs27
-rw-r--r--crates/ide_completion/src/completions/keyword.rs25
-rw-r--r--crates/ide_completion/src/completions/macro_in_item_position.rs48
-rw-r--r--crates/ide_completion/src/completions/pattern.rs24
-rw-r--r--crates/ide_completion/src/completions/postfix.rs22
-rw-r--r--crates/ide_completion/src/completions/postfix/format_like.rs22
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs84
-rw-r--r--crates/ide_completion/src/completions/snippet.rs14
-rw-r--r--crates/ide_completion/src/completions/trait_impl.rs18
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs130
-rw-r--r--crates/ide_completion/src/context.rs174
-rw-r--r--crates/ide_completion/src/generated_lint_completions.rs6380
-rw-r--r--crates/ide_completion/src/lib.rs2
-rw-r--r--crates/ide_completion/src/patterns.rs30
-rw-r--r--crates/ide_completion/src/render.rs400
-rw-r--r--crates/ide_completion/src/render/builder_ext.rs12
-rw-r--r--crates/ide_completion/src/render/function.rs26
-rw-r--r--crates/ide_completion/src/render/macro_.rs4
-rw-r--r--crates/ide_completion/src/render/pattern.rs6
-rw-r--r--crates/ide_completion/src/render/type_alias.rs23
26 files changed, 743 insertions, 7047 deletions
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml
index ba81c9e04..3c45fe1cb 100644
--- a/crates/ide_completion/Cargo.toml
+++ b/crates/ide_completion/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14itertools = "0.10.0" 14itertools = "0.10.0"
15log = "0.4.8" 15log = "0.4.8"
16rustc-hash = "1.1.0" 16rustc-hash = "1.1.0"
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index ffdcdc930..bd90cefb2 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -6,7 +6,6 @@ pub(crate) mod flyimport;
6pub(crate) mod fn_param; 6pub(crate) mod fn_param;
7pub(crate) mod keyword; 7pub(crate) mod keyword;
8pub(crate) mod lifetime; 8pub(crate) mod lifetime;
9pub(crate) mod macro_in_item_position;
10pub(crate) mod mod_; 9pub(crate) mod mod_;
11pub(crate) mod pattern; 10pub(crate) mod pattern;
12pub(crate) mod postfix; 11pub(crate) mod postfix;
@@ -30,7 +29,7 @@ use crate::{
30 macro_::render_macro, 29 macro_::render_macro,
31 pattern::{render_struct_pat, render_variant_pat}, 30 pattern::{render_struct_pat, render_variant_pat},
32 render_field, render_resolution, render_tuple_field, 31 render_field, render_resolution, render_tuple_field,
33 type_alias::render_type_alias, 32 type_alias::{render_type_alias, render_type_alias_with_eq},
34 RenderContext, 33 RenderContext,
35 }, 34 },
36 CompletionContext, CompletionItem, CompletionItemKind, 35 CompletionContext, CompletionItem, CompletionItemKind,
@@ -57,10 +56,16 @@ impl Builder {
57} 56}
58 57
59impl Completions { 58impl Completions {
60 pub(crate) fn add(&mut self, item: CompletionItem) { 59 fn add(&mut self, item: CompletionItem) {
61 self.buf.push(item) 60 self.buf.push(item)
62 } 61 }
63 62
63 fn add_opt(&mut self, item: Option<CompletionItem>) {
64 if let Some(item) = item {
65 self.buf.push(item)
66 }
67 }
68
64 pub(crate) fn add_all<I>(&mut self, items: I) 69 pub(crate) fn add_all<I>(&mut self, items: I)
65 where 70 where
66 I: IntoIterator, 71 I: IntoIterator,
@@ -104,9 +109,10 @@ impl Completions {
104 local_name: hir::Name, 109 local_name: hir::Name,
105 resolution: &hir::ScopeDef, 110 resolution: &hir::ScopeDef,
106 ) { 111 ) {
107 if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) { 112 if ctx.expects_type() && resolution.is_value_def() {
108 self.add(item); 113 return;
109 } 114 }
115 self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution));
110 } 116 }
111 117
112 pub(crate) fn add_macro( 118 pub(crate) fn add_macro(
@@ -119,9 +125,7 @@ impl Completions {
119 Some(it) => it, 125 Some(it) => it,
120 None => return, 126 None => return,
121 }; 127 };
122 if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) { 128 self.add_opt(render_macro(RenderContext::new(ctx), None, name, macro_));
123 self.add(item);
124 }
125 } 129 }
126 130
127 pub(crate) fn add_function( 131 pub(crate) fn add_function(
@@ -130,9 +134,10 @@ impl Completions {
130 func: hir::Function, 134 func: hir::Function,
131 local_name: Option<hir::Name>, 135 local_name: Option<hir::Name>,
132 ) { 136 ) {
133 if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { 137 if ctx.expects_type() {
134 self.add(item) 138 return;
135 } 139 }
140 self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func));
136 } 141 }
137 142
138 pub(crate) fn add_method( 143 pub(crate) fn add_method(
@@ -142,10 +147,7 @@ impl Completions {
142 receiver: Option<hir::Name>, 147 receiver: Option<hir::Name>,
143 local_name: Option<hir::Name>, 148 local_name: Option<hir::Name>,
144 ) { 149 ) {
145 if let Some(item) = render_method(RenderContext::new(ctx), None, receiver, local_name, func) 150 self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func));
146 {
147 self.add(item)
148 }
149 } 151 }
150 152
151 pub(crate) fn add_variant_pat( 153 pub(crate) fn add_variant_pat(
@@ -154,9 +156,7 @@ impl Completions {
154 variant: hir::Variant, 156 variant: hir::Variant,
155 local_name: Option<hir::Name>, 157 local_name: Option<hir::Name>,
156 ) { 158 ) {
157 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, local_name, None) { 159 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None));
158 self.add(item);
159 }
160 } 160 }
161 161
162 pub(crate) fn add_qualified_variant_pat( 162 pub(crate) fn add_qualified_variant_pat(
@@ -165,9 +165,7 @@ impl Completions {
165 variant: hir::Variant, 165 variant: hir::Variant,
166 path: hir::ModPath, 166 path: hir::ModPath,
167 ) { 167 ) {
168 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) { 168 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)));
169 self.add(item);
170 }
171 } 169 }
172 170
173 pub(crate) fn add_struct_pat( 171 pub(crate) fn add_struct_pat(
@@ -176,21 +174,26 @@ impl Completions {
176 strukt: hir::Struct, 174 strukt: hir::Struct,
177 local_name: Option<hir::Name>, 175 local_name: Option<hir::Name>,
178 ) { 176 ) {
179 if let Some(item) = render_struct_pat(RenderContext::new(ctx), strukt, local_name) { 177 self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name));
180 self.add(item);
181 }
182 } 178 }
183 179
184 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { 180 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
185 if let Some(item) = render_const(RenderContext::new(ctx), constant) { 181 if ctx.expects_type() {
186 self.add(item); 182 return;
187 } 183 }
184 self.add_opt(render_const(RenderContext::new(ctx), constant));
188 } 185 }
189 186
190 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { 187 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
191 if let Some(item) = render_type_alias(RenderContext::new(ctx), type_alias) { 188 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias));
192 self.add(item) 189 }
193 } 190
191 pub(crate) fn add_type_alias_with_eq(
192 &mut self,
193 ctx: &CompletionContext,
194 type_alias: hir::TypeAlias,
195 ) {
196 self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
194 } 197 }
195 198
196 pub(crate) fn add_qualified_enum_variant( 199 pub(crate) fn add_qualified_enum_variant(
@@ -209,6 +212,9 @@ impl Completions {
209 variant: hir::Variant, 212 variant: hir::Variant,
210 local_name: Option<hir::Name>, 213 local_name: Option<hir::Name>,
211 ) { 214 ) {
215 if ctx.expects_type() {
216 return;
217 }
212 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); 218 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None);
213 self.add(item); 219 self.add(item);
214 } 220 }
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index c48bb9e66..6df569c2a 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -3,20 +3,20 @@
3//! This module uses a bit of static metadata to provide completions 3//! This module uses a bit of static metadata to provide completions
4//! for built-in attributes. 4//! for built-in attributes.
5 5
6use hir::HasAttrs;
7use ide_db::helpers::generated_lints::{CLIPPY_LINTS, DEFAULT_LINTS, FEATURES};
6use once_cell::sync::Lazy; 8use once_cell::sync::Lazy;
7use rustc_hash::{FxHashMap, FxHashSet}; 9use rustc_hash::{FxHashMap, FxHashSet};
8use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, NodeOrToken, SyntaxKind, T}; 10use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, NodeOrToken, SyntaxKind, T};
9 11
10use crate::{ 12use crate::{
11 context::CompletionContext, 13 context::CompletionContext,
12 generated_lint_completions::{CLIPPY_LINTS, FEATURES},
13 item::{CompletionItem, CompletionItemKind, CompletionKind}, 14 item::{CompletionItem, CompletionItemKind, CompletionKind},
14 Completions, 15 Completions,
15}; 16};
16 17
17mod derive; 18mod derive;
18mod lint; 19mod lint;
19pub(crate) use self::lint::LintCompletion;
20 20
21pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 21pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
22 let attribute = ctx.attribute_under_caret.as_ref()?; 22 let attribute = ctx.attribute_under_caret.as_ref()?;
@@ -25,7 +25,7 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
25 "derive" => derive::complete_derive(acc, ctx, token_tree), 25 "derive" => derive::complete_derive(acc, ctx, token_tree),
26 "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES), 26 "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES),
27 "allow" | "warn" | "deny" | "forbid" => { 27 "allow" | "warn" | "deny" | "forbid" => {
28 lint::complete_lint(acc, ctx, token_tree.clone(), lint::DEFAULT_LINT_COMPLETIONS); 28 lint::complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINTS);
29 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); 29 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
30 } 30 }
31 _ => (), 31 _ => (),
@@ -69,7 +69,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
69 } 69 }
70 70
71 if is_inner || !attr_completion.prefer_inner { 71 if is_inner || !attr_completion.prefer_inner {
72 acc.add(item.build()); 72 item.add_to(acc);
73 } 73 }
74 }; 74 };
75 75
@@ -82,6 +82,24 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
82 None if is_inner => ATTRIBUTES.iter().for_each(add_completion), 82 None if is_inner => ATTRIBUTES.iter().for_each(add_completion),
83 None => ATTRIBUTES.iter().filter(|compl| !compl.prefer_inner).for_each(add_completion), 83 None => ATTRIBUTES.iter().filter(|compl| !compl.prefer_inner).for_each(add_completion),
84 } 84 }
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 item.add_to(acc);
100 }
101 }
102 });
85} 103}
86 104
87struct AttrCompletion { 105struct AttrCompletion {
@@ -201,7 +219,7 @@ static KIND_TO_ATTRIBUTES: Lazy<FxHashMap<SyntaxKind, &[&str]>> = Lazy::new(|| {
201}); 219});
202const EXPR_ATTRIBUTES: &[&str] = attrs!(); 220const EXPR_ATTRIBUTES: &[&str] = attrs!();
203 221
204/// https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index 222/// <https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index>
205// Keep these sorted for the binary search! 223// Keep these sorted for the binary search!
206const ATTRIBUTES: &[AttrCompletion] = &[ 224const ATTRIBUTES: &[AttrCompletion] = &[
207 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")), 225 attr("allow(…)", Some("allow"), Some("allow(${0:lint})")),
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index 0bc3eab98..d526824fb 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -1,6 +1,7 @@
1//! Completion for derives 1//! Completion for derives
2use hir::HasAttrs;
2use itertools::Itertools; 3use itertools::Itertools;
3use rustc_hash::FxHashSet; 4use rustc_hash::FxHashMap;
4use syntax::ast; 5use syntax::ast;
5 6
6use crate::{ 7use crate::{
@@ -15,66 +16,64 @@ pub(super) fn complete_derive(
15 derive_input: ast::TokenTree, 16 derive_input: ast::TokenTree,
16) { 17) {
17 if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) { 18 if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) {
18 for derive_completion in DEFAULT_DERIVE_COMPLETIONS 19 for (derive, docs) in get_derive_names_in_scope(ctx) {
19 .iter() 20 let (label, lookup) = if let Some(derive_completion) = DEFAULT_DERIVE_COMPLETIONS
20 .filter(|completion| !existing_derives.contains(completion.label)) 21 .iter()
21 { 22 .find(|derive_completion| derive_completion.label == derive)
22 let mut components = vec![derive_completion.label]; 23 {
23 components.extend( 24 let mut components = vec![derive_completion.label];
24 derive_completion 25 components.extend(
25 .dependencies 26 derive_completion
26 .iter() 27 .dependencies
27 .filter(|&&dependency| !existing_derives.contains(dependency)), 28 .iter()
28 ); 29 .filter(|&&dependency| !existing_derives.contains(dependency)),
29 let lookup = components.join(", "); 30 );
30 let label = components.iter().rev().join(", "); 31 let lookup = components.join(", ");
32 let label = components.iter().rev().join(", ");
33 (label, Some(lookup))
34 } else {
35 (derive, None)
36 };
31 let mut item = 37 let mut item =
32 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label); 38 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 );
43 item.kind(CompletionItemKind::Attribute); 39 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 }
44 item.add_to(acc); 46 item.add_to(acc);
45 } 47 }
46 } 48 }
47} 49}
48 50
49fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { 51fn get_derive_names_in_scope(
50 let mut result = FxHashSet::default(); 52 ctx: &CompletionContext,
53) -> FxHashMap<String, Option<hir::Documentation>> {
54 let mut result = FxHashMap::default();
51 ctx.scope.process_all_names(&mut |name, scope_def| { 55 ctx.scope.process_all_names(&mut |name, scope_def| {
52 if let hir::ScopeDef::MacroDef(mac) = scope_def { 56 if let hir::ScopeDef::MacroDef(mac) = scope_def {
53 if mac.kind() == hir::MacroKind::Derive { 57 if mac.kind() == hir::MacroKind::Derive {
54 result.insert(name.to_string()); 58 result.insert(name.to_string(), mac.docs(ctx.db));
55 } 59 }
56 } 60 }
57 }); 61 });
58 result 62 result
59} 63}
60 64
61struct DeriveCompletion { 65struct DeriveDependencies {
62 label: &'static str, 66 label: &'static str,
63 dependencies: &'static [&'static str], 67 dependencies: &'static [&'static str],
64} 68}
65 69
66/// Standard Rust derives and the information about their dependencies 70/// Standard Rust derives that have dependencies
67/// (the dependencies are needed so that the main derive don't break the compilation when added) 71/// (the dependencies are needed so that the main derive don't break the compilation when added)
68const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[ 72const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[
69 DeriveCompletion { label: "Clone", dependencies: &[] }, 73 DeriveDependencies { label: "Copy", dependencies: &["Clone"] },
70 DeriveCompletion { label: "Copy", dependencies: &["Clone"] }, 74 DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] },
71 DeriveCompletion { label: "Debug", dependencies: &[] }, 75 DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
72 DeriveCompletion { label: "Default", dependencies: &[] }, 76 DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] },
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"] },
78]; 77];
79 78
80#[cfg(test)] 79#[cfg(test)]
@@ -94,6 +93,7 @@ mod tests {
94 } 93 }
95 94
96 #[test] 95 #[test]
96 #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
97 fn empty_derive() { 97 fn empty_derive() {
98 check( 98 check(
99 r#"#[derive($0)] struct Test;"#, 99 r#"#[derive($0)] struct Test;"#,
@@ -112,6 +112,7 @@ mod tests {
112 } 112 }
113 113
114 #[test] 114 #[test]
115 #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
115 fn derive_with_input() { 116 fn derive_with_input() {
116 check( 117 check(
117 r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, 118 r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#,
@@ -129,6 +130,7 @@ mod tests {
129 } 130 }
130 131
131 #[test] 132 #[test]
133 #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures
132 fn derive_with_input2() { 134 fn derive_with_input2() {
133 check( 135 check(
134 r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, 136 r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#,
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs
index 403630dce..ca99e9759 100644
--- a/crates/ide_completion/src/completions/attribute/lint.rs
+++ b/crates/ide_completion/src/completions/attribute/lint.rs
@@ -1,4 +1,5 @@
1//! Completion for lints 1//! Completion for lints
2use ide_db::helpers::generated_lints::Lint;
2use syntax::ast; 3use syntax::ast;
3 4
4use crate::{ 5use crate::{
@@ -11,7 +12,7 @@ pub(super) fn complete_lint(
11 acc: &mut Completions, 12 acc: &mut Completions,
12 ctx: &CompletionContext, 13 ctx: &CompletionContext,
13 derive_input: ast::TokenTree, 14 derive_input: ast::TokenTree,
14 lints_completions: &[LintCompletion], 15 lints_completions: &[Lint],
15) { 16) {
16 if let Some(existing_lints) = super::parse_comma_sep_input(derive_input) { 17 if let Some(existing_lints) = super::parse_comma_sep_input(derive_input) {
17 for lint_completion in lints_completions 18 for lint_completion in lints_completions
@@ -23,136 +24,13 @@ pub(super) fn complete_lint(
23 ctx.source_range(), 24 ctx.source_range(),
24 lint_completion.label, 25 lint_completion.label,
25 ); 26 );
26 item.kind(CompletionItemKind::Attribute).detail(lint_completion.description); 27 item.kind(CompletionItemKind::Attribute)
28 .documentation(hir::Documentation::new(lint_completion.description.to_owned()));
27 item.add_to(acc) 29 item.add_to(acc)
28 } 30 }
29 } 31 }
30} 32}
31 33
32pub(crate) struct LintCompletion {
33 pub(crate) label: &'static str,
34 pub(crate) description: &'static str,
35}
36
37#[rustfmt::skip]
38pub(super) const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
39 LintCompletion { label: "absolute_paths_not_starting_with_crate", description: r#"fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name"# },
40 LintCompletion { label: "anonymous_parameters", description: r#"detects anonymous parameters"# },
41 LintCompletion { label: "box_pointers", description: r#"use of owned (Box type) heap memory"# },
42 LintCompletion { label: "deprecated_in_future", description: r#"detects use of items that will be deprecated in a future version"# },
43 LintCompletion { label: "elided_lifetimes_in_paths", description: r#"hidden lifetime parameters in types are deprecated"# },
44 LintCompletion { label: "explicit_outlives_requirements", description: r#"outlives requirements can be inferred"# },
45 LintCompletion { label: "indirect_structural_match", description: r#"pattern with const indirectly referencing non-structural-match type"# },
46 LintCompletion { label: "keyword_idents", description: r#"detects edition keywords being used as an identifier"# },
47 LintCompletion { label: "macro_use_extern_crate", description: r#"the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system"# },
48 LintCompletion { label: "meta_variable_misuse", description: r#"possible meta-variable misuse at macro definition"# },
49 LintCompletion { label: "missing_copy_implementations", description: r#"detects potentially-forgotten implementations of `Copy`"# },
50 LintCompletion { label: "missing_crate_level_docs", description: r#"detects crates with no crate-level documentation"# },
51 LintCompletion { label: "missing_debug_implementations", description: r#"detects missing implementations of Debug"# },
52 LintCompletion { label: "missing_docs", description: r#"detects missing documentation for public members"# },
53 LintCompletion { label: "missing_doc_code_examples", description: r#"detects publicly-exported items without code samples in their documentation"# },
54 LintCompletion { label: "non_ascii_idents", description: r#"detects non-ASCII identifiers"# },
55 LintCompletion { label: "private_doc_tests", description: r#"detects code samples in docs of private items not documented by rustdoc"# },
56 LintCompletion { label: "single_use_lifetimes", description: r#"detects lifetime parameters that are only used once"# },
57 LintCompletion { label: "trivial_casts", description: r#"detects trivial casts which could be removed"# },
58 LintCompletion { label: "trivial_numeric_casts", description: r#"detects trivial casts of numeric types which could be removed"# },
59 LintCompletion { label: "unaligned_references", description: r#"detects unaligned references to fields of packed structs"# },
60 LintCompletion { label: "unreachable_pub", description: r#"`pub` items not reachable from crate root"# },
61 LintCompletion { label: "unsafe_code", description: r#"usage of `unsafe` code"# },
62 LintCompletion { label: "unsafe_op_in_unsafe_fn", description: r#"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"# },
63 LintCompletion { label: "unstable_features", description: r#"enabling unstable features (deprecated. do not use)"# },
64 LintCompletion { label: "unused_crate_dependencies", description: r#"crate dependencies that are never used"# },
65 LintCompletion { label: "unused_extern_crates", description: r#"extern crates that are never used"# },
66 LintCompletion { label: "unused_import_braces", description: r#"unnecessary braces around an imported item"# },
67 LintCompletion { label: "unused_lifetimes", description: r#"detects lifetime parameters that are never used"# },
68 LintCompletion { label: "unused_qualifications", description: r#"detects unnecessarily qualified names"# },
69 LintCompletion { label: "unused_results", description: r#"unused result of an expression in a statement"# },
70 LintCompletion { label: "variant_size_differences", description: r#"detects enums with widely varying variant sizes"# },
71 LintCompletion { label: "array_into_iter", description: r#"detects calling `into_iter` on arrays"# },
72 LintCompletion { label: "asm_sub_register", description: r#"using only a subset of a register for inline asm inputs"# },
73 LintCompletion { label: "bare_trait_objects", description: r#"suggest using `dyn Trait` for trait objects"# },
74 LintCompletion { label: "bindings_with_variant_name", description: r#"detects pattern bindings with the same name as one of the matched variants"# },
75 LintCompletion { label: "cenum_impl_drop_cast", description: r#"a C-like enum implementing Drop is cast"# },
76 LintCompletion { label: "clashing_extern_declarations", description: r#"detects when an extern fn has been declared with the same name but different types"# },
77 LintCompletion { label: "coherence_leak_check", description: r#"distinct impls distinguished only by the leak-check code"# },
78 LintCompletion { label: "confusable_idents", description: r#"detects visually confusable pairs between identifiers"# },
79 LintCompletion { label: "dead_code", description: r#"detect unused, unexported items"# },
80 LintCompletion { label: "deprecated", description: r#"detects use of deprecated items"# },
81 LintCompletion { label: "ellipsis_inclusive_range_patterns", description: r#"`...` range patterns are deprecated"# },
82 LintCompletion { label: "exported_private_dependencies", description: r#"public interface leaks type from a private dependency"# },
83 LintCompletion { label: "illegal_floating_point_literal_pattern", description: r#"floating-point literals cannot be used in patterns"# },
84 LintCompletion { label: "improper_ctypes", description: r#"proper use of libc types in foreign modules"# },
85 LintCompletion { label: "improper_ctypes_definitions", description: r#"proper use of libc types in foreign item definitions"# },
86 LintCompletion { label: "incomplete_features", description: r#"incomplete features that may function improperly in some or all cases"# },
87 LintCompletion { label: "inline_no_sanitize", description: r#"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`"# },
88 LintCompletion { label: "intra_doc_link_resolution_failure", description: r#"failures in resolving intra-doc link targets"# },
89 LintCompletion { label: "invalid_codeblock_attributes", description: r#"codeblock attribute looks a lot like a known one"# },
90 LintCompletion { label: "invalid_value", description: r#"an invalid value is being created (such as a NULL reference)"# },
91 LintCompletion { label: "irrefutable_let_patterns", description: r#"detects irrefutable patterns in if-let and while-let statements"# },
92 LintCompletion { label: "late_bound_lifetime_arguments", description: r#"detects generic lifetime arguments in path segments with late bound lifetime parameters"# },
93 LintCompletion { label: "mixed_script_confusables", description: r#"detects Unicode scripts whose mixed script confusables codepoints are solely used"# },
94 LintCompletion { label: "mutable_borrow_reservation_conflict", description: r#"reservation of a two-phased borrow conflicts with other shared borrows"# },
95 LintCompletion { label: "non_camel_case_types", description: r#"types, variants, traits and type parameters should have camel case names"# },
96 LintCompletion { label: "non_shorthand_field_patterns", description: r#"using `Struct { x: x }` instead of `Struct { x }` in a pattern"# },
97 LintCompletion { label: "non_snake_case", description: r#"variables, methods, functions, lifetime parameters and modules should have snake case names"# },
98 LintCompletion { label: "non_upper_case_globals", description: r#"static constants should have uppercase identifiers"# },
99 LintCompletion { label: "no_mangle_generic_items", description: r#"generic items must be mangled"# },
100 LintCompletion { label: "overlapping_patterns", description: r#"detects overlapping patterns"# },
101 LintCompletion { label: "path_statements", description: r#"path statements with no effect"# },
102 LintCompletion { label: "private_in_public", description: r#"detect private items in public interfaces not caught by the old implementation"# },
103 LintCompletion { label: "proc_macro_derive_resolution_fallback", description: r#"detects proc macro derives using inaccessible names from parent modules"# },
104 LintCompletion { label: "redundant_semicolons", description: r#"detects unnecessary trailing semicolons"# },
105 LintCompletion { label: "renamed_and_removed_lints", description: r#"lints that have been renamed or removed"# },
106 LintCompletion { label: "safe_packed_borrows", description: r#"safe borrows of fields of packed structs were erroneously allowed"# },
107 LintCompletion { label: "stable_features", description: r#"stable features found in `#[feature]` directive"# },
108 LintCompletion { label: "trivial_bounds", description: r#"these bounds don't depend on an type parameters"# },
109 LintCompletion { label: "type_alias_bounds", description: r#"bounds in type aliases are not enforced"# },
110 LintCompletion { label: "tyvar_behind_raw_pointer", description: r#"raw pointer to an inference variable"# },
111 LintCompletion { label: "uncommon_codepoints", description: r#"detects uncommon Unicode codepoints in identifiers"# },
112 LintCompletion { label: "unconditional_recursion", description: r#"functions that cannot return without calling themselves"# },
113 LintCompletion { label: "unknown_lints", description: r#"unrecognized lint attribute"# },
114 LintCompletion { label: "unnameable_test_items", description: r#"detects an item that cannot be named being marked as `#[test_case]`"# },
115 LintCompletion { label: "unreachable_code", description: r#"detects unreachable code paths"# },
116 LintCompletion { label: "unreachable_patterns", description: r#"detects unreachable patterns"# },
117 LintCompletion { label: "unstable_name_collisions", description: r#"detects name collision with an existing but unstable method"# },
118 LintCompletion { label: "unused_allocation", description: r#"detects unnecessary allocations that can be eliminated"# },
119 LintCompletion { label: "unused_assignments", description: r#"detect assignments that will never be read"# },
120 LintCompletion { label: "unused_attributes", description: r#"detects attributes that were not used by the compiler"# },
121 LintCompletion { label: "unused_braces", description: r#"unnecessary braces around an expression"# },
122 LintCompletion { label: "unused_comparisons", description: r#"comparisons made useless by limits of the types involved"# },
123 LintCompletion { label: "unused_doc_comments", description: r#"detects doc comments that aren't used by rustdoc"# },
124 LintCompletion { label: "unused_features", description: r#"unused features found in crate-level `#[feature]` directives"# },
125 LintCompletion { label: "unused_imports", description: r#"imports that are never used"# },
126 LintCompletion { label: "unused_labels", description: r#"detects labels that are never used"# },
127 LintCompletion { label: "unused_macros", description: r#"detects macros that were not used"# },
128 LintCompletion { label: "unused_must_use", description: r#"unused result of a type flagged as `#[must_use]`"# },
129 LintCompletion { label: "unused_mut", description: r#"detect mut variables which don't need to be mutable"# },
130 LintCompletion { label: "unused_parens", description: r#"`if`, `match`, `while` and `return` do not need parentheses"# },
131 LintCompletion { label: "unused_unsafe", description: r#"unnecessary use of an `unsafe` block"# },
132 LintCompletion { label: "unused_variables", description: r#"detect variables which are not used in any way"# },
133 LintCompletion { label: "warnings", description: r#"mass-change the level for lints which produce warnings"# },
134 LintCompletion { label: "where_clauses_object_safety", description: r#"checks the object safety of where clauses"# },
135 LintCompletion { label: "while_true", description: r#"suggest using `loop { }` instead of `while true { }`"# },
136 LintCompletion { label: "ambiguous_associated_items", description: r#"ambiguous associated items"# },
137 LintCompletion { label: "arithmetic_overflow", description: r#"arithmetic operation overflows"# },
138 LintCompletion { label: "conflicting_repr_hints", description: r#"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"# },
139 LintCompletion { label: "const_err", description: r#"constant evaluation detected erroneous expression"# },
140 LintCompletion { label: "ill_formed_attribute_input", description: r#"ill-formed attribute inputs that were previously accepted and used in practice"# },
141 LintCompletion { label: "incomplete_include", description: r#"trailing content in included file"# },
142 LintCompletion { label: "invalid_type_param_default", description: r#"type parameter default erroneously allowed in invalid location"# },
143 LintCompletion { label: "macro_expanded_macro_exports_accessed_by_absolute_paths", description: r#"macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths"# },
144 LintCompletion { label: "missing_fragment_specifier", description: r#"detects missing fragment specifiers in unused `macro_rules!` patterns"# },
145 LintCompletion { label: "mutable_transmutes", description: r#"mutating transmuted &mut T from &T may cause undefined behavior"# },
146 LintCompletion { label: "no_mangle_const_items", description: r#"const items will not have their symbols exported"# },
147 LintCompletion { label: "order_dependent_trait_objects", description: r#"trait-object types were treated as different depending on marker-trait order"# },
148 LintCompletion { label: "overflowing_literals", description: r#"literal out of range for its type"# },
149 LintCompletion { label: "patterns_in_fns_without_body", description: r#"patterns in functions without body were erroneously allowed"# },
150 LintCompletion { label: "pub_use_of_private_extern_crate", description: r#"detect public re-exports of private extern crates"# },
151 LintCompletion { label: "soft_unstable", description: r#"a feature gate that doesn't break dependent crates"# },
152 LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# },
153 LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# },
154];
155
156#[cfg(test)] 34#[cfg(test)]
157mod tests { 35mod tests {
158 36
@@ -184,4 +62,13 @@ mod tests {
184 r#"#[allow(keyword_idents, deprecated)] struct Test;"#, 62 r#"#[allow(keyword_idents, deprecated)] struct Test;"#,
185 ) 63 )
186 } 64 }
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 }
187} 74}
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index e0a7021fd..9552875c1 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -4,7 +4,7 @@ use either::Either;
4use hir::{HasVisibility, ScopeDef}; 4use hir::{HasVisibility, ScopeDef};
5use rustc_hash::FxHashSet; 5use rustc_hash::FxHashSet;
6 6
7use crate::{context::CompletionContext, Completions}; 7use crate::{context::CompletionContext, patterns::ImmediateLocation, Completions};
8 8
9/// Complete dot accesses, i.e. fields or methods. 9/// Complete dot accesses, i.e. fields or methods.
10pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { 10pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
@@ -13,12 +13,12 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
13 _ => return complete_undotted_self(acc, ctx), 13 _ => return complete_undotted_self(acc, ctx),
14 }; 14 };
15 15
16 let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { 16 let receiver_ty = match ctx.sema.type_of_expr(dot_receiver) {
17 Some(ty) => ty, 17 Some(ty) => ty,
18 _ => return, 18 _ => return,
19 }; 19 };
20 20
21 if ctx.is_call { 21 if matches!(ctx.completion_location, Some(ImmediateLocation::MethodCall { .. })) {
22 cov_mark::hit!(test_no_struct_field_completion_for_method_call); 22 cov_mark::hit!(test_no_struct_field_completion_for_method_call);
23 } else { 23 } else {
24 complete_fields(ctx, &receiver_ty, |field, ty| match field { 24 complete_fields(ctx, &receiver_ty, |field, ty| match field {
@@ -33,7 +33,7 @@ fn complete_undotted_self(acc: &mut Completions, ctx: &CompletionContext) {
33 if !ctx.config.enable_self_on_the_fly { 33 if !ctx.config.enable_self_on_the_fly {
34 return; 34 return;
35 } 35 }
36 if !ctx.is_trivial_path || ctx.is_path_disallowed() { 36 if !ctx.is_trivial_path() || ctx.is_path_disallowed() {
37 return; 37 return;
38 } 38 }
39 ctx.scope.process_all_names(&mut |name, def| { 39 ctx.scope.process_all_names(&mut |name, def| {
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index d72bf13d3..30b8d44bd 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -1,10 +1,10 @@
1//! Feature: completion with imports-on-the-fly 1//! Feature: completion with imports-on-the-fly
2//! 2//!
3//! When completing names in the current scope, proposes additional imports from other modules or crates, 3//! When completing names in the current scope, proposes additional imports from other modules or crates,
4//! if they can be qualified in the scope and their name contains all symbols from the completion input. 4//! if they can be qualified in the scope, and their name contains all symbols from the completion input.
5//! 5//!
6//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. 6//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
7//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the contaning is checked case-insensitively. 7//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively.
8//! 8//!
9//! ``` 9//! ```
10//! fn main() { 10//! fn main() {
@@ -23,8 +23,8 @@
23//! ``` 23//! ```
24//! 24//!
25//! Also completes associated items, that require trait imports. 25//! Also completes associated items, that require trait imports.
26//! If any unresolved and/or partially-qualified path predeces the input, it will be taken into account. 26//! If any unresolved and/or partially-qualified path precedes the input, it will be taken into account.
27//! Currently, only the imports with their import path ending with the whole qialifier will be proposed 27//! Currently, only the imports with their import path ending with the whole qualifier will be proposed
28//! (no fuzzy matching for qualifier). 28//! (no fuzzy matching for qualifier).
29//! 29//!
30//! ``` 30//! ```
@@ -61,14 +61,14 @@
61//! } 61//! }
62//! ``` 62//! ```
63//! 63//!
64//! NOTE: currently, if an assoc item comes from a trait that's not currently imported and it also has an unresolved and/or partially-qualified path, 64//! NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path,
65//! no imports will be proposed. 65//! no imports will be proposed.
66//! 66//!
67//! .Fuzzy search details 67//! .Fuzzy search details
68//! 68//!
69//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only 69//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
70//! (i.e. in `HashMap` in the `std::collections::HashMap` path). 70//! (i.e. in `HashMap` in the `std::collections::HashMap` path).
71//! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols 71//! For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols
72//! (but shows all associated items for any input length). 72//! (but shows all associated items for any input length).
73//! 73//!
74//! .Import configuration 74//! .Import configuration
@@ -79,18 +79,17 @@
79//! .LSP and performance implications 79//! .LSP and performance implications
80//! 80//!
81//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` 81//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
82//! (case sensitive) resolve client capability in its client capabilities. 82//! (case-sensitive) resolve client capability in its client capabilities.
83//! This way the server is able to defer the costly computations, doing them for a selected completion item only. 83//! This way the server is able to defer the costly computations, doing them for a selected completion item only.
84//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, 84//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
85//! which might be slow ergo the feature is automatically disabled. 85//! which might be slow ergo the feature is automatically disabled.
86//! 86//!
87//! .Feature toggle 87//! .Feature toggle
88//! 88//!
89//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. 89//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
90//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding 90//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
91//! capability enabled. 91//! capability enabled.
92 92
93use hir::ModPath;
94use ide_db::helpers::{ 93use ide_db::helpers::{
95 import_assets::{ImportAssets, ImportCandidate}, 94 import_assets::{ImportAssets, ImportCandidate},
96 insert_use::ImportScope, 95 insert_use::ImportScope,
@@ -161,13 +160,13 @@ pub(crate) fn position_for_import<'a>(
161) -> Option<&'a SyntaxNode> { 160) -> Option<&'a SyntaxNode> {
162 Some(match import_candidate { 161 Some(match import_candidate {
163 Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(), 162 Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(),
164 Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(), 163 Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual()?.syntax(),
165 Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(), 164 Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver()?.syntax(),
166 None => ctx 165 None => ctx
167 .name_ref_syntax 166 .name_ref_syntax
168 .as_ref() 167 .as_ref()
169 .map(|name_ref| name_ref.syntax()) 168 .map(|name_ref| name_ref.syntax())
170 .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax())) 169 .or_else(|| ctx.path_qual().map(|path| path.syntax()))
171 .or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?, 170 .or_else(|| ctx.dot_receiver().map(|expr| expr.syntax()))?,
172 }) 171 })
173} 172}
@@ -190,7 +189,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
190 }; 189 };
191 let assets_for_path = ImportAssets::for_fuzzy_path( 190 let assets_for_path = ImportAssets::for_fuzzy_path(
192 current_module, 191 current_module,
193 ctx.path_qual.clone(), 192 ctx.path_qual().cloned(),
194 fuzzy_name, 193 fuzzy_name,
195 &ctx.sema, 194 &ctx.sema,
196 approximate_node, 195 approximate_node,
@@ -208,7 +207,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
208} 207}
209 208
210fn compute_fuzzy_completion_order_key( 209fn compute_fuzzy_completion_order_key(
211 proposed_mod_path: &ModPath, 210 proposed_mod_path: &hir::ModPath,
212 user_input_lowercased: &str, 211 user_input_lowercased: &str,
213) -> usize { 212) -> usize {
214 cov_mark::hit!(certain_fuzzy_order_test); 213 cov_mark::hit!(certain_fuzzy_order_test);
diff --git a/crates/ide_completion/src/completions/keyword.rs b/crates/ide_completion/src/completions/keyword.rs
index 1a7a484a4..ba13d3707 100644
--- a/crates/ide_completion/src/completions/keyword.rs
+++ b/crates/ide_completion/src/completions/keyword.rs
@@ -5,8 +5,8 @@ use std::iter;
5use syntax::{SyntaxKind, T}; 5use syntax::{SyntaxKind, T};
6 6
7use crate::{ 7use crate::{
8 patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind, 8 context::PathCompletionContext, patterns::ImmediateLocation, CompletionContext, CompletionItem,
9 CompletionKind, Completions, 9 CompletionItemKind, CompletionKind, Completions,
10}; 10};
11 11
12pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) { 12pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionContext) {
@@ -19,11 +19,12 @@ pub(crate) fn complete_use_tree_keyword(acc: &mut Completions, ctx: &CompletionC
19 }; 19 };
20 20
21 if ctx.use_item_syntax.is_some() { 21 if ctx.use_item_syntax.is_some() {
22 if ctx.path_qual.is_none() { 22 let qual = ctx.path_qual();
23 if qual.is_none() {
23 kw_completion("crate::").add_to(acc); 24 kw_completion("crate::").add_to(acc);
24 } 25 }
25 kw_completion("self").add_to(acc); 26 kw_completion("self").add_to(acc);
26 if iter::successors(ctx.path_qual.clone(), |p| p.qualifier()) 27 if iter::successors(qual.cloned(), |p| p.qualifier())
27 .all(|p| p.segment().and_then(|s| s.super_token()).is_some()) 28 .all(|p| p.segment().and_then(|s| s.super_token()).is_some())
28 { 29 {
29 kw_completion("super::").add_to(acc); 30 kw_completion("super::").add_to(acc);
@@ -127,8 +128,15 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
127 add_keyword("mut", "mut "); 128 add_keyword("mut", "mut ");
128 } 129 }
129 130
130 if ctx.in_loop_body { 131 let (can_be_stmt, in_loop_body) = match ctx.path_context {
131 if ctx.can_be_stmt { 132 Some(PathCompletionContext {
133 is_trivial_path: true, can_be_stmt, in_loop_body, ..
134 }) => (can_be_stmt, in_loop_body),
135 _ => return,
136 };
137
138 if in_loop_body {
139 if can_be_stmt {
132 add_keyword("continue", "continue;"); 140 add_keyword("continue", "continue;");
133 add_keyword("break", "break;"); 141 add_keyword("break", "break;");
134 } else { 142 } else {
@@ -137,9 +145,6 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
137 } 145 }
138 } 146 }
139 147
140 if !ctx.is_trivial_path {
141 return;
142 }
143 let fn_def = match &ctx.function_def { 148 let fn_def = match &ctx.function_def {
144 Some(it) => it, 149 Some(it) => it,
145 None => return, 150 None => return,
@@ -147,7 +152,7 @@ pub(crate) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
147 152
148 add_keyword( 153 add_keyword(
149 "return", 154 "return",
150 match (ctx.can_be_stmt, fn_def.ret_type().is_some()) { 155 match (can_be_stmt, fn_def.ret_type().is_some()) {
151 (true, true) => "return $0;", 156 (true, true) => "return $0;",
152 (true, false) => "return;", 157 (true, false) => "return;",
153 (false, true) => "return $0", 158 (false, true) => "return $0",
diff --git a/crates/ide_completion/src/completions/macro_in_item_position.rs b/crates/ide_completion/src/completions/macro_in_item_position.rs
deleted file mode 100644
index 781b96ff1..000000000
--- a/crates/ide_completion/src/completions/macro_in_item_position.rs
+++ /dev/null
@@ -1,48 +0,0 @@
1//! Completes macro invocations used in item position.
2
3use crate::{CompletionContext, Completions};
4
5// Ideally this should be removed and moved into `(un)qualified_path` respectively
6pub(crate) fn complete_macro_in_item_position(acc: &mut Completions, ctx: &CompletionContext) {
7 // Show only macros in top level.
8 if !ctx.expects_item() {
9 return;
10 }
11
12 ctx.scope.process_all_names(&mut |name, res| {
13 if let hir::ScopeDef::MacroDef(mac) = res {
14 acc.add_macro(ctx, Some(name.clone()), mac);
15 }
16 // FIXME: This should be done in qualified_path/unqualified_path instead?
17 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
18 acc.add_resolution(ctx, name, &res);
19 }
20 })
21}
22
23#[cfg(test)]
24mod tests {
25 use expect_test::{expect, Expect};
26
27 use crate::{test_utils::completion_list, CompletionKind};
28
29 fn check(ra_fixture: &str, expect: Expect) {
30 let actual = completion_list(ra_fixture, CompletionKind::Reference);
31 expect.assert_eq(&actual)
32 }
33
34 #[test]
35 fn completes_macros_as_item() {
36 check(
37 r#"
38macro_rules! foo { () => {} }
39fn foo() {}
40
41$0
42"#,
43 expect![[r#"
44 ma foo!(…) macro_rules! foo
45 "#]],
46 )
47 }
48}
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index 8a728c67e..1daa8595a 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -39,7 +39,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
39 | hir::ModuleDef::Module(..) => refutable, 39 | hir::ModuleDef::Module(..) => refutable,
40 _ => false, 40 _ => false,
41 }, 41 },
42 hir::ScopeDef::MacroDef(_) => true, 42 hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
43 hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() { 43 hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
44 Some(hir::Adt::Struct(strukt)) => { 44 Some(hir::Adt::Struct(strukt)) => {
45 acc.add_struct_pat(ctx, strukt, Some(name.clone())); 45 acc.add_struct_pat(ctx, strukt, Some(name.clone()));
@@ -102,6 +102,28 @@ fn foo() {
102 } 102 }
103 103
104 #[test] 104 #[test]
105 fn does_not_complete_non_fn_macros() {
106 check(
107 r#"
108macro_rules! m { ($e:expr) => { $e } }
109enum E { X }
110
111#[rustc_builtin_macro]
112macro Clone {}
113
114fn foo() {
115 match E::X { $0 }
116}
117"#,
118 expect![[r#"
119 ev E::X ()
120 en E
121 ma m!(…) macro_rules! m
122 "#]],
123 );
124 }
125
126 #[test]
105 fn completes_in_simple_macro_call() { 127 fn completes_in_simple_macro_call() {
106 check( 128 check(
107 r#" 129 r#"
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 86bbb58e2..9f98b21be 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -24,7 +24,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
24 } 24 }
25 25
26 let (dot_receiver, receiver_is_ambiguous_float_literal) = match &ctx.completion_location { 26 let (dot_receiver, receiver_is_ambiguous_float_literal) = match &ctx.completion_location {
27 Some(ImmediateLocation::MethodCall { receiver: Some(it) }) => (it, false), 27 Some(ImmediateLocation::MethodCall { receiver: Some(it), .. }) => (it, false),
28 Some(ImmediateLocation::FieldAccess { 28 Some(ImmediateLocation::FieldAccess {
29 receiver: Some(it), 29 receiver: Some(it),
30 receiver_is_ambiguous_float_literal, 30 receiver_is_ambiguous_float_literal,
@@ -34,7 +34,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
34 34
35 let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal); 35 let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal);
36 36
37 let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { 37 let receiver_ty = match ctx.sema.type_of_expr(dot_receiver) {
38 Some(it) => it, 38 Some(it) => it,
39 None => return, 39 None => return,
40 }; 40 };
@@ -50,7 +50,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
50 postfix_snippet( 50 postfix_snippet(
51 ctx, 51 ctx,
52 cap, 52 cap,
53 &dot_receiver, 53 dot_receiver,
54 "ifl", 54 "ifl",
55 "if let Ok {}", 55 "if let Ok {}",
56 &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), 56 &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text),
@@ -60,7 +60,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
60 postfix_snippet( 60 postfix_snippet(
61 ctx, 61 ctx,
62 cap, 62 cap,
63 &dot_receiver, 63 dot_receiver,
64 "while", 64 "while",
65 "while let Ok {}", 65 "while let Ok {}",
66 &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), 66 &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text),
@@ -71,7 +71,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
71 postfix_snippet( 71 postfix_snippet(
72 ctx, 72 ctx,
73 cap, 73 cap,
74 &dot_receiver, 74 dot_receiver,
75 "ifl", 75 "ifl",
76 "if let Some {}", 76 "if let Some {}",
77 &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), 77 &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text),
@@ -81,7 +81,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
81 postfix_snippet( 81 postfix_snippet(
82 ctx, 82 ctx,
83 cap, 83 cap,
84 &dot_receiver, 84 dot_receiver,
85 "while", 85 "while",
86 "while let Some {}", 86 "while let Some {}",
87 &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), 87 &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text),
@@ -93,7 +93,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
93 postfix_snippet( 93 postfix_snippet(
94 ctx, 94 ctx,
95 cap, 95 cap,
96 &dot_receiver, 96 dot_receiver,
97 "if", 97 "if",
98 "if expr {}", 98 "if expr {}",
99 &format!("if {} {{\n $0\n}}", receiver_text), 99 &format!("if {} {{\n $0\n}}", receiver_text),
@@ -102,22 +102,22 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
102 postfix_snippet( 102 postfix_snippet(
103 ctx, 103 ctx,
104 cap, 104 cap,
105 &dot_receiver, 105 dot_receiver,
106 "while", 106 "while",
107 "while expr {}", 107 "while expr {}",
108 &format!("while {} {{\n $0\n}}", receiver_text), 108 &format!("while {} {{\n $0\n}}", receiver_text),
109 ) 109 )
110 .add_to(acc); 110 .add_to(acc);
111 postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) 111 postfix_snippet(ctx, cap, dot_receiver, "not", "!expr", &format!("!{}", receiver_text))
112 .add_to(acc); 112 .add_to(acc);
113 } 113 }
114 114
115 postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) 115 postfix_snippet(ctx, cap, dot_receiver, "ref", "&expr", &format!("&{}", receiver_text))
116 .add_to(acc); 116 .add_to(acc);
117 postfix_snippet( 117 postfix_snippet(
118 ctx, 118 ctx,
119 cap, 119 cap,
120 &dot_receiver, 120 dot_receiver,
121 "refm", 121 "refm",
122 "&mut expr", 122 "&mut expr",
123 &format!("&mut {}", receiver_text), 123 &format!("&mut {}", receiver_text),
diff --git a/crates/ide_completion/src/completions/postfix/format_like.rs b/crates/ide_completion/src/completions/postfix/format_like.rs
index 0dcb3e898..2dc13c293 100644
--- a/crates/ide_completion/src/completions/postfix/format_like.rs
+++ b/crates/ide_completion/src/completions/postfix/format_like.rs
@@ -4,15 +4,15 @@
4// 4//
5// The following postfix snippets are available: 5// The following postfix snippets are available:
6// 6//
7// - `format` -> `format!(...)` 7// * `format` -> `format!(...)`
8// - `panic` -> `panic!(...)` 8// * `panic` -> `panic!(...)`
9// - `println` -> `println!(...)` 9// * `println` -> `println!(...)`
10// - `log`: 10// * `log`:
11// + `logd` -> `log::debug!(...)` 11// ** `logd` -> `log::debug!(...)`
12// + `logt` -> `log::trace!(...)` 12// ** `logt` -> `log::trace!(...)`
13// + `logi` -> `log::info!(...)` 13// ** `logi` -> `log::info!(...)`
14// + `logw` -> `log::warn!(...)` 14// ** `logw` -> `log::warn!(...)`
15// + `loge` -> `log::error!(...)` 15// ** `loge` -> `log::error!(...)`
16// 16//
17// image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[] 17// image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[]
18 18
@@ -53,7 +53,7 @@ pub(crate) fn add_format_like_completions(
53 for (label, macro_name) in KINDS { 53 for (label, macro_name) in KINDS {
54 let snippet = parser.into_suggestion(macro_name); 54 let snippet = parser.into_suggestion(macro_name);
55 55
56 postfix_snippet(ctx, cap, &dot_receiver, label, macro_name, &snippet).add_to(acc); 56 postfix_snippet(ctx, cap, dot_receiver, label, macro_name, &snippet).add_to(acc);
57 } 57 }
58 } 58 }
59} 59}
@@ -91,7 +91,7 @@ enum State {
91impl FormatStrParser { 91impl FormatStrParser {
92 pub(crate) fn new(input: String) -> Self { 92 pub(crate) fn new(input: String) -> Self {
93 Self { 93 Self {
94 input: input, 94 input,
95 output: String::new(), 95 output: String::new(),
96 extracted_expressions: Vec::new(), 96 extracted_expressions: Vec::new(),
97 state: State::NotExpr, 97 state: State::NotExpr,
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index de58ce1cd..6083537b7 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -7,25 +7,28 @@ use syntax::AstNode;
7use crate::{CompletionContext, Completions}; 7use crate::{CompletionContext, Completions};
8 8
9pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { 9pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) {
10 if ctx.is_path_disallowed() || ctx.expects_item() { 10 if ctx.is_path_disallowed() {
11 return; 11 return;
12 } 12 }
13 let path = match &ctx.path_qual { 13 let path = match ctx.path_qual() {
14 Some(path) => path.clone(), 14 Some(path) => path,
15 None => return, 15 None => return,
16 }; 16 };
17 17
18 let resolution = match ctx.sema.resolve_path(&path) { 18 let resolution = match ctx.sema.resolve_path(path) {
19 Some(res) => res, 19 Some(res) => res,
20 None => return, 20 None => return,
21 }; 21 };
22 let context_module = ctx.scope.module(); 22 let context_module = ctx.scope.module();
23 if ctx.expects_assoc_item() { 23
24 if ctx.expects_item() || ctx.expects_assoc_item() {
24 if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution { 25 if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
25 let module_scope = module.scope(ctx.db, context_module); 26 let module_scope = module.scope(ctx.db, context_module);
26 for (name, def) in module_scope { 27 for (name, def) in module_scope {
27 if let hir::ScopeDef::MacroDef(macro_def) = def { 28 if let hir::ScopeDef::MacroDef(macro_def) = def {
28 acc.add_macro(ctx, Some(name.clone()), macro_def); 29 if macro_def.is_fn_like() {
30 acc.add_macro(ctx, Some(name.clone()), macro_def);
31 }
29 } 32 }
30 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { 33 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
31 acc.add_resolution(ctx, name, &def); 34 acc.add_resolution(ctx, name, &def);
@@ -57,6 +60,13 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
57 } 60 }
58 } 61 }
59 62
63 if let hir::ScopeDef::MacroDef(macro_def) = def {
64 if !macro_def.is_fn_like() {
65 // Don't suggest attribute macros and derives.
66 continue;
67 }
68 }
69
60 acc.add_resolution(ctx, name, &def); 70 acc.add_resolution(ctx, name, &def);
61 } 71 }
62 } 72 }
@@ -198,6 +208,36 @@ mod tests {
198 } 208 }
199 209
200 #[test] 210 #[test]
211 fn dont_complete_values_in_type_pos() {
212 check(
213 r#"
214const FOO: () = ();
215static BAR: () = ();
216struct Baz;
217fn foo() {
218 let _: self::$0;
219}
220"#,
221 expect![[r#"
222 st Baz
223 "#]],
224 );
225 }
226
227 #[test]
228 fn dont_complete_enum_variants_in_type_pos() {
229 check(
230 r#"
231enum Foo { Bar }
232fn foo() {
233 let _: Foo::$0;
234}
235"#,
236 expect![[r#""#]],
237 );
238 }
239
240 #[test]
201 fn dont_complete_current_use_in_braces_with_glob() { 241 fn dont_complete_current_use_in_braces_with_glob() {
202 check( 242 check(
203 r#" 243 r#"
@@ -617,6 +657,32 @@ fn main() { let _ = crate::$0 }
617 } 657 }
618 658
619 #[test] 659 #[test]
660 fn does_not_complete_non_fn_macros() {
661 check(
662 r#"
663mod m {
664 #[rustc_builtin_macro]
665 pub macro Clone {}
666}
667
668fn f() {m::$0}
669"#,
670 expect![[r#""#]],
671 );
672 check(
673 r#"
674mod m {
675 #[rustc_builtin_macro]
676 pub macro bench {}
677}
678
679fn f() {m::$0}
680"#,
681 expect![[r#""#]],
682 );
683 }
684
685 #[test]
620 fn completes_in_assoc_item_list() { 686 fn completes_in_assoc_item_list() {
621 check( 687 check(
622 r#" 688 r#"
@@ -631,17 +697,17 @@ impl MyStruct {
631"#, 697"#,
632 expect![[r##" 698 expect![[r##"
633 md bar 699 md bar
634 ma foo! #[macro_export] macro_rules! foo 700 ma foo!(…) #[macro_export] macro_rules! foo
635 "##]], 701 "##]],
636 ); 702 );
637 } 703 }
638 704
639 #[test] 705 #[test]
640 #[ignore] // FIXME doesn't complete anything atm
641 fn completes_in_item_list() { 706 fn completes_in_item_list() {
642 check( 707 check(
643 r#" 708 r#"
644struct MyStruct {} 709struct MyStruct {}
710#[macro_export]
645macro_rules! foo {} 711macro_rules! foo {}
646mod bar {} 712mod bar {}
647 713
@@ -649,7 +715,7 @@ crate::$0
649"#, 715"#,
650 expect![[r#" 716 expect![[r#"
651 md bar 717 md bar
652 ma foo! macro_rules! foo 718 ma foo!(…) #[macro_export] macro_rules! foo
653 "#]], 719 "#]],
654 ) 720 )
655 } 721 }
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index 6e6a6eb92..b9862de67 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -3,8 +3,8 @@
3use ide_db::helpers::SnippetCap; 3use ide_db::helpers::SnippetCap;
4 4
5use crate::{ 5use crate::{
6 item::Builder, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, 6 context::PathCompletionContext, item::Builder, CompletionContext, CompletionItem,
7 Completions, 7 CompletionItemKind, CompletionKind, Completions,
8}; 8};
9 9
10fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder { 10fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str) -> Builder {
@@ -14,15 +14,21 @@ fn snippet(ctx: &CompletionContext, cap: SnippetCap, label: &str, snippet: &str)
14} 14}
15 15
16pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) { 16pub(crate) fn complete_expr_snippet(acc: &mut Completions, ctx: &CompletionContext) {
17 if !(ctx.is_trivial_path && ctx.function_def.is_some()) { 17 if ctx.function_def.is_none() {
18 return; 18 return;
19 } 19 }
20
21 let can_be_stmt = match ctx.path_context {
22 Some(PathCompletionContext { is_trivial_path: true, can_be_stmt, .. }) => can_be_stmt,
23 _ => return,
24 };
25
20 let cap = match ctx.config.snippet_cap { 26 let cap = match ctx.config.snippet_cap {
21 Some(it) => it, 27 Some(it) => it,
22 None => return, 28 None => return,
23 }; 29 };
24 30
25 if ctx.can_be_stmt { 31 if can_be_stmt {
26 snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc); 32 snippet(ctx, cap, "pd", "eprintln!(\"$0 = {:?}\", $0);").add_to(acc);
27 snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc); 33 snippet(ctx, cap, "ppd", "eprintln!(\"$0 = {:#?}\", $0);").add_to(acc);
28 } 34 }
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index 968c0254d..a60e5f43c 100644
--- a/crates/ide_completion/src/completions/trait_impl.rs
+++ b/crates/ide_completion/src/completions/trait_impl.rs
@@ -34,20 +34,13 @@
34use hir::{self, HasAttrs, HasSource}; 34use hir::{self, HasAttrs, HasSource};
35use ide_db::{traits::get_missing_assoc_items, SymbolKind}; 35use ide_db::{traits::get_missing_assoc_items, SymbolKind};
36use syntax::{ 36use syntax::{
37 ast::{self, edit, Impl}, 37 ast::{self, edit},
38 display::function_declaration, 38 display::function_declaration,
39 AstNode, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, T, 39 AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, T,
40}; 40};
41use text_edit::TextEdit; 41use text_edit::TextEdit;
42 42
43use crate::{ 43use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
44 CompletionContext,
45 CompletionItem,
46 CompletionItemKind,
47 CompletionKind,
48 Completions,
49 // display::function_declaration,
50};
51 44
52#[derive(Debug, PartialEq, Eq)] 45#[derive(Debug, PartialEq, Eq)]
53enum ImplCompletionKind { 46enum ImplCompletionKind {
@@ -58,7 +51,7 @@ enum ImplCompletionKind {
58} 51}
59 52
60pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { 53pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) {
61 if let Some((kind, trigger, impl_def)) = completion_match(ctx) { 54 if let Some((kind, trigger, impl_def)) = completion_match(ctx.token.clone()) {
62 get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item { 55 get_missing_assoc_items(&ctx.sema, &impl_def).into_iter().for_each(|item| match item {
63 hir::AssocItem::Function(fn_item) 56 hir::AssocItem::Function(fn_item)
64 if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn => 57 if kind == ImplCompletionKind::All || kind == ImplCompletionKind::Fn =>
@@ -80,8 +73,7 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext
80 } 73 }
81} 74}
82 75
83fn completion_match(ctx: &CompletionContext) -> Option<(ImplCompletionKind, SyntaxNode, Impl)> { 76fn completion_match(mut token: SyntaxToken) -> Option<(ImplCompletionKind, SyntaxNode, ast::Impl)> {
84 let mut token = ctx.token.clone();
85 // For keyword without name like `impl .. { fn $0 }`, the current position is inside 77 // For keyword without name like `impl .. { fn $0 }`, the current position is inside
86 // the whitespace token, which is outside `FN` syntax node. 78 // the whitespace token, which is outside `FN` syntax node.
87 // We need to follow the previous token in this case. 79 // We need to follow the previous token in this case.
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index bd955aa85..952f052a1 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -1,30 +1,32 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use hir::ScopeDef; 3use hir::ScopeDef;
4use syntax::{ast, AstNode};
4 5
5use crate::{CompletionContext, Completions}; 6use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
6 7
7pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 8pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
8 if !ctx.is_trivial_path { 9 if ctx.is_path_disallowed() || !ctx.is_trivial_path() {
9 return;
10 }
11 if ctx.is_path_disallowed() || ctx.expects_item() {
12 return; 10 return;
13 } 11 }
14 12
15 if ctx.expects_assoc_item() { 13 if ctx.expects_item() || ctx.expects_assoc_item() {
16 ctx.scope.process_all_names(&mut |name, def| { 14 // only show macros in {Assoc}ItemList
17 if let ScopeDef::MacroDef(macro_def) = def { 15 ctx.scope.process_all_names(&mut |name, res| {
18 acc.add_macro(ctx, Some(name.clone()), macro_def); 16 if let hir::ScopeDef::MacroDef(mac) = res {
17 if mac.is_fn_like() {
18 acc.add_macro(ctx, Some(name.clone()), mac);
19 }
19 } 20 }
20 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def { 21 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
21 acc.add_resolution(ctx, name, &def); 22 acc.add_resolution(ctx, name, &res);
22 } 23 }
23 }); 24 });
24 return; 25 return;
25 } 26 }
26 27
27 if ctx.expects_use_tree() { 28 if ctx.expects_use_tree() {
29 // only show modules in a fresh UseTree
28 cov_mark::hit!(only_completes_modules_in_import); 30 cov_mark::hit!(only_completes_modules_in_import);
29 ctx.scope.process_all_names(&mut |name, res| { 31 ctx.scope.process_all_names(&mut |name, res| {
30 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res { 32 if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
@@ -42,12 +44,32 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
42 }); 44 });
43 } 45 }
44 46
47 if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location {
48 if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) {
49 if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) =
50 ctx.sema.resolve_path(&path_seg.parent_path())
51 {
52 trait_.items(ctx.sema.db).into_iter().for_each(|it| {
53 if let hir::AssocItem::TypeAlias(alias) = it {
54 acc.add_type_alias_with_eq(ctx, alias)
55 }
56 });
57 }
58 }
59 }
60
45 ctx.scope.process_all_names(&mut |name, res| { 61 ctx.scope.process_all_names(&mut |name, res| {
46 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { 62 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
47 cov_mark::hit!(skip_lifetime_completion); 63 cov_mark::hit!(skip_lifetime_completion);
48 return; 64 return;
49 } 65 }
50 acc.add_resolution(ctx, name, &res); 66 let add_resolution = match res {
67 ScopeDef::MacroDef(mac) => mac.is_fn_like(),
68 _ => true,
69 };
70 if add_resolution {
71 acc.add_resolution(ctx, name, &res);
72 }
51 }); 73 });
52} 74}
53 75
@@ -70,6 +92,28 @@ mod tests {
70 } 92 }
71 93
72 #[test] 94 #[test]
95 fn dont_complete_values_in_type_pos() {
96 check(
97 r#"
98const FOO: () = ();
99static BAR: () = ();
100enum Foo {
101 Bar
102}
103struct Baz;
104fn foo() {
105 let local = ();
106 let _: $0;
107}
108"#,
109 expect![[r#"
110 en Foo
111 st Baz
112 "#]],
113 );
114 }
115
116 #[test]
73 fn only_completes_modules_in_import() { 117 fn only_completes_modules_in_import() {
74 cov_mark::check!(only_completes_modules_in_import); 118 cov_mark::check!(only_completes_modules_in_import);
75 check( 119 check(
@@ -340,7 +384,6 @@ fn x() -> $0
340"#, 384"#,
341 expect![[r#" 385 expect![[r#"
342 st Foo 386 st Foo
343 fn x() fn()
344 "#]], 387 "#]],
345 ); 388 );
346 } 389 }
@@ -392,7 +435,6 @@ pub mod prelude {
392} 435}
393"#, 436"#,
394 expect![[r#" 437 expect![[r#"
395 fn foo() fn()
396 md std 438 md std
397 st Option 439 st Option
398 "#]], 440 "#]],
@@ -428,6 +470,44 @@ mod macros {
428 } 470 }
429 471
430 #[test] 472 #[test]
473 fn does_not_complete_non_fn_macros() {
474 check(
475 r#"
476#[rustc_builtin_macro]
477pub macro Clone {}
478
479fn f() {$0}
480"#,
481 expect![[r#"
482 fn f() fn()
483 "#]],
484 );
485 check(
486 r#"
487#[rustc_builtin_macro]
488pub macro Clone {}
489
490struct S;
491impl S {
492 $0
493}
494"#,
495 expect![[r#""#]],
496 );
497 check(
498 r#"
499#[rustc_builtin_macro]
500pub macro bench {}
501
502fn f() {$0}
503"#,
504 expect![[r#"
505 fn f() fn()
506 "#]],
507 );
508 }
509
510 #[test]
431 fn completes_std_prelude_if_core_is_defined() { 511 fn completes_std_prelude_if_core_is_defined() {
432 check( 512 check(
433 r#" 513 r#"
@@ -449,7 +529,6 @@ pub mod prelude {
449} 529}
450"#, 530"#,
451 expect![[r#" 531 expect![[r#"
452 fn foo() fn()
453 md std 532 md std
454 md core 533 md core
455 st String 534 st String
@@ -510,7 +589,6 @@ macro_rules! foo { () => {} }
510fn main() { let x: $0 } 589fn main() { let x: $0 }
511"#, 590"#,
512 expect![[r#" 591 expect![[r#"
513 fn main() fn()
514 ma foo!(…) macro_rules! foo 592 ma foo!(…) macro_rules! foo
515 "#]], 593 "#]],
516 ); 594 );
@@ -693,12 +771,11 @@ impl MyStruct {
693"#, 771"#,
694 expect![[r#" 772 expect![[r#"
695 md bar 773 md bar
696 ma foo! macro_rules! foo 774 ma foo!(…) macro_rules! foo
697 "#]], 775 "#]],
698 ) 776 )
699 } 777 }
700 778
701 // FIXME: The completions here currently come from `macro_in_item_position`, but they shouldn't
702 #[test] 779 #[test]
703 fn completes_in_item_list() { 780 fn completes_in_item_list() {
704 check( 781 check(
@@ -715,4 +792,21 @@ $0
715 "#]], 792 "#]],
716 ) 793 )
717 } 794 }
795
796 #[test]
797 fn completes_assoc_types_in_dynimpl_trait() {
798 check(
799 r#"
800trait Foo {
801 type Bar;
802}
803
804fn foo(_: impl Foo<B$0>) {}
805"#,
806 expect![[r#"
807 ta Bar = type Bar;
808 tt Foo
809 "#]],
810 );
811 }
718} 812}
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 6f685c02f..4c3929a26 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -29,6 +29,34 @@ pub(crate) enum PatternRefutability {
29 Irrefutable, 29 Irrefutable,
30} 30}
31 31
32#[derive(Debug)]
33pub(super) enum PathKind {
34 Expr,
35 Type,
36}
37
38#[derive(Debug)]
39pub(crate) struct PathCompletionContext {
40 /// If this is a call with () already there
41 call_kind: Option<CallKind>,
42 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
43 pub(super) is_trivial_path: bool,
44 /// If not a trivial path, the prefix (qualifier).
45 pub(super) qualifier: Option<ast::Path>,
46 pub(super) kind: Option<PathKind>,
47 /// Whether the path segment has type args or not.
48 pub(super) has_type_args: bool,
49 /// `true` if we are a statement or a last expr in the block.
50 pub(super) can_be_stmt: bool,
51 pub(super) in_loop_body: bool,
52}
53
54#[derive(Copy, Clone, Debug, PartialEq, Eq)]
55pub(crate) enum CallKind {
56 Pat,
57 Mac,
58 Expr,
59}
32/// `CompletionContext` is created early during completion to figure out, where 60/// `CompletionContext` is created early during completion to figure out, where
33/// exactly is the cursor, syntax-wise. 61/// exactly is the cursor, syntax-wise.
34#[derive(Debug)] 62#[derive(Debug)]
@@ -45,14 +73,13 @@ pub(crate) struct CompletionContext<'a> {
45 pub(super) krate: Option<hir::Crate>, 73 pub(super) krate: Option<hir::Crate>,
46 pub(super) expected_name: Option<NameOrNameRef>, 74 pub(super) expected_name: Option<NameOrNameRef>,
47 pub(super) expected_type: Option<Type>, 75 pub(super) expected_type: Option<Type>,
48 pub(super) name_ref_syntax: Option<ast::NameRef>,
49
50 pub(super) use_item_syntax: Option<ast::Use>,
51 76
52 /// The parent function of the cursor position if it exists. 77 /// The parent function of the cursor position if it exists.
53 pub(super) function_def: Option<ast::Fn>, 78 pub(super) function_def: Option<ast::Fn>,
54 /// The parent impl of the cursor position if it exists. 79 /// The parent impl of the cursor position if it exists.
55 pub(super) impl_def: Option<ast::Impl>, 80 pub(super) impl_def: Option<ast::Impl>,
81 pub(super) name_ref_syntax: Option<ast::NameRef>,
82 pub(super) use_item_syntax: Option<ast::Use>,
56 83
57 // potentially set if we are completing a lifetime 84 // potentially set if we are completing a lifetime
58 pub(super) lifetime_syntax: Option<ast::Lifetime>, 85 pub(super) lifetime_syntax: Option<ast::Lifetime>,
@@ -67,29 +94,12 @@ pub(crate) struct CompletionContext<'a> {
67 pub(super) completion_location: Option<ImmediateLocation>, 94 pub(super) completion_location: Option<ImmediateLocation>,
68 pub(super) prev_sibling: Option<ImmediatePrevSibling>, 95 pub(super) prev_sibling: Option<ImmediatePrevSibling>,
69 pub(super) attribute_under_caret: Option<ast::Attr>, 96 pub(super) attribute_under_caret: Option<ast::Attr>,
97 pub(super) previous_token: Option<SyntaxToken>,
70 98
71 /// FIXME: `ActiveParameter` is string-based, which is very very wrong 99 pub(super) path_context: Option<PathCompletionContext>,
72 pub(super) active_parameter: Option<ActiveParameter>, 100 pub(super) active_parameter: Option<ActiveParameter>,
73 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
74 pub(super) is_trivial_path: bool,
75 /// If not a trivial path, the prefix (qualifier).
76 pub(super) path_qual: Option<ast::Path>,
77 /// `true` if we are a statement or a last expr in the block.
78 pub(super) can_be_stmt: bool,
79 /// `true` if we expect an expression at the cursor position.
80 pub(super) is_expr: bool,
81 /// If this is a call (method or function) in particular, i.e. the () are already there.
82 pub(super) is_call: bool,
83 /// Like `is_call`, but for tuple patterns.
84 pub(super) is_pattern_call: bool,
85 /// If this is a macro call, i.e. the () are already there.
86 pub(super) is_macro_call: bool,
87 pub(super) is_path_type: bool,
88 pub(super) has_type_args: bool,
89 pub(super) locals: Vec<(String, Local)>, 101 pub(super) locals: Vec<(String, Local)>,
90 102
91 pub(super) previous_token: Option<SyntaxToken>,
92 pub(super) in_loop_body: bool,
93 pub(super) incomplete_let: bool, 103 pub(super) incomplete_let: bool,
94 104
95 no_completion_required: bool, 105 no_completion_required: bool,
@@ -136,36 +146,27 @@ impl<'a> CompletionContext<'a> {
136 original_token, 146 original_token,
137 token, 147 token,
138 krate, 148 krate,
139 lifetime_allowed: false,
140 expected_name: None, 149 expected_name: None,
141 expected_type: None, 150 expected_type: None,
151 function_def: None,
152 impl_def: None,
142 name_ref_syntax: None, 153 name_ref_syntax: None,
154 use_item_syntax: None,
143 lifetime_syntax: None, 155 lifetime_syntax: None,
144 lifetime_param_syntax: None, 156 lifetime_param_syntax: None,
145 function_def: None, 157 lifetime_allowed: false,
146 use_item_syntax: None,
147 impl_def: None,
148 active_parameter: ActiveParameter::at(db, position),
149 is_label_ref: false, 158 is_label_ref: false,
150 is_param: false,
151 is_pat_or_const: None, 159 is_pat_or_const: None,
152 is_trivial_path: false, 160 is_param: false,
153 path_qual: None,
154 can_be_stmt: false,
155 is_expr: false,
156 is_call: false,
157 is_pattern_call: false,
158 is_macro_call: false,
159 is_path_type: false,
160 has_type_args: false,
161 previous_token: None,
162 in_loop_body: false,
163 completion_location: None, 161 completion_location: None,
164 prev_sibling: None, 162 prev_sibling: None,
165 no_completion_required: false,
166 incomplete_let: false,
167 attribute_under_caret: None, 163 attribute_under_caret: None,
164 previous_token: None,
165 path_context: None,
166 active_parameter: ActiveParameter::at(db, position),
168 locals, 167 locals,
168 incomplete_let: false,
169 no_completion_required: false,
169 }; 170 };
170 171
171 let mut original_file = original_file.syntax().clone(); 172 let mut original_file = original_file.syntax().clone();
@@ -250,14 +251,14 @@ impl<'a> CompletionContext<'a> {
250 pub(crate) fn has_dot_receiver(&self) -> bool { 251 pub(crate) fn has_dot_receiver(&self) -> bool {
251 matches!( 252 matches!(
252 &self.completion_location, 253 &self.completion_location,
253 Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver }) 254 Some(ImmediateLocation::FieldAccess { receiver, .. }) | Some(ImmediateLocation::MethodCall { receiver,.. })
254 if receiver.is_some() 255 if receiver.is_some()
255 ) 256 )
256 } 257 }
257 258
258 pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> { 259 pub(crate) fn dot_receiver(&self) -> Option<&ast::Expr> {
259 match &self.completion_location { 260 match &self.completion_location {
260 Some(ImmediateLocation::MethodCall { receiver }) 261 Some(ImmediateLocation::MethodCall { receiver, .. })
261 | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(), 262 | Some(ImmediateLocation::FieldAccess { receiver, .. }) => receiver.as_ref(),
262 _ => None, 263 _ => None,
263 } 264 }
@@ -275,11 +276,6 @@ impl<'a> CompletionContext<'a> {
275 matches!(self.completion_location, Some(ImmediateLocation::ItemList)) 276 matches!(self.completion_location, Some(ImmediateLocation::ItemList))
276 } 277 }
277 278
278 // fn expects_value(&self) -> bool {
279 pub(crate) fn expects_expression(&self) -> bool {
280 self.is_expr
281 }
282
283 pub(crate) fn has_block_expr_parent(&self) -> bool { 279 pub(crate) fn has_block_expr_parent(&self) -> bool {
284 matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) 280 matches!(self.completion_location, Some(ImmediateLocation::BlockExpr))
285 } 281 }
@@ -316,6 +312,26 @@ impl<'a> CompletionContext<'a> {
316 ) || self.attribute_under_caret.is_some() 312 ) || self.attribute_under_caret.is_some()
317 } 313 }
318 314
315 pub(crate) fn expects_expression(&self) -> bool {
316 matches!(self.path_context, Some(PathCompletionContext { kind: Some(PathKind::Expr), .. }))
317 }
318
319 pub(crate) fn expects_type(&self) -> bool {
320 matches!(self.path_context, Some(PathCompletionContext { kind: Some(PathKind::Type), .. }))
321 }
322
323 pub(crate) fn path_call_kind(&self) -> Option<CallKind> {
324 self.path_context.as_ref().and_then(|it| it.call_kind)
325 }
326
327 pub(crate) fn is_trivial_path(&self) -> bool {
328 matches!(self.path_context, Some(PathCompletionContext { is_trivial_path: true, .. }))
329 }
330
331 pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
332 self.path_context.as_ref().and_then(|it| it.qualifier.as_ref())
333 }
334
319 fn fill_impl_def(&mut self) { 335 fn fill_impl_def(&mut self) {
320 self.impl_def = self 336 self.impl_def = self
321 .sema 337 .sema
@@ -364,7 +380,7 @@ impl<'a> CompletionContext<'a> {
364 (|| { 380 (|| {
365 let expr_field = self.token.prev_sibling_or_token()? 381 let expr_field = self.token.prev_sibling_or_token()?
366 .into_node() 382 .into_node()
367 .and_then(|node| ast::RecordExprField::cast(node))?; 383 .and_then(ast::RecordExprField::cast)?;
368 let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?; 384 let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?;
369 Some(( 385 Some((
370 Some(ty), 386 Some(ty),
@@ -441,7 +457,6 @@ impl<'a> CompletionContext<'a> {
441 let for_is_prev2 = for_is_prev2(syntax_element.clone()); 457 let for_is_prev2 = for_is_prev2(syntax_element.clone());
442 (fn_is_prev && !inside_impl_trait_block) || for_is_prev2 458 (fn_is_prev && !inside_impl_trait_block) || for_is_prev2
443 }; 459 };
444 self.in_loop_body = is_in_loop_body(syntax_element.clone());
445 460
446 self.incomplete_let = 461 self.incomplete_let =
447 syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| { 462 syntax_element.ancestors().take(6).find_map(ast::LetStmt::cast).map_or(false, |it| {
@@ -452,7 +467,7 @@ impl<'a> CompletionContext<'a> {
452 self.expected_type = expected_type; 467 self.expected_type = expected_type;
453 self.expected_name = expected_name; 468 self.expected_name = expected_name;
454 469
455 let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) { 470 let name_like = match find_node_at_offset(&file_with_fake_ident, offset) {
456 Some(it) => it, 471 Some(it) => it,
457 None => return, 472 None => return,
458 }; 473 };
@@ -549,10 +564,6 @@ impl<'a> CompletionContext<'a> {
549 self.name_ref_syntax = 564 self.name_ref_syntax =
550 find_node_at_offset(original_file, name_ref.syntax().text_range().start()); 565 find_node_at_offset(original_file, name_ref.syntax().text_range().start());
551 566
552 if matches!(self.completion_location, Some(ImmediateLocation::ItemList)) {
553 return;
554 }
555
556 self.use_item_syntax = 567 self.use_item_syntax =
557 self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast); 568 self.sema.token_ancestors_with_macros(self.token.clone()).find_map(ast::Use::cast);
558 569
@@ -567,23 +578,43 @@ impl<'a> CompletionContext<'a> {
567 None => return, 578 None => return,
568 }; 579 };
569 580
570 if let Some(segment) = ast::PathSegment::cast(parent.clone()) { 581 if let Some(segment) = ast::PathSegment::cast(parent) {
582 let path_ctx = self.path_context.get_or_insert(PathCompletionContext {
583 call_kind: None,
584 is_trivial_path: false,
585 qualifier: None,
586 has_type_args: false,
587 can_be_stmt: false,
588 in_loop_body: false,
589 kind: None,
590 });
591 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
571 let path = segment.parent_path(); 592 let path = segment.parent_path();
572 self.is_call = path
573 .syntax()
574 .parent()
575 .and_then(ast::PathExpr::cast)
576 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
577 .is_some();
578 self.is_macro_call = path.syntax().parent().and_then(ast::MacroCall::cast).is_some();
579 self.is_pattern_call =
580 path.syntax().parent().and_then(ast::TupleStructPat::cast).is_some();
581 593
582 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 594 if let Some(p) = path.syntax().parent() {
583 self.has_type_args = segment.generic_arg_list().is_some(); 595 path_ctx.call_kind = match_ast! {
596 match p {
597 ast::PathExpr(it) => it.syntax().parent().and_then(ast::CallExpr::cast).map(|_| CallKind::Expr),
598 ast::MacroCall(it) => it.excl_token().and(Some(CallKind::Mac)),
599 ast::TupleStructPat(_it) => Some(CallKind::Pat),
600 _ => None
601 }
602 };
603 }
604
605 if let Some(parent) = path.syntax().parent() {
606 path_ctx.kind = match_ast! {
607 match parent {
608 ast::PathType(_it) => Some(PathKind::Type),
609 ast::PathExpr(_it) => Some(PathKind::Expr),
610 _ => None,
611 }
612 };
613 }
614 path_ctx.has_type_args = segment.generic_arg_list().is_some();
584 615
585 if let Some(path) = path_or_use_tree_qualifier(&path) { 616 if let Some(path) = path_or_use_tree_qualifier(&path) {
586 self.path_qual = path 617 path_ctx.qualifier = path
587 .segment() 618 .segment()
588 .and_then(|it| { 619 .and_then(|it| {
589 find_node_with_range::<ast::PathSegment>( 620 find_node_with_range::<ast::PathSegment>(
@@ -601,11 +632,11 @@ impl<'a> CompletionContext<'a> {
601 } 632 }
602 } 633 }
603 634
604 self.is_trivial_path = true; 635 path_ctx.is_trivial_path = true;
605 636
606 // Find either enclosing expr statement (thing with `;`) or a 637 // Find either enclosing expr statement (thing with `;`) or a
607 // block. If block, check that we are the last expr. 638 // block. If block, check that we are the last expr.
608 self.can_be_stmt = name_ref 639 path_ctx.can_be_stmt = name_ref
609 .syntax() 640 .syntax()
610 .ancestors() 641 .ancestors()
611 .find_map(|node| { 642 .find_map(|node| {
@@ -621,10 +652,7 @@ impl<'a> CompletionContext<'a> {
621 None 652 None
622 }) 653 })
623 .unwrap_or(false); 654 .unwrap_or(false);
624 self.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
625 } 655 }
626 self.is_call |=
627 matches!(self.completion_location, Some(ImmediateLocation::MethodCall { .. }));
628 } 656 }
629} 657}
630 658
diff --git a/crates/ide_completion/src/generated_lint_completions.rs b/crates/ide_completion/src/generated_lint_completions.rs
deleted file mode 100644
index 0d405350d..000000000
--- a/crates/ide_completion/src/generated_lint_completions.rs
+++ /dev/null
@@ -1,6380 +0,0 @@
1//! Generated file, do not edit by hand, see `xtask/src/codegen`
2
3use crate::completions::attribute::LintCompletion;
4pub(super) const FEATURES: &[LintCompletion] = &[
5 LintCompletion {
6 label: "plugin_registrar",
7 description: r##"# `plugin_registrar`
8
9The tracking issue for this feature is: [#29597]
10
11[#29597]: https://github.com/rust-lang/rust/issues/29597
12
13This feature is part of "compiler plugins." It will often be used with the
14[`plugin`] and `rustc_private` features as well. For more details, see
15their docs.
16
17[`plugin`]: plugin.md
18
19------------------------
20"##,
21 },
22 LintCompletion {
23 label: "inline_const",
24 description: r##"# `inline_const`
25
26The tracking issue for this feature is: [#76001]
27
28------
29
30This feature allows you to use inline constant expressions. For example, you can
31turn this code:
32
33```rust
34# fn add_one(x: i32) -> i32 { x + 1 }
35const MY_COMPUTATION: i32 = 1 + 2 * 3 / 4;
36
37fn main() {
38 let x = add_one(MY_COMPUTATION);
39}
40```
41
42into this code:
43
44```rust
45#![feature(inline_const)]
46
47# fn add_one(x: i32) -> i32 { x + 1 }
48fn main() {
49 let x = add_one(const { 1 + 2 * 3 / 4 });
50}
51```
52
53You can also use inline constant expressions in patterns:
54
55```rust
56#![feature(inline_const)]
57
58const fn one() -> i32 { 1 }
59
60let some_int = 3;
61match some_int {
62 const { 1 + 2 } => println!("Matched 1 + 2"),
63 const { one() } => println!("Matched const fn returning 1"),
64 _ => println!("Didn't match anything :("),
65}
66```
67
68[#76001]: https://github.com/rust-lang/rust/issues/76001
69"##,
70 },
71 LintCompletion {
72 label: "auto_traits",
73 description: r##"# `auto_traits`
74
75The tracking issue for this feature is [#13231]
76
77[#13231]: https://github.com/rust-lang/rust/issues/13231
78
79----
80
81The `auto_traits` feature gate allows you to define auto traits.
82
83Auto traits, like [`Send`] or [`Sync`] in the standard library, are marker traits
84that are automatically implemented for every type, unless the type, or a type it contains,
85has explicitly opted out via a negative impl. (Negative impls are separately controlled
86by the `negative_impls` feature.)
87
88[`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
89[`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
90
91```rust,ignore (partial-example)
92impl !Trait for Type {}
93```
94
95Example:
96
97```rust
98#![feature(negative_impls)]
99#![feature(auto_traits)]
100
101auto trait Valid {}
102
103struct True;
104struct False;
105
106impl !Valid for False {}
107
108struct MaybeValid<T>(T);
109
110fn must_be_valid<T: Valid>(_t: T) { }
111
112fn main() {
113 // works
114 must_be_valid( MaybeValid(True) );
115
116 // compiler error - trait bound not satisfied
117 // must_be_valid( MaybeValid(False) );
118}
119```
120
121## Automatic trait implementations
122
123When a type is declared as an `auto trait`, we will automatically
124create impls for every struct/enum/union, unless an explicit impl is
125provided. These automatic impls contain a where clause for each field
126of the form `T: AutoTrait`, where `T` is the type of the field and
127`AutoTrait` is the auto trait in question. As an example, consider the
128struct `List` and the auto trait `Send`:
129
130```rust
131struct List<T> {
132 data: T,
133 next: Option<Box<List<T>>>,
134}
135```
136
137Presuming that there is no explicit impl of `Send` for `List`, the
138compiler will supply an automatic impl of the form:
139
140```rust
141struct List<T> {
142 data: T,
143 next: Option<Box<List<T>>>,
144}
145
146unsafe impl<T> Send for List<T>
147where
148 T: Send, // from the field `data`
149 Option<Box<List<T>>>: Send, // from the field `next`
150{ }
151```
152
153Explicit impls may be either positive or negative. They take the form:
154
155```rust,ignore (partial-example)
156impl<...> AutoTrait for StructName<..> { }
157impl<...> !AutoTrait for StructName<..> { }
158```
159
160## Coinduction: Auto traits permit cyclic matching
161
162Unlike ordinary trait matching, auto traits are **coinductive**. This
163means, in short, that cycles which occur in trait matching are
164considered ok. As an example, consider the recursive struct `List`
165introduced in the previous section. In attempting to determine whether
166`List: Send`, we would wind up in a cycle: to apply the impl, we must
167show that `Option<Box<List>>: Send`, which will in turn require
168`Box<List>: Send` and then finally `List: Send` again. Under ordinary
169trait matching, this cycle would be an error, but for an auto trait it
170is considered a successful match.
171
172## Items
173
174Auto traits cannot have any trait items, such as methods or associated types. This ensures that we can generate default implementations.
175
176## Supertraits
177
178Auto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile.
179"##,
180 },
181 LintCompletion {
182 label: "ffi_const",
183 description: r##"# `ffi_const`
184
185The tracking issue for this feature is: [#58328]
186
187------
188
189The `#[ffi_const]` attribute applies clang's `const` attribute to foreign
190functions declarations.
191
192That is, `#[ffi_const]` functions shall have no effects except for its return
193value, which can only depend on the values of the function parameters, and is
194not affected by changes to the observable state of the program.
195
196Applying the `#[ffi_const]` attribute to a function that violates these
197requirements is undefined behaviour.
198
199This attribute enables Rust to perform common optimizations, like sub-expression
200elimination, and it can avoid emitting some calls in repeated invocations of the
201function with the same argument values regardless of other operations being
202performed in between these functions calls (as opposed to `#[ffi_pure]`
203functions).
204
205## Pitfalls
206
207A `#[ffi_const]` function can only read global memory that would not affect
208its return value for the whole execution of the program (e.g. immutable global
209memory). `#[ffi_const]` functions are referentially-transparent and therefore
210more strict than `#[ffi_pure]` functions.
211
212A common pitfall involves applying the `#[ffi_const]` attribute to a
213function that reads memory through pointer arguments which do not necessarily
214point to immutable global memory.
215
216A `#[ffi_const]` function that returns unit has no effect on the abstract
217machine's state, and a `#[ffi_const]` function cannot be `#[ffi_pure]`.
218
219A `#[ffi_const]` function must not diverge, neither via a side effect (e.g. a
220call to `abort`) nor by infinite loops.
221
222When translating C headers to Rust FFI, it is worth verifying for which targets
223the `const` attribute is enabled in those headers, and using the appropriate
224`cfg` macros in the Rust side to match those definitions. While the semantics of
225`const` are implemented identically by many C and C++ compilers, e.g., clang,
226[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily
227implemented in this way on all of them. It is therefore also worth verifying
228that the semantics of the C toolchain used to compile the binary being linked
229against are compatible with those of the `#[ffi_const]`.
230
231[#58328]: https://github.com/rust-lang/rust/issues/58328
232[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html
233[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute
234[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm
235"##,
236 },
237 LintCompletion {
238 label: "external_doc",
239 description: r##"# `external_doc`
240
241The tracking issue for this feature is: [#44732]
242
243The `external_doc` feature allows the use of the `include` parameter to the `#[doc]` attribute, to
244include external files in documentation. Use the attribute in place of, or in addition to, regular
245doc comments and `#[doc]` attributes, and `rustdoc` will load the given file when it renders
246documentation for your crate.
247
248With the following files in the same directory:
249
250`external-doc.md`:
251
252```markdown
253# My Awesome Type
254
255This is the documentation for this spectacular type.
256```
257
258`lib.rs`:
259
260```no_run (needs-external-files)
261#![feature(external_doc)]
262
263#[doc(include = "external-doc.md")]
264pub struct MyAwesomeType;
265```
266
267`rustdoc` will load the file `external-doc.md` and use it as the documentation for the `MyAwesomeType`
268struct.
269
270When locating files, `rustdoc` will base paths in the `src/` directory, as if they were alongside the
271`lib.rs` for your crate. So if you want a `docs/` folder to live alongside the `src/` directory,
272start your paths with `../docs/` for `rustdoc` to properly find the file.
273
274This feature was proposed in [RFC #1990] and initially implemented in PR [#44781].
275
276[#44732]: https://github.com/rust-lang/rust/issues/44732
277[RFC #1990]: https://github.com/rust-lang/rfcs/pull/1990
278[#44781]: https://github.com/rust-lang/rust/pull/44781
279"##,
280 },
281 LintCompletion {
282 label: "box_patterns",
283 description: r##"# `box_patterns`
284
285The tracking issue for this feature is: [#29641]
286
287[#29641]: https://github.com/rust-lang/rust/issues/29641
288
289See also [`box_syntax`](box-syntax.md)
290
291------------------------
292
293Box patterns let you match on `Box<T>`s:
294
295
296```rust
297#![feature(box_patterns)]
298
299fn main() {
300 let b = Some(Box::new(5));
301 match b {
302 Some(box n) if n < 0 => {
303 println!("Box contains negative number {}", n);
304 },
305 Some(box n) if n >= 0 => {
306 println!("Box contains non-negative number {}", n);
307 },
308 None => {
309 println!("No box");
310 },
311 _ => unreachable!()
312 }
313}
314```
315"##,
316 },
317 LintCompletion {
318 label: "abi_c_cmse_nonsecure_call",
319 description: r##"# `abi_c_cmse_nonsecure_call`
320
321The tracking issue for this feature is: [#81391]
322
323[#81391]: https://github.com/rust-lang/rust/issues/81391
324
325------------------------
326
327The [TrustZone-M
328feature](https://developer.arm.com/documentation/100690/latest/) is available
329for targets with the Armv8-M architecture profile (`thumbv8m` in their target
330name).
331LLVM, the Rust compiler and the linker are providing
332[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the
333TrustZone-M feature.
334
335One of the things provided, with this unstable feature, is the
336`C-cmse-nonsecure-call` function ABI. This ABI is used on function pointers to
337non-secure code to mark a non-secure function call (see [section
3385.5](https://developer.arm.com/documentation/ecm0359818/latest/) for details).
339
340With this ABI, the compiler will do the following to perform the call:
341* save registers needed after the call to Secure memory
342* clear all registers that might contain confidential information
343* clear the Least Significant Bit of the function address
344* branches using the BLXNS instruction
345
346To avoid using the non-secure stack, the compiler will constrain the number and
347type of parameters/return value.
348
349The `extern "C-cmse-nonsecure-call"` ABI is otherwise equivalent to the
350`extern "C"` ABI.
351
352<!-- NOTE(ignore) this example is specific to thumbv8m targets -->
353
354``` rust,ignore
355#![no_std]
356#![feature(abi_c_cmse_nonsecure_call)]
357
358#[no_mangle]
359pub fn call_nonsecure_function(addr: usize) -> u32 {
360 let non_secure_function =
361 unsafe { core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn() -> u32>(addr) };
362 non_secure_function()
363}
364```
365
366``` text
367$ rustc --emit asm --crate-type lib --target thumbv8m.main-none-eabi function.rs
368
369call_nonsecure_function:
370 .fnstart
371 .save {r7, lr}
372 push {r7, lr}
373 .setfp r7, sp
374 mov r7, sp
375 .pad #16
376 sub sp, #16
377 str r0, [sp, #12]
378 ldr r0, [sp, #12]
379 str r0, [sp, #8]
380 b .LBB0_1
381.LBB0_1:
382 ldr r0, [sp, #8]
383 push.w {r4, r5, r6, r7, r8, r9, r10, r11}
384 bic r0, r0, #1
385 mov r1, r0
386 mov r2, r0
387 mov r3, r0
388 mov r4, r0
389 mov r5, r0
390 mov r6, r0
391 mov r7, r0
392 mov r8, r0
393 mov r9, r0
394 mov r10, r0
395 mov r11, r0
396 mov r12, r0
397 msr apsr_nzcvq, r0
398 blxns r0
399 pop.w {r4, r5, r6, r7, r8, r9, r10, r11}
400 str r0, [sp, #4]
401 b .LBB0_2
402.LBB0_2:
403 ldr r0, [sp, #4]
404 add sp, #16
405 pop {r7, pc}
406```
407"##,
408 },
409 LintCompletion {
410 label: "member_constraints",
411 description: r##"# `member_constraints`
412
413The tracking issue for this feature is: [#61997]
414
415[#61997]: https://github.com/rust-lang/rust/issues/61997
416
417------------------------
418
419The `member_constraints` feature gate lets you use `impl Trait` syntax with
420multiple unrelated lifetime parameters.
421
422A simple example is:
423
424```rust
425#![feature(member_constraints)]
426
427trait Trait<'a, 'b> { }
428impl<T> Trait<'_, '_> for T {}
429
430fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
431 (x, y)
432}
433
434fn main() { }
435```
436
437Without the `member_constraints` feature gate, the above example is an
438error because both `'a` and `'b` appear in the impl Trait bounds, but
439neither outlives the other.
440"##,
441 },
442 LintCompletion {
443 label: "allocator_internals",
444 description: r##"# `allocator_internals`
445
446This feature does not have a tracking issue, it is an unstable implementation
447detail of the `global_allocator` feature not intended for use outside the
448compiler.
449
450------------------------
451"##,
452 },
453 LintCompletion {
454 label: "cfg_sanitize",
455 description: r##"# `cfg_sanitize`
456
457The tracking issue for this feature is: [#39699]
458
459[#39699]: https://github.com/rust-lang/rust/issues/39699
460
461------------------------
462
463The `cfg_sanitize` feature makes it possible to execute different code
464depending on whether a particular sanitizer is enabled or not.
465
466## Examples
467
468```rust
469#![feature(cfg_sanitize)]
470
471#[cfg(sanitize = "thread")]
472fn a() {
473 // ...
474}
475
476#[cfg(not(sanitize = "thread"))]
477fn a() {
478 // ...
479}
480
481fn b() {
482 if cfg!(sanitize = "leak") {
483 // ...
484 } else {
485 // ...
486 }
487}
488```
489"##,
490 },
491 LintCompletion {
492 label: "cfg_panic",
493 description: r##"# `cfg_panic`
494
495The tracking issue for this feature is: [#77443]
496
497[#77443]: https://github.com/rust-lang/rust/issues/77443
498
499------------------------
500
501The `cfg_panic` feature makes it possible to execute different code
502depending on the panic strategy.
503
504Possible values at the moment are `"unwind"` or `"abort"`, although
505it is possible that new panic strategies may be added to Rust in the
506future.
507
508## Examples
509
510```rust
511#![feature(cfg_panic)]
512
513#[cfg(panic = "unwind")]
514fn a() {
515 // ...
516}
517
518#[cfg(not(panic = "unwind"))]
519fn a() {
520 // ...
521}
522
523fn b() {
524 if cfg!(panic = "abort") {
525 // ...
526 } else {
527 // ...
528 }
529}
530```
531"##,
532 },
533 LintCompletion {
534 label: "ffi_pure",
535 description: r##"# `ffi_pure`
536
537The tracking issue for this feature is: [#58329]
538
539------
540
541The `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign
542functions declarations.
543
544That is, `#[ffi_pure]` functions shall have no effects except for its return
545value, which shall not change across two consecutive function calls with
546the same parameters.
547
548Applying the `#[ffi_pure]` attribute to a function that violates these
549requirements is undefined behavior.
550
551This attribute enables Rust to perform common optimizations, like sub-expression
552elimination and loop optimizations. Some common examples of pure functions are
553`strlen` or `memcmp`.
554
555These optimizations are only applicable when the compiler can prove that no
556program state observable by the `#[ffi_pure]` function has changed between calls
557of the function, which could alter the result. See also the `#[ffi_const]`
558attribute, which provides stronger guarantees regarding the allowable behavior
559of a function, enabling further optimization.
560
561## Pitfalls
562
563A `#[ffi_pure]` function can read global memory through the function
564parameters (e.g. pointers), globals, etc. `#[ffi_pure]` functions are not
565referentially-transparent, and are therefore more relaxed than `#[ffi_const]`
566functions.
567
568However, accessing global memory through volatile or atomic reads can violate the
569requirement that two consecutive function calls shall return the same value.
570
571A `pure` function that returns unit has no effect on the abstract machine's
572state.
573
574A `#[ffi_pure]` function must not diverge, neither via a side effect (e.g. a
575call to `abort`) nor by infinite loops.
576
577When translating C headers to Rust FFI, it is worth verifying for which targets
578the `pure` attribute is enabled in those headers, and using the appropriate
579`cfg` macros in the Rust side to match those definitions. While the semantics of
580`pure` are implemented identically by many C and C++ compilers, e.g., clang,
581[GCC], [ARM C/C++ compiler], [IBM ILE C/C++], etc. they are not necessarily
582implemented in this way on all of them. It is therefore also worth verifying
583that the semantics of the C toolchain used to compile the binary being linked
584against are compatible with those of the `#[ffi_pure]`.
585
586
587[#58329]: https://github.com/rust-lang/rust/issues/58329
588[ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html
589[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute
590[IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm
591"##,
592 },
593 LintCompletion {
594 label: "repr128",
595 description: r##"# `repr128`
596
597The tracking issue for this feature is: [#56071]
598
599[#56071]: https://github.com/rust-lang/rust/issues/56071
600
601------------------------
602
603The `repr128` feature adds support for `#[repr(u128)]` on `enum`s.
604
605```rust
606#![feature(repr128)]
607
608#[repr(u128)]
609enum Foo {
610 Bar(u64),
611}
612```
613"##,
614 },
615 LintCompletion {
616 label: "generators",
617 description: r##"# `generators`
618
619The tracking issue for this feature is: [#43122]
620
621[#43122]: https://github.com/rust-lang/rust/issues/43122
622
623------------------------
624
625The `generators` feature gate in Rust allows you to define generator or
626coroutine literals. A generator is a "resumable function" that syntactically
627resembles a closure but compiles to much different semantics in the compiler
628itself. The primary feature of a generator is that it can be suspended during
629execution to be resumed at a later date. Generators use the `yield` keyword to
630"return", and then the caller can `resume` a generator to resume execution just
631after the `yield` keyword.
632
633Generators are an extra-unstable feature in the compiler right now. Added in
634[RFC 2033] they're mostly intended right now as a information/constraint
635gathering phase. The intent is that experimentation can happen on the nightly
636compiler before actual stabilization. A further RFC will be required to
637stabilize generators/coroutines and will likely contain at least a few small
638tweaks to the overall design.
639
640[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033
641
642A syntactical example of a generator is:
643
644```rust
645#![feature(generators, generator_trait)]
646
647use std::ops::{Generator, GeneratorState};
648use std::pin::Pin;
649
650fn main() {
651 let mut generator = || {
652 yield 1;
653 return "foo"
654 };
655
656 match Pin::new(&mut generator).resume(()) {
657 GeneratorState::Yielded(1) => {}
658 _ => panic!("unexpected value from resume"),
659 }
660 match Pin::new(&mut generator).resume(()) {
661 GeneratorState::Complete("foo") => {}
662 _ => panic!("unexpected value from resume"),
663 }
664}
665```
666
667Generators are closure-like literals which can contain a `yield` statement. The
668`yield` statement takes an optional expression of a value to yield out of the
669generator. All generator literals implement the `Generator` trait in the
670`std::ops` module. The `Generator` trait has one main method, `resume`, which
671resumes execution of the generator at the previous suspension point.
672
673An example of the control flow of generators is that the following example
674prints all numbers in order:
675
676```rust
677#![feature(generators, generator_trait)]
678
679use std::ops::Generator;
680use std::pin::Pin;
681
682fn main() {
683 let mut generator = || {
684 println!("2");
685 yield;
686 println!("4");
687 };
688
689 println!("1");
690 Pin::new(&mut generator).resume(());
691 println!("3");
692 Pin::new(&mut generator).resume(());
693 println!("5");
694}
695```
696
697At this time the main intended use case of generators is an implementation
698primitive for async/await syntax, but generators will likely be extended to
699ergonomic implementations of iterators and other primitives in the future.
700Feedback on the design and usage is always appreciated!
701
702### The `Generator` trait
703
704The `Generator` trait in `std::ops` currently looks like:
705
706```rust
707# #![feature(arbitrary_self_types, generator_trait)]
708# use std::ops::GeneratorState;
709# use std::pin::Pin;
710
711pub trait Generator<R = ()> {
712 type Yield;
713 type Return;
714 fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState<Self::Yield, Self::Return>;
715}
716```
717
718The `Generator::Yield` type is the type of values that can be yielded with the
719`yield` statement. The `Generator::Return` type is the returned type of the
720generator. This is typically the last expression in a generator's definition or
721any value passed to `return` in a generator. The `resume` function is the entry
722point for executing the `Generator` itself.
723
724The return value of `resume`, `GeneratorState`, looks like:
725
726```rust
727pub enum GeneratorState<Y, R> {
728 Yielded(Y),
729 Complete(R),
730}
731```
732
733The `Yielded` variant indicates that the generator can later be resumed. This
734corresponds to a `yield` point in a generator. The `Complete` variant indicates
735that the generator is complete and cannot be resumed again. Calling `resume`
736after a generator has returned `Complete` will likely result in a panic of the
737program.
738
739### Closure-like semantics
740
741The closure-like syntax for generators alludes to the fact that they also have
742closure-like semantics. Namely:
743
744* When created, a generator executes no code. A closure literal does not
745 actually execute any of the closure's code on construction, and similarly a
746 generator literal does not execute any code inside the generator when
747 constructed.
748
749* Generators can capture outer variables by reference or by move, and this can
750 be tweaked with the `move` keyword at the beginning of the closure. Like
751 closures all generators will have an implicit environment which is inferred by
752 the compiler. Outer variables can be moved into a generator for use as the
753 generator progresses.
754
755* Generator literals produce a value with a unique type which implements the
756 `std::ops::Generator` trait. This allows actual execution of the generator
757 through the `Generator::resume` method as well as also naming it in return
758 types and such.
759
760* Traits like `Send` and `Sync` are automatically implemented for a `Generator`
761 depending on the captured variables of the environment. Unlike closures,
762 generators also depend on variables live across suspension points. This means
763 that although the ambient environment may be `Send` or `Sync`, the generator
764 itself may not be due to internal variables live across `yield` points being
765 not-`Send` or not-`Sync`. Note that generators do
766 not implement traits like `Copy` or `Clone` automatically.
767
768* Whenever a generator is dropped it will drop all captured environment
769 variables.
770
771### Generators as state machines
772
773In the compiler, generators are currently compiled as state machines. Each
774`yield` expression will correspond to a different state that stores all live
775variables over that suspension point. Resumption of a generator will dispatch on
776the current state and then execute internally until a `yield` is reached, at
777which point all state is saved off in the generator and a value is returned.
778
779Let's take a look at an example to see what's going on here:
780
781```rust
782#![feature(generators, generator_trait)]
783
784use std::ops::Generator;
785use std::pin::Pin;
786
787fn main() {
788 let ret = "foo";
789 let mut generator = move || {
790 yield 1;
791 return ret
792 };
793
794 Pin::new(&mut generator).resume(());
795 Pin::new(&mut generator).resume(());
796}
797```
798
799This generator literal will compile down to something similar to:
800
801```rust
802#![feature(arbitrary_self_types, generators, generator_trait)]
803
804use std::ops::{Generator, GeneratorState};
805use std::pin::Pin;
806
807fn main() {
808 let ret = "foo";
809 let mut generator = {
810 enum __Generator {
811 Start(&'static str),
812 Yield1(&'static str),
813 Done,
814 }
815
816 impl Generator for __Generator {
817 type Yield = i32;
818 type Return = &'static str;
819
820 fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState<i32, &'static str> {
821 use std::mem;
822 match mem::replace(&mut *self, __Generator::Done) {
823 __Generator::Start(s) => {
824 *self = __Generator::Yield1(s);
825 GeneratorState::Yielded(1)
826 }
827
828 __Generator::Yield1(s) => {
829 *self = __Generator::Done;
830 GeneratorState::Complete(s)
831 }
832
833 __Generator::Done => {
834 panic!("generator resumed after completion")
835 }
836 }
837 }
838 }
839
840 __Generator::Start(ret)
841 };
842
843 Pin::new(&mut generator).resume(());
844 Pin::new(&mut generator).resume(());
845}
846```
847
848Notably here we can see that the compiler is generating a fresh type,
849`__Generator` in this case. This type has a number of states (represented here
850as an `enum`) corresponding to each of the conceptual states of the generator.
851At the beginning we're closing over our outer variable `foo` and then that
852variable is also live over the `yield` point, so it's stored in both states.
853
854When the generator starts it'll immediately yield 1, but it saves off its state
855just before it does so indicating that it has reached the yield point. Upon
856resuming again we'll execute the `return ret` which returns the `Complete`
857state.
858
859Here we can also note that the `Done` state, if resumed, panics immediately as
860it's invalid to resume a completed generator. It's also worth noting that this
861is just a rough desugaring, not a normative specification for what the compiler
862does.
863"##,
864 },
865 LintCompletion {
866 label: "non_ascii_idents",
867 description: r##"# `non_ascii_idents`
868
869The tracking issue for this feature is: [#55467]
870
871[#55467]: https://github.com/rust-lang/rust/issues/55467
872
873------------------------
874
875The `non_ascii_idents` feature adds support for non-ASCII identifiers.
876
877## Examples
878
879```rust
880#![feature(non_ascii_idents)]
881
882const ε: f64 = 0.00001f64;
883const Π: f64 = 3.14f64;
884```
885
886## Changes to the language reference
887
888> **<sup>Lexer:<sup>**\
889> IDENTIFIER :\
890> &nbsp;&nbsp; &nbsp;&nbsp; XID_start XID_continue<sup>\*</sup>\
891> &nbsp;&nbsp; | `_` XID_continue<sup>+</sup>
892
893An identifier is any nonempty Unicode string of the following form:
894
895Either
896
897 * The first character has property [`XID_start`]
898 * The remaining characters have property [`XID_continue`]
899
900Or
901
902 * The first character is `_`
903 * The identifier is more than one character, `_` alone is not an identifier
904 * The remaining characters have property [`XID_continue`]
905
906that does _not_ occur in the set of [strict keywords].
907
908> **Note**: [`XID_start`] and [`XID_continue`] as character properties cover the
909> character ranges used to form the more familiar C and Java language-family
910> identifiers.
911
912[`XID_start`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&abb=on&g=&i=
913[`XID_continue`]: http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&abb=on&g=&i=
914[strict keywords]: ../../reference/keywords.md#strict-keywords
915"##,
916 },
917 LintCompletion {
918 label: "compiler_builtins",
919 description: r##"# `compiler_builtins`
920
921This feature is internal to the Rust compiler and is not intended for general use.
922
923------------------------
924"##,
925 },
926 LintCompletion {
927 label: "or_patterns",
928 description: r##"# `or_patterns`
929
930The tracking issue for this feature is: [#54883]
931
932[#54883]: https://github.com/rust-lang/rust/issues/54883
933
934------------------------
935
936The `or_pattern` language feature allows `|` to be arbitrarily nested within
937a pattern, for example, `Some(A(0) | B(1 | 2))` becomes a valid pattern.
938
939## Examples
940
941```rust,no_run
942#![feature(or_patterns)]
943
944pub enum Foo {
945 Bar,
946 Baz,
947 Quux,
948}
949
950pub fn example(maybe_foo: Option<Foo>) {
951 match maybe_foo {
952 Some(Foo::Bar | Foo::Baz) => {
953 println!("The value contained `Bar` or `Baz`");
954 }
955 Some(_) => {
956 println!("The value did not contain `Bar` or `Baz`");
957 }
958 None => {
959 println!("The value was `None`");
960 }
961 }
962}
963```
964"##,
965 },
966 LintCompletion {
967 label: "negative_impls",
968 description: r##"# `negative_impls`
969
970The tracking issue for this feature is [#68318].
971
972[#68318]: https://github.com/rust-lang/rust/issues/68318
973
974----
975
976With the feature gate `negative_impls`, you can write negative impls as well as positive ones:
977
978```rust
979#![feature(negative_impls)]
980trait DerefMut { }
981impl<T: ?Sized> !DerefMut for &T { }
982```
983
984Negative impls indicate a semver guarantee that the given trait will not be implemented for the given types. Negative impls play an additional purpose for auto traits, described below.
985
986Negative impls have the following characteristics:
987
988* They do not have any items.
989* They must obey the orphan rules as if they were a positive impl.
990* They cannot "overlap" with any positive impls.
991
992## Semver interaction
993
994It is a breaking change to remove a negative impl. Negative impls are a commitment not to implement the given trait for the named types.
995
996## Orphan and overlap rules
997
998Negative impls must obey the same orphan rules as a positive impl. This implies you cannot add a negative impl for types defined in upstream crates and so forth.
999
1000Similarly, negative impls cannot overlap with positive impls, again using the same "overlap" check that we ordinarily use to determine if two impls overlap. (Note that positive impls typically cannot overlap with one another either, except as permitted by specialization.)
1001
1002## Interaction with auto traits
1003
1004Declaring a negative impl `impl !SomeAutoTrait for SomeType` for an
1005auto-trait serves two purposes:
1006
1007* as with any trait, it declares that `SomeType` will never implement `SomeAutoTrait`;
1008* it disables the automatic `SomeType: SomeAutoTrait` impl that would otherwise have been generated.
1009
1010Note that, at present, there is no way to indicate that a given type
1011does not implement an auto trait *but that it may do so in the
1012future*. For ordinary types, this is done by simply not declaring any
1013impl at all, but that is not an option for auto traits. A workaround
1014is that one could embed a marker type as one of the fields, where the
1015marker type is `!AutoTrait`.
1016
1017## Immediate uses
1018
1019Negative impls are used to declare that `&T: !DerefMut` and `&mut T: !Clone`, as required to fix the soundness of `Pin` described in [#66544](https://github.com/rust-lang/rust/issues/66544).
1020
1021This serves two purposes:
1022
1023* For proving the correctness of unsafe code, we can use that impl as evidence that no `DerefMut` or `Clone` impl exists.
1024* It prevents downstream crates from creating such impls.
1025"##,
1026 },
1027 LintCompletion {
1028 label: "cmse_nonsecure_entry",
1029 description: r##"# `cmse_nonsecure_entry`
1030
1031The tracking issue for this feature is: [#75835]
1032
1033[#75835]: https://github.com/rust-lang/rust/issues/75835
1034
1035------------------------
1036
1037The [TrustZone-M
1038feature](https://developer.arm.com/documentation/100690/latest/) is available
1039for targets with the Armv8-M architecture profile (`thumbv8m` in their target
1040name).
1041LLVM, the Rust compiler and the linker are providing
1042[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the
1043TrustZone-M feature.
1044
1045One of the things provided, with this unstable feature, is the
1046`cmse_nonsecure_entry` attribute. This attribute marks a Secure function as an
1047entry function (see [section
10485.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details).
1049With this attribute, the compiler will do the following:
1050* add a special symbol on the function which is the `__acle_se_` prefix and the
1051 standard function name
1052* constrain the number of parameters to avoid using the Non-Secure stack
1053* before returning from the function, clear registers that might contain Secure
1054 information
1055* use the `BXNS` instruction to return
1056
1057Because the stack can not be used to pass parameters, there will be compilation
1058errors if:
1059* the total size of all parameters is too big (for example more than four 32
1060 bits integers)
1061* the entry function is not using a C ABI
1062
1063The special symbol `__acle_se_` will be used by the linker to generate a secure
1064gateway veneer.
1065
1066<!-- NOTE(ignore) this example is specific to thumbv8m targets -->
1067
1068``` rust,ignore
1069#![feature(cmse_nonsecure_entry)]
1070
1071#[no_mangle]
1072#[cmse_nonsecure_entry]
1073pub extern "C" fn entry_function(input: u32) -> u32 {
1074 input + 6
1075}
1076```
1077
1078``` text
1079$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs
1080$ arm-none-eabi-objdump -D function.o
1081
108200000000 <entry_function>:
1083 0: b580 push {r7, lr}
1084 2: 466f mov r7, sp
1085 4: b082 sub sp, #8
1086 6: 9001 str r0, [sp, #4]
1087 8: 1d81 adds r1, r0, #6
1088 a: 460a mov r2, r1
1089 c: 4281 cmp r1, r0
1090 e: 9200 str r2, [sp, #0]
1091 10: d30b bcc.n 2a <entry_function+0x2a>
1092 12: e7ff b.n 14 <entry_function+0x14>
1093 14: 9800 ldr r0, [sp, #0]
1094 16: b002 add sp, #8
1095 18: e8bd 4080 ldmia.w sp!, {r7, lr}
1096 1c: 4671 mov r1, lr
1097 1e: 4672 mov r2, lr
1098 20: 4673 mov r3, lr
1099 22: 46f4 mov ip, lr
1100 24: f38e 8800 msr CPSR_f, lr
1101 28: 4774 bxns lr
1102 2a: f240 0000 movw r0, #0
1103 2e: f2c0 0000 movt r0, #0
1104 32: f240 0200 movw r2, #0
1105 36: f2c0 0200 movt r2, #0
1106 3a: 211c movs r1, #28
1107 3c: f7ff fffe bl 0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E>
1108 40: defe udf #254 ; 0xfe
1109```
1110"##,
1111 },
1112 LintCompletion {
1113 label: "plugin",
1114 description: r##"# `plugin`
1115
1116The tracking issue for this feature is: [#29597]
1117
1118[#29597]: https://github.com/rust-lang/rust/issues/29597
1119
1120
1121This feature is part of "compiler plugins." It will often be used with the
1122[`plugin_registrar`] and `rustc_private` features.
1123
1124[`plugin_registrar`]: plugin-registrar.md
1125
1126------------------------
1127
1128`rustc` can load compiler plugins, which are user-provided libraries that
1129extend the compiler's behavior with new lint checks, etc.
1130
1131A plugin is a dynamic library crate with a designated *registrar* function that
1132registers extensions with `rustc`. Other crates can load these extensions using
1133the crate attribute `#![plugin(...)]`. See the
1134`rustc_driver::plugin` documentation for more about the
1135mechanics of defining and loading a plugin.
1136
1137In the vast majority of cases, a plugin should *only* be used through
1138`#![plugin]` and not through an `extern crate` item. Linking a plugin would
1139pull in all of librustc_ast and librustc as dependencies of your crate. This is
1140generally unwanted unless you are building another plugin.
1141
1142The usual practice is to put compiler plugins in their own crate, separate from
1143any `macro_rules!` macros or ordinary Rust code meant to be used by consumers
1144of a library.
1145
1146# Lint plugins
1147
1148Plugins can extend [Rust's lint
1149infrastructure](../../reference/attributes/diagnostics.md#lint-check-attributes) with
1150additional checks for code style, safety, etc. Now let's write a plugin
1151[`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs)
1152that warns about any item named `lintme`.
1153
1154```rust,ignore (requires-stage-2)
1155#![feature(plugin_registrar)]
1156#![feature(box_syntax, rustc_private)]
1157
1158extern crate rustc_ast;
1159
1160// Load rustc as a plugin to get macros
1161extern crate rustc_driver;
1162#[macro_use]
1163extern crate rustc_lint;
1164#[macro_use]
1165extern crate rustc_session;
1166
1167use rustc_driver::plugin::Registry;
1168use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
1169use rustc_ast::ast;
1170declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
1171
1172declare_lint_pass!(Pass => [TEST_LINT]);
1173
1174impl EarlyLintPass for Pass {
1175 fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
1176 if it.ident.name.as_str() == "lintme" {
1177 cx.lint(TEST_LINT, |lint| {
1178 lint.build("item is named 'lintme'").set_span(it.span).emit()
1179 });
1180 }
1181 }
1182}
1183
1184#[plugin_registrar]
1185pub fn plugin_registrar(reg: &mut Registry) {
1186 reg.lint_store.register_lints(&[&TEST_LINT]);
1187 reg.lint_store.register_early_pass(|| box Pass);
1188}
1189```
1190
1191Then code like
1192
1193```rust,ignore (requires-plugin)
1194#![feature(plugin)]
1195#![plugin(lint_plugin_test)]
1196
1197fn lintme() { }
1198```
1199
1200will produce a compiler warning:
1201
1202```txt
1203foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
1204foo.rs:4 fn lintme() { }
1205 ^~~~~~~~~~~~~~~
1206```
1207
1208The components of a lint plugin are:
1209
1210* one or more `declare_lint!` invocations, which define static `Lint` structs;
1211
1212* a struct holding any state needed by the lint pass (here, none);
1213
1214* a `LintPass`
1215 implementation defining how to check each syntax element. A single
1216 `LintPass` may call `span_lint` for several different `Lint`s, but should
1217 register them all through the `get_lints` method.
1218
1219Lint passes are syntax traversals, but they run at a late stage of compilation
1220where type information is available. `rustc`'s [built-in
1221lints](https://github.com/rust-lang/rust/blob/master/src/librustc_session/lint/builtin.rs)
1222mostly use the same infrastructure as lint plugins, and provide examples of how
1223to access type information.
1224
1225Lints defined by plugins are controlled by the usual [attributes and compiler
1226flags](../../reference/attributes/diagnostics.md#lint-check-attributes), e.g.
1227`#[allow(test_lint)]` or `-A test-lint`. These identifiers are derived from the
1228first argument to `declare_lint!`, with appropriate case and punctuation
1229conversion.
1230
1231You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
1232including those provided by plugins loaded by `foo.rs`.
1233"##,
1234 },
1235 LintCompletion {
1236 label: "intrinsics",
1237 description: r##"# `intrinsics`
1238
1239The tracking issue for this feature is: None.
1240
1241Intrinsics are never intended to be stable directly, but intrinsics are often
1242exported in some sort of stable manner. Prefer using the stable interfaces to
1243the intrinsic directly when you can.
1244
1245------------------------
1246
1247
1248These are imported as if they were FFI functions, with the special
1249`rust-intrinsic` ABI. For example, if one was in a freestanding
1250context, but wished to be able to `transmute` between types, and
1251perform efficient pointer arithmetic, one would import those functions
1252via a declaration like
1253
1254```rust
1255#![feature(intrinsics)]
1256# fn main() {}
1257
1258extern "rust-intrinsic" {
1259 fn transmute<T, U>(x: T) -> U;
1260
1261 fn offset<T>(dst: *const T, offset: isize) -> *const T;
1262}
1263```
1264
1265As with any other FFI functions, these are always `unsafe` to call.
1266"##,
1267 },
1268 LintCompletion {
1269 label: "rustc_attrs",
1270 description: r##"# `rustc_attrs`
1271
1272This feature has no tracking issue, and is therefore internal to
1273the compiler, not being intended for general use.
1274
1275Note: `rustc_attrs` enables many rustc-internal attributes and this page
1276only discuss a few of them.
1277
1278------------------------
1279
1280The `rustc_attrs` feature allows debugging rustc type layouts by using
1281`#[rustc_layout(...)]` to debug layout at compile time (it even works
1282with `cargo check`) as an alternative to `rustc -Z print-type-sizes`
1283that is way more verbose.
1284
1285Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`,
1286`abi`. Note that it only works on sized types without generics.
1287
1288## Examples
1289
1290```rust,compile_fail
1291#![feature(rustc_attrs)]
1292
1293#[rustc_layout(abi, size)]
1294pub enum X {
1295 Y(u8, u8, u8),
1296 Z(isize),
1297}
1298```
1299
1300When that is compiled, the compiler will error with something like
1301
1302```text
1303error: abi: Aggregate { sized: true }
1304 --> src/lib.rs:4:1
1305 |
13064 | / pub enum T {
13075 | | Y(u8, u8, u8),
13086 | | Z(isize),
13097 | | }
1310 | |_^
1311
1312error: size: Size { raw: 16 }
1313 --> src/lib.rs:4:1
1314 |
13154 | / pub enum T {
13165 | | Y(u8, u8, u8),
13176 | | Z(isize),
13187 | | }
1319 | |_^
1320
1321error: aborting due to 2 previous errors
1322```
1323"##,
1324 },
1325 LintCompletion {
1326 label: "const_fn",
1327 description: r##"# `const_fn`
1328
1329The tracking issue for this feature is: [#57563]
1330
1331[#57563]: https://github.com/rust-lang/rust/issues/57563
1332
1333------------------------
1334
1335The `const_fn` feature enables additional functionality not stabilized in the
1336[minimal subset of `const_fn`](https://github.com/rust-lang/rust/issues/53555)
1337"##,
1338 },
1339 LintCompletion {
1340 label: "abi_thiscall",
1341 description: r##"# `abi_thiscall`
1342
1343The tracking issue for this feature is: [#42202]
1344
1345[#42202]: https://github.com/rust-lang/rust/issues/42202
1346
1347------------------------
1348
1349The MSVC ABI on x86 Windows uses the `thiscall` calling convention for C++
1350instance methods by default; it is identical to the usual (C) calling
1351convention on x86 Windows except that the first parameter of the method,
1352the `this` pointer, is passed in the ECX register.
1353"##,
1354 },
1355 LintCompletion {
1356 label: "trait_alias",
1357 description: r##"# `trait_alias`
1358
1359The tracking issue for this feature is: [#41517]
1360
1361[#41517]: https://github.com/rust-lang/rust/issues/41517
1362
1363------------------------
1364
1365The `trait_alias` feature adds support for trait aliases. These allow aliases
1366to be created for one or more traits (currently just a single regular trait plus
1367any number of auto-traits), and used wherever traits would normally be used as
1368either bounds or trait objects.
1369
1370```rust
1371#![feature(trait_alias)]
1372
1373trait Foo = std::fmt::Debug + Send;
1374trait Bar = Foo + Sync;
1375
1376// Use trait alias as bound on type parameter.
1377fn foo<T: Foo>(v: &T) {
1378 println!("{:?}", v);
1379}
1380
1381pub fn main() {
1382 foo(&1);
1383
1384 // Use trait alias for trait objects.
1385 let a: &Bar = &123;
1386 println!("{:?}", a);
1387 let b = Box::new(456) as Box<dyn Foo>;
1388 println!("{:?}", b);
1389}
1390```
1391"##,
1392 },
1393 LintCompletion {
1394 label: "lang_items",
1395 description: r##"# `lang_items`
1396
1397The tracking issue for this feature is: None.
1398
1399------------------------
1400
1401The `rustc` compiler has certain pluggable operations, that is,
1402functionality that isn't hard-coded into the language, but is
1403implemented in libraries, with a special marker to tell the compiler
1404it exists. The marker is the attribute `#[lang = "..."]` and there are
1405various different values of `...`, i.e. various different 'lang
1406items'.
1407
1408For example, `Box` pointers require two lang items, one for allocation
1409and one for deallocation. A freestanding program that uses the `Box`
1410sugar for dynamic allocations via `malloc` and `free`:
1411
1412```rust,ignore (libc-is-finicky)
1413#![feature(lang_items, box_syntax, start, libc, core_intrinsics, rustc_private)]
1414#![no_std]
1415use core::intrinsics;
1416use core::panic::PanicInfo;
1417
1418extern crate libc;
1419
1420#[lang = "owned_box"]
1421pub struct Box<T>(*mut T);
1422
1423#[lang = "exchange_malloc"]
1424unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
1425 let p = libc::malloc(size as libc::size_t) as *mut u8;
1426
1427 // Check if `malloc` failed:
1428 if p as usize == 0 {
1429 intrinsics::abort();
1430 }
1431
1432 p
1433}
1434
1435#[lang = "box_free"]
1436unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
1437 libc::free(ptr as *mut libc::c_void)
1438}
1439
1440#[start]
1441fn main(_argc: isize, _argv: *const *const u8) -> isize {
1442 let _x = box 1;
1443
1444 0
1445}
1446
1447#[lang = "eh_personality"] extern fn rust_eh_personality() {}
1448#[lang = "panic_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } }
1449#[no_mangle] pub extern fn rust_eh_register_frames () {}
1450#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
1451```
1452
1453Note the use of `abort`: the `exchange_malloc` lang item is assumed to
1454return a valid pointer, and so needs to do the check internally.
1455
1456Other features provided by lang items include:
1457
1458- overloadable operators via traits: the traits corresponding to the
1459 `==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
1460 marked with lang items; those specific four are `eq`, `ord`,
1461 `deref`, and `add` respectively.
1462- stack unwinding and general failure; the `eh_personality`,
1463 `panic` and `panic_bounds_check` lang items.
1464- the traits in `std::marker` used to indicate types of
1465 various kinds; lang items `send`, `sync` and `copy`.
1466- the marker types and variance indicators found in
1467 `std::marker`; lang items `covariant_type`,
1468 `contravariant_lifetime`, etc.
1469
1470Lang items are loaded lazily by the compiler; e.g. if one never uses
1471`Box` then there is no need to define functions for `exchange_malloc`
1472and `box_free`. `rustc` will emit an error when an item is needed
1473but not found in the current crate or any that it depends on.
1474
1475Most lang items are defined by `libcore`, but if you're trying to build
1476an executable without the standard library, you'll run into the need
1477for lang items. The rest of this page focuses on this use-case, even though
1478lang items are a bit broader than that.
1479
1480### Using libc
1481
1482In order to build a `#[no_std]` executable we will need libc as a dependency.
1483We can specify this using our `Cargo.toml` file:
1484
1485```toml
1486[dependencies]
1487libc = { version = "0.2.14", default-features = false }
1488```
1489
1490Note that the default features have been disabled. This is a critical step -
1491**the default features of libc include the standard library and so must be
1492disabled.**
1493
1494### Writing an executable without stdlib
1495
1496Controlling the entry point is possible in two ways: the `#[start]` attribute,
1497or overriding the default shim for the C `main` function with your own.
1498
1499The function marked `#[start]` is passed the command line parameters
1500in the same format as C:
1501
1502```rust,ignore (libc-is-finicky)
1503#![feature(lang_items, core_intrinsics, rustc_private)]
1504#![feature(start)]
1505#![no_std]
1506use core::intrinsics;
1507use core::panic::PanicInfo;
1508
1509// Pull in the system libc library for what crt0.o likely requires.
1510extern crate libc;
1511
1512// Entry point for this program.
1513#[start]
1514fn start(_argc: isize, _argv: *const *const u8) -> isize {
1515 0
1516}
1517
1518// These functions are used by the compiler, but not
1519// for a bare-bones hello world. These are normally
1520// provided by libstd.
1521#[lang = "eh_personality"]
1522#[no_mangle]
1523pub extern fn rust_eh_personality() {
1524}
1525
1526#[lang = "panic_impl"]
1527#[no_mangle]
1528pub extern fn rust_begin_panic(info: &PanicInfo) -> ! {
1529 unsafe { intrinsics::abort() }
1530}
1531```
1532
1533To override the compiler-inserted `main` shim, one has to disable it
1534with `#![no_main]` and then create the appropriate symbol with the
1535correct ABI and the correct name, which requires overriding the
1536compiler's name mangling too:
1537
1538```rust,ignore (libc-is-finicky)
1539#![feature(lang_items, core_intrinsics, rustc_private)]
1540#![feature(start)]
1541#![no_std]
1542#![no_main]
1543use core::intrinsics;
1544use core::panic::PanicInfo;
1545
1546// Pull in the system libc library for what crt0.o likely requires.
1547extern crate libc;
1548
1549// Entry point for this program.
1550#[no_mangle] // ensure that this symbol is called `main` in the output
1551pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
1552 0
1553}
1554
1555// These functions are used by the compiler, but not
1556// for a bare-bones hello world. These are normally
1557// provided by libstd.
1558#[lang = "eh_personality"]
1559#[no_mangle]
1560pub extern fn rust_eh_personality() {
1561}
1562
1563#[lang = "panic_impl"]
1564#[no_mangle]
1565pub extern fn rust_begin_panic(info: &PanicInfo) -> ! {
1566 unsafe { intrinsics::abort() }
1567}
1568```
1569
1570In many cases, you may need to manually link to the `compiler_builtins` crate
1571when building a `no_std` binary. You may observe this via linker error messages
1572such as "```undefined reference to `__rust_probestack'```".
1573
1574## More about the language items
1575
1576The compiler currently makes a few assumptions about symbols which are
1577available in the executable to call. Normally these functions are provided by
1578the standard library, but without it you must define your own. These symbols
1579are called "language items", and they each have an internal name, and then a
1580signature that an implementation must conform to.
1581
1582The first of these functions, `rust_eh_personality`, is used by the failure
1583mechanisms of the compiler. This is often mapped to GCC's personality function
1584(see the [libstd implementation][unwind] for more information), but crates
1585which do not trigger a panic can be assured that this function is never
1586called. The language item's name is `eh_personality`.
1587
1588[unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs
1589
1590The second function, `rust_begin_panic`, is also used by the failure mechanisms of the
1591compiler. When a panic happens, this controls the message that's displayed on
1592the screen. While the language item's name is `panic_impl`, the symbol name is
1593`rust_begin_panic`.
1594
1595Finally, a `eh_catch_typeinfo` static is needed for certain targets which
1596implement Rust panics on top of C++ exceptions.
1597
1598## List of all language items
1599
1600This is a list of all language items in Rust along with where they are located in
1601the source code.
1602
1603- Primitives
1604 - `i8`: `libcore/num/mod.rs`
1605 - `i16`: `libcore/num/mod.rs`
1606 - `i32`: `libcore/num/mod.rs`
1607 - `i64`: `libcore/num/mod.rs`
1608 - `i128`: `libcore/num/mod.rs`
1609 - `isize`: `libcore/num/mod.rs`
1610 - `u8`: `libcore/num/mod.rs`
1611 - `u16`: `libcore/num/mod.rs`
1612 - `u32`: `libcore/num/mod.rs`
1613 - `u64`: `libcore/num/mod.rs`
1614 - `u128`: `libcore/num/mod.rs`
1615 - `usize`: `libcore/num/mod.rs`
1616 - `f32`: `libstd/f32.rs`
1617 - `f64`: `libstd/f64.rs`
1618 - `char`: `libcore/char.rs`
1619 - `slice`: `liballoc/slice.rs`
1620 - `str`: `liballoc/str.rs`
1621 - `const_ptr`: `libcore/ptr.rs`
1622 - `mut_ptr`: `libcore/ptr.rs`
1623 - `unsafe_cell`: `libcore/cell.rs`
1624- Runtime
1625 - `start`: `libstd/rt.rs`
1626 - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC)
1627 - `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)
1628 - `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
1629 - `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC)
1630 - `panic`: `libcore/panicking.rs`
1631 - `panic_bounds_check`: `libcore/panicking.rs`
1632 - `panic_impl`: `libcore/panicking.rs`
1633 - `panic_impl`: `libstd/panicking.rs`
1634- Allocations
1635 - `owned_box`: `liballoc/boxed.rs`
1636 - `exchange_malloc`: `liballoc/heap.rs`
1637 - `box_free`: `liballoc/heap.rs`
1638- Operands
1639 - `not`: `libcore/ops/bit.rs`
1640 - `bitand`: `libcore/ops/bit.rs`
1641 - `bitor`: `libcore/ops/bit.rs`
1642 - `bitxor`: `libcore/ops/bit.rs`
1643 - `shl`: `libcore/ops/bit.rs`
1644 - `shr`: `libcore/ops/bit.rs`
1645 - `bitand_assign`: `libcore/ops/bit.rs`
1646 - `bitor_assign`: `libcore/ops/bit.rs`
1647 - `bitxor_assign`: `libcore/ops/bit.rs`
1648 - `shl_assign`: `libcore/ops/bit.rs`
1649 - `shr_assign`: `libcore/ops/bit.rs`
1650 - `deref`: `libcore/ops/deref.rs`
1651 - `deref_mut`: `libcore/ops/deref.rs`
1652 - `index`: `libcore/ops/index.rs`
1653 - `index_mut`: `libcore/ops/index.rs`
1654 - `add`: `libcore/ops/arith.rs`
1655 - `sub`: `libcore/ops/arith.rs`
1656 - `mul`: `libcore/ops/arith.rs`
1657 - `div`: `libcore/ops/arith.rs`
1658 - `rem`: `libcore/ops/arith.rs`
1659 - `neg`: `libcore/ops/arith.rs`
1660 - `add_assign`: `libcore/ops/arith.rs`
1661 - `sub_assign`: `libcore/ops/arith.rs`
1662 - `mul_assign`: `libcore/ops/arith.rs`
1663 - `div_assign`: `libcore/ops/arith.rs`
1664 - `rem_assign`: `libcore/ops/arith.rs`
1665 - `eq`: `libcore/cmp.rs`
1666 - `ord`: `libcore/cmp.rs`
1667- Functions
1668 - `fn`: `libcore/ops/function.rs`
1669 - `fn_mut`: `libcore/ops/function.rs`
1670 - `fn_once`: `libcore/ops/function.rs`
1671 - `generator_state`: `libcore/ops/generator.rs`
1672 - `generator`: `libcore/ops/generator.rs`
1673- Other
1674 - `coerce_unsized`: `libcore/ops/unsize.rs`
1675 - `drop`: `libcore/ops/drop.rs`
1676 - `drop_in_place`: `libcore/ptr.rs`
1677 - `clone`: `libcore/clone.rs`
1678 - `copy`: `libcore/marker.rs`
1679 - `send`: `libcore/marker.rs`
1680 - `sized`: `libcore/marker.rs`
1681 - `unsize`: `libcore/marker.rs`
1682 - `sync`: `libcore/marker.rs`
1683 - `phantom_data`: `libcore/marker.rs`
1684 - `discriminant_kind`: `libcore/marker.rs`
1685 - `freeze`: `libcore/marker.rs`
1686 - `debug_trait`: `libcore/fmt/mod.rs`
1687 - `non_zero`: `libcore/nonzero.rs`
1688 - `arc`: `liballoc/sync.rs`
1689 - `rc`: `liballoc/rc.rs`
1690"##,
1691 },
1692 LintCompletion {
1693 label: "doc_spotlight",
1694 description: r##"# `doc_spotlight`
1695
1696The tracking issue for this feature is: [#45040]
1697
1698The `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute,
1699to "spotlight" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]`
1700attribute to a trait definition will make rustdoc print extra information for functions which return
1701a type that implements that trait. For example, this attribute is applied to the `Iterator`,
1702`io::Read`, `io::Write`, and `Future` traits in the standard library.
1703
1704You can do this on your own traits, like this:
1705
1706```
1707#![feature(doc_spotlight)]
1708
1709#[doc(spotlight)]
1710pub trait MyTrait {}
1711
1712pub struct MyStruct;
1713impl MyTrait for MyStruct {}
1714
1715/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`,
1716/// without having to write that yourself!
1717pub fn my_fn() -> MyStruct { MyStruct }
1718```
1719
1720This feature was originally implemented in PR [#45039].
1721
1722[#45040]: https://github.com/rust-lang/rust/issues/45040
1723[#45039]: https://github.com/rust-lang/rust/pull/45039
1724"##,
1725 },
1726 LintCompletion {
1727 label: "c_variadic",
1728 description: r##"# `c_variadic`
1729
1730The tracking issue for this feature is: [#44930]
1731
1732[#44930]: https://github.com/rust-lang/rust/issues/44930
1733
1734------------------------
1735
1736The `c_variadic` language feature enables C-variadic functions to be
1737defined in Rust. The may be called both from within Rust and via FFI.
1738
1739## Examples
1740
1741```rust
1742#![feature(c_variadic)]
1743
1744pub unsafe extern "C" fn add(n: usize, mut args: ...) -> usize {
1745 let mut sum = 0;
1746 for _ in 0..n {
1747 sum += args.arg::<usize>();
1748 }
1749 sum
1750}
1751```
1752"##,
1753 },
1754 LintCompletion {
1755 label: "intra_doc_pointers",
1756 description: r##"# `intra-doc-pointers`
1757
1758The tracking issue for this feature is: [#80896]
1759
1760[#80896]: https://github.com/rust-lang/rust/issues/80896
1761
1762------------------------
1763
1764Rustdoc does not currently allow disambiguating between `*const` and `*mut`, and
1765raw pointers in intra-doc links are unstable until it does.
1766
1767```rust
1768#![feature(intra_doc_pointers)]
1769//! [pointer::add]
1770```
1771"##,
1772 },
1773 LintCompletion {
1774 label: "box_syntax",
1775 description: r##"# `box_syntax`
1776
1777The tracking issue for this feature is: [#49733]
1778
1779[#49733]: https://github.com/rust-lang/rust/issues/49733
1780
1781See also [`box_patterns`](box-patterns.md)
1782
1783------------------------
1784
1785Currently the only stable way to create a `Box` is via the `Box::new` method.
1786Also it is not possible in stable Rust to destructure a `Box` in a match
1787pattern. The unstable `box` keyword can be used to create a `Box`. An example
1788usage would be:
1789
1790```rust
1791#![feature(box_syntax)]
1792
1793fn main() {
1794 let b = box 5;
1795}
1796```
1797"##,
1798 },
1799 LintCompletion {
1800 label: "unsized_locals",
1801 description: r##"# `unsized_locals`
1802
1803The tracking issue for this feature is: [#48055]
1804
1805[#48055]: https://github.com/rust-lang/rust/issues/48055
1806
1807------------------------
1808
1809This implements [RFC1909]. When turned on, you can have unsized arguments and locals:
1810
1811[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-unsized-rvalues.md
1812
1813```rust
1814#![allow(incomplete_features)]
1815#![feature(unsized_locals, unsized_fn_params)]
1816
1817use std::any::Any;
1818
1819fn main() {
1820 let x: Box<dyn Any> = Box::new(42);
1821 let x: dyn Any = *x;
1822 // ^ unsized local variable
1823 // ^^ unsized temporary
1824 foo(x);
1825}
1826
1827fn foo(_: dyn Any) {}
1828// ^^^^^^ unsized argument
1829```
1830
1831The RFC still forbids the following unsized expressions:
1832
1833```rust,compile_fail
1834#![feature(unsized_locals)]
1835
1836use std::any::Any;
1837
1838struct MyStruct<T: ?Sized> {
1839 content: T,
1840}
1841
1842struct MyTupleStruct<T: ?Sized>(T);
1843
1844fn answer() -> Box<dyn Any> {
1845 Box::new(42)
1846}
1847
1848fn main() {
1849 // You CANNOT have unsized statics.
1850 static X: dyn Any = *answer(); // ERROR
1851 const Y: dyn Any = *answer(); // ERROR
1852
1853 // You CANNOT have struct initialized unsized.
1854 MyStruct { content: *answer() }; // ERROR
1855 MyTupleStruct(*answer()); // ERROR
1856 (42, *answer()); // ERROR
1857
1858 // You CANNOT have unsized return types.
1859 fn my_function() -> dyn Any { *answer() } // ERROR
1860
1861 // You CAN have unsized local variables...
1862 let mut x: dyn Any = *answer(); // OK
1863 // ...but you CANNOT reassign to them.
1864 x = *answer(); // ERROR
1865
1866 // You CANNOT even initialize them separately.
1867 let y: dyn Any; // OK
1868 y = *answer(); // ERROR
1869
1870 // Not mentioned in the RFC, but by-move captured variables are also Sized.
1871 let x: dyn Any = *answer();
1872 (move || { // ERROR
1873 let y = x;
1874 })();
1875
1876 // You CAN create a closure with unsized arguments,
1877 // but you CANNOT call it.
1878 // This is an implementation detail and may be changed in the future.
1879 let f = |x: dyn Any| {};
1880 f(*answer()); // ERROR
1881}
1882```
1883
1884## By-value trait objects
1885
1886With this feature, you can have by-value `self` arguments without `Self: Sized` bounds.
1887
1888```rust
1889#![feature(unsized_fn_params)]
1890
1891trait Foo {
1892 fn foo(self) {}
1893}
1894
1895impl<T: ?Sized> Foo for T {}
1896
1897fn main() {
1898 let slice: Box<[i32]> = Box::new([1, 2, 3]);
1899 <[i32] as Foo>::foo(*slice);
1900}
1901```
1902
1903And `Foo` will also be object-safe.
1904
1905```rust
1906#![feature(unsized_fn_params)]
1907
1908trait Foo {
1909 fn foo(self) {}
1910}
1911
1912impl<T: ?Sized> Foo for T {}
1913
1914fn main () {
1915 let slice: Box<dyn Foo> = Box::new([1, 2, 3]);
1916 // doesn't compile yet
1917 <dyn Foo as Foo>::foo(*slice);
1918}
1919```
1920
1921One of the objectives of this feature is to allow `Box<dyn FnOnce>`.
1922
1923## Variable length arrays
1924
1925The RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`.
1926
1927```rust,ignore (not-yet-implemented)
1928#![feature(unsized_locals)]
1929
1930fn mergesort<T: Ord>(a: &mut [T]) {
1931 let mut tmp = [T; dyn a.len()];
1932 // ...
1933}
1934
1935fn main() {
1936 let mut a = [3, 1, 5, 6];
1937 mergesort(&mut a);
1938 assert_eq!(a, [1, 3, 5, 6]);
1939}
1940```
1941
1942VLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`.
1943
1944## Advisory on stack usage
1945
1946It's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are:
1947
1948- When you need a by-value trait objects.
1949- When you really need a fast allocation of small temporary arrays.
1950
1951Another pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code
1952
1953```rust
1954#![feature(unsized_locals)]
1955
1956fn main() {
1957 let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
1958 let _x = {{{{{{{{{{*x}}}}}}}}}};
1959}
1960```
1961
1962and the code
1963
1964```rust
1965#![feature(unsized_locals)]
1966
1967fn main() {
1968 for _ in 0..10 {
1969 let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
1970 let _x = *x;
1971 }
1972}
1973```
1974
1975will unnecessarily extend the stack frame.
1976"##,
1977 },
1978 LintCompletion {
1979 label: "arbitrary_enum_discriminant",
1980 description: r##"# `arbitrary_enum_discriminant`
1981
1982The tracking issue for this feature is: [#60553]
1983
1984[#60553]: https://github.com/rust-lang/rust/issues/60553
1985
1986------------------------
1987
1988The `arbitrary_enum_discriminant` feature permits tuple-like and
1989struct-like enum variants with `#[repr(<int-type>)]` to have explicit discriminants.
1990
1991## Examples
1992
1993```rust
1994#![feature(arbitrary_enum_discriminant)]
1995
1996#[allow(dead_code)]
1997#[repr(u8)]
1998enum Enum {
1999 Unit = 3,
2000 Tuple(u16) = 2,
2001 Struct {
2002 a: u8,
2003 b: u16,
2004 } = 1,
2005}
2006
2007impl Enum {
2008 fn tag(&self) -> u8 {
2009 unsafe { *(self as *const Self as *const u8) }
2010 }
2011}
2012
2013assert_eq!(3, Enum::Unit.tag());
2014assert_eq!(2, Enum::Tuple(5).tag());
2015assert_eq!(1, Enum::Struct{a: 7, b: 11}.tag());
2016```
2017"##,
2018 },
2019 LintCompletion {
2020 label: "unboxed_closures",
2021 description: r##"# `unboxed_closures`
2022
2023The tracking issue for this feature is [#29625]
2024
2025See Also: [`fn_traits`](../library-features/fn-traits.md)
2026
2027[#29625]: https://github.com/rust-lang/rust/issues/29625
2028
2029----
2030
2031The `unboxed_closures` feature allows you to write functions using the `"rust-call"` ABI,
2032required for implementing the [`Fn*`] family of traits. `"rust-call"` functions must have
2033exactly one (non self) argument, a tuple representing the argument list.
2034
2035[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
2036
2037```rust
2038#![feature(unboxed_closures)]
2039
2040extern "rust-call" fn add_args(args: (u32, u32)) -> u32 {
2041 args.0 + args.1
2042}
2043
2044fn main() {}
2045```
2046"##,
2047 },
2048 LintCompletion {
2049 label: "custom_test_frameworks",
2050 description: r##"# `custom_test_frameworks`
2051
2052The tracking issue for this feature is: [#50297]
2053
2054[#50297]: https://github.com/rust-lang/rust/issues/50297
2055
2056------------------------
2057
2058The `custom_test_frameworks` feature allows the use of `#[test_case]` and `#![test_runner]`.
2059Any function, const, or static can be annotated with `#[test_case]` causing it to be aggregated (like `#[test]`)
2060and be passed to the test runner determined by the `#![test_runner]` crate attribute.
2061
2062```rust
2063#![feature(custom_test_frameworks)]
2064#![test_runner(my_runner)]
2065
2066fn my_runner(tests: &[&i32]) {
2067 for t in tests {
2068 if **t == 0 {
2069 println!("PASSED");
2070 } else {
2071 println!("FAILED");
2072 }
2073 }
2074}
2075
2076#[test_case]
2077const WILL_PASS: i32 = 0;
2078
2079#[test_case]
2080const WILL_FAIL: i32 = 4;
2081```
2082"##,
2083 },
2084 LintCompletion {
2085 label: "abi_msp430_interrupt",
2086 description: r##"# `abi_msp430_interrupt`
2087
2088The tracking issue for this feature is: [#38487]
2089
2090[#38487]: https://github.com/rust-lang/rust/issues/38487
2091
2092------------------------
2093
2094In the MSP430 architecture, interrupt handlers have a special calling
2095convention. You can use the `"msp430-interrupt"` ABI to make the compiler apply
2096the right calling convention to the interrupt handlers you define.
2097
2098<!-- NOTE(ignore) this example is specific to the msp430 target -->
2099
2100``` rust,ignore
2101#![feature(abi_msp430_interrupt)]
2102#![no_std]
2103
2104// Place the interrupt handler at the appropriate memory address
2105// (Alternatively, you can use `#[used]` and remove `pub` and `#[no_mangle]`)
2106#[link_section = "__interrupt_vector_10"]
2107#[no_mangle]
2108pub static TIM0_VECTOR: extern "msp430-interrupt" fn() = tim0;
2109
2110// The interrupt handler
2111extern "msp430-interrupt" fn tim0() {
2112 // ..
2113}
2114```
2115
2116``` text
2117$ msp430-elf-objdump -CD ./target/msp430/release/app
2118Disassembly of section __interrupt_vector_10:
2119
21200000fff2 <TIM0_VECTOR>:
2121 fff2: 00 c0 interrupt service routine at 0xc000
2122
2123Disassembly of section .text:
2124
21250000c000 <int::tim0>:
2126 c000: 00 13 reti
2127```
2128"##,
2129 },
2130 LintCompletion {
2131 label: "impl_trait_in_bindings",
2132 description: r##"# `impl_trait_in_bindings`
2133
2134The tracking issue for this feature is: [#63065]
2135
2136[#63065]: https://github.com/rust-lang/rust/issues/63065
2137
2138------------------------
2139
2140The `impl_trait_in_bindings` feature gate lets you use `impl Trait` syntax in
2141`let`, `static`, and `const` bindings.
2142
2143A simple example is:
2144
2145```rust
2146#![feature(impl_trait_in_bindings)]
2147
2148use std::fmt::Debug;
2149
2150fn main() {
2151 let a: impl Debug + Clone = 42;
2152 let b = a.clone();
2153 println!("{:?}", b); // prints `42`
2154}
2155```
2156
2157Note however that because the types of `a` and `b` are opaque in the above
2158example, calling inherent methods or methods outside of the specified traits
2159(e.g., `a.abs()` or `b.abs()`) is not allowed, and yields an error.
2160"##,
2161 },
2162 LintCompletion {
2163 label: "cfg_version",
2164 description: r##"# `cfg_version`
2165
2166The tracking issue for this feature is: [#64796]
2167
2168[#64796]: https://github.com/rust-lang/rust/issues/64796
2169
2170------------------------
2171
2172The `cfg_version` feature makes it possible to execute different code
2173depending on the compiler version.
2174
2175## Examples
2176
2177```rust
2178#![feature(cfg_version)]
2179
2180#[cfg(version("1.42"))]
2181fn a() {
2182 // ...
2183}
2184
2185#[cfg(not(version("1.42")))]
2186fn a() {
2187 // ...
2188}
2189
2190fn b() {
2191 if cfg!(version("1.42")) {
2192 // ...
2193 } else {
2194 // ...
2195 }
2196}
2197```
2198"##,
2199 },
2200 LintCompletion {
2201 label: "link_cfg",
2202 description: r##"# `link_cfg`
2203
2204This feature is internal to the Rust compiler and is not intended for general use.
2205
2206------------------------
2207"##,
2208 },
2209 LintCompletion {
2210 label: "infer_static_outlives_requirements",
2211 description: r##"# `infer_static_outlives_requirements`
2212
2213The tracking issue for this feature is: [#54185]
2214
2215[#54185]: https://github.com/rust-lang/rust/issues/54185
2216
2217------------------------
2218The `infer_static_outlives_requirements` feature indicates that certain
2219`'static` outlives requirements can be inferred by the compiler rather than
2220stating them explicitly.
2221
2222Note: It is an accompanying feature to `infer_outlives_requirements`,
2223which must be enabled to infer outlives requirements.
2224
2225For example, currently generic struct definitions that contain
2226references, require where-clauses of the form T: 'static. By using
2227this feature the outlives predicates will be inferred, although
2228they may still be written explicitly.
2229
2230```rust,ignore (pseudo-Rust)
2231struct Foo<U> where U: 'static { // <-- currently required
2232 bar: Bar<U>
2233}
2234struct Bar<T: 'static> {
2235 x: T,
2236}
2237```
2238
2239
2240## Examples:
2241
2242```rust,ignore (pseudo-Rust)
2243#![feature(infer_outlives_requirements)]
2244#![feature(infer_static_outlives_requirements)]
2245
2246#[rustc_outlives]
2247// Implicitly infer U: 'static
2248struct Foo<U> {
2249 bar: Bar<U>
2250}
2251struct Bar<T: 'static> {
2252 x: T,
2253}
2254```
2255"##,
2256 },
2257 LintCompletion {
2258 label: "marker_trait_attr",
2259 description: r##"# `marker_trait_attr`
2260
2261The tracking issue for this feature is: [#29864]
2262
2263[#29864]: https://github.com/rust-lang/rust/issues/29864
2264
2265------------------------
2266
2267Normally, Rust keeps you from adding trait implementations that could
2268overlap with each other, as it would be ambiguous which to use. This
2269feature, however, carves out an exception to that rule: a trait can
2270opt-in to having overlapping implementations, at the cost that those
2271implementations are not allowed to override anything (and thus the
2272trait itself cannot have any associated items, as they're pointless
2273when they'd need to do the same thing for every type anyway).
2274
2275```rust
2276#![feature(marker_trait_attr)]
2277
2278#[marker] trait CheapToClone: Clone {}
2279
2280impl<T: Copy> CheapToClone for T {}
2281
2282// These could potentially overlap with the blanket implementation above,
2283// so are only allowed because CheapToClone is a marker trait.
2284impl<T: CheapToClone, U: CheapToClone> CheapToClone for (T, U) {}
2285impl<T: CheapToClone> CheapToClone for std::ops::Range<T> {}
2286
2287fn cheap_clone<T: CheapToClone>(t: T) -> T {
2288 t.clone()
2289}
2290```
2291
2292This is expected to replace the unstable `overlapping_marker_traits`
2293feature, which applied to all empty traits (without needing an opt-in).
2294"##,
2295 },
2296 LintCompletion {
2297 label: "doc_masked",
2298 description: r##"# `doc_masked`
2299
2300The tracking issue for this feature is: [#44027]
2301
2302-----
2303
2304The `doc_masked` feature allows a crate to exclude types from a given crate from appearing in lists
2305of trait implementations. The specifics of the feature are as follows:
2306
23071. When rustdoc encounters an `extern crate` statement annotated with a `#[doc(masked)]` attribute,
2308 it marks the crate as being masked.
2309
23102. When listing traits a given type implements, rustdoc ensures that traits from masked crates are
2311 not emitted into the documentation.
2312
23133. When listing types that implement a given trait, rustdoc ensures that types from masked crates
2314 are not emitted into the documentation.
2315
2316This feature was introduced in PR [#44026] to ensure that compiler-internal and
2317implementation-specific types and traits were not included in the standard library's documentation.
2318Such types would introduce broken links into the documentation.
2319
2320[#44026]: https://github.com/rust-lang/rust/pull/44026
2321[#44027]: https://github.com/rust-lang/rust/pull/44027
2322"##,
2323 },
2324 LintCompletion {
2325 label: "abi_ptx",
2326 description: r##"# `abi_ptx`
2327
2328The tracking issue for this feature is: [#38788]
2329
2330[#38788]: https://github.com/rust-lang/rust/issues/38788
2331
2332------------------------
2333
2334When emitting PTX code, all vanilla Rust functions (`fn`) get translated to
2335"device" functions. These functions are *not* callable from the host via the
2336CUDA API so a crate with only device functions is not too useful!
2337
2338OTOH, "global" functions *can* be called by the host; you can think of them
2339as the real public API of your crate. To produce a global function use the
2340`"ptx-kernel"` ABI.
2341
2342<!-- NOTE(ignore) this example is specific to the nvptx targets -->
2343
2344``` rust,ignore
2345#![feature(abi_ptx)]
2346#![no_std]
2347
2348pub unsafe extern "ptx-kernel" fn global_function() {
2349 device_function();
2350}
2351
2352pub fn device_function() {
2353 // ..
2354}
2355```
2356
2357``` text
2358$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm
2359
2360$ cat $(find -name '*.s')
2361//
2362// Generated by LLVM NVPTX Back-End
2363//
2364
2365.version 3.2
2366.target sm_20
2367.address_size 64
2368
2369 // .globl _ZN6kernel15global_function17h46111ebe6516b382E
2370
2371.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E()
2372{
2373
2374
2375 ret;
2376}
2377
2378 // .globl _ZN6kernel15device_function17hd6a0e4993bbf3f78E
2379.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E()
2380{
2381
2382
2383 ret;
2384}
2385```
2386"##,
2387 },
2388 LintCompletion {
2389 label: "profiler_runtime",
2390 description: r##"# `profiler_runtime`
2391
2392The tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524).
2393
2394------------------------
2395"##,
2396 },
2397 LintCompletion {
2398 label: "crate_visibility_modifier",
2399 description: r##"# `crate_visibility_modifier`
2400
2401The tracking issue for this feature is: [#53120]
2402
2403[#53120]: https://github.com/rust-lang/rust/issues/53120
2404
2405-----
2406
2407The `crate_visibility_modifier` feature allows the `crate` keyword to be used
2408as a visibility modifier synonymous to `pub(crate)`, indicating that a type
2409(function, _&c._) is to be visible to the entire enclosing crate, but not to
2410other crates.
2411
2412```rust
2413#![feature(crate_visibility_modifier)]
2414
2415crate struct Foo {
2416 bar: usize,
2417}
2418```
2419"##,
2420 },
2421 LintCompletion {
2422 label: "doc_cfg",
2423 description: r##"# `doc_cfg`
2424
2425The tracking issue for this feature is: [#43781]
2426
2427------
2428
2429The `doc_cfg` feature allows an API be documented as only available in some specific platforms.
2430This attribute has two effects:
2431
24321. In the annotated item's documentation, there will be a message saying "This is supported on
2433 (platform) only".
2434
24352. The item's doc-tests will only run on the specific platform.
2436
2437In addition to allowing the use of the `#[doc(cfg)]` attribute, this feature enables the use of a
2438special conditional compilation flag, `#[cfg(doc)]`, set whenever building documentation on your
2439crate.
2440
2441This feature was introduced as part of PR [#43348] to allow the platform-specific parts of the
2442standard library be documented.
2443
2444```rust
2445#![feature(doc_cfg)]
2446
2447#[cfg(any(windows, doc))]
2448#[doc(cfg(windows))]
2449/// The application's icon in the notification area (a.k.a. system tray).
2450///
2451/// # Examples
2452///
2453/// ```no_run
2454/// extern crate my_awesome_ui_library;
2455/// use my_awesome_ui_library::current_app;
2456/// use my_awesome_ui_library::windows::notification;
2457///
2458/// let icon = current_app().get::<notification::Icon>();
2459/// icon.show();
2460/// icon.show_message("Hello");
2461/// ```
2462pub struct Icon {
2463 // ...
2464}
2465```
2466
2467[#43781]: https://github.com/rust-lang/rust/issues/43781
2468[#43348]: https://github.com/rust-lang/rust/issues/43348
2469"##,
2470 },
2471 LintCompletion {
2472 label: "unsized_tuple_coercion",
2473 description: r##"# `unsized_tuple_coercion`
2474
2475The tracking issue for this feature is: [#42877]
2476
2477[#42877]: https://github.com/rust-lang/rust/issues/42877
2478
2479------------------------
2480
2481This is a part of [RFC0401]. According to the RFC, there should be an implementation like this:
2482
2483```rust,ignore (partial-example)
2484impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized<U> {}
2485```
2486
2487This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this:
2488
2489```rust
2490#![feature(unsized_tuple_coercion)]
2491
2492fn main() {
2493 let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);
2494 let y : &([i32; 3], [i32]) = &x;
2495 assert_eq!(y.1[0], 4);
2496}
2497```
2498
2499[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
2500"##,
2501 },
2502 LintCompletion {
2503 label: "no_sanitize",
2504 description: r##"# `no_sanitize`
2505
2506The tracking issue for this feature is: [#39699]
2507
2508[#39699]: https://github.com/rust-lang/rust/issues/39699
2509
2510------------------------
2511
2512The `no_sanitize` attribute can be used to selectively disable sanitizer
2513instrumentation in an annotated function. This might be useful to: avoid
2514instrumentation overhead in a performance critical function, or avoid
2515instrumenting code that contains constructs unsupported by given sanitizer.
2516
2517The precise effect of this annotation depends on particular sanitizer in use.
2518For example, with `no_sanitize(thread)`, the thread sanitizer will no longer
2519instrument non-atomic store / load operations, but it will instrument atomic
2520operations to avoid reporting false positives and provide meaning full stack
2521traces.
2522
2523## Examples
2524
2525``` rust
2526#![feature(no_sanitize)]
2527
2528#[no_sanitize(address)]
2529fn foo() {
2530 // ...
2531}
2532```
2533"##,
2534 },
2535 LintCompletion {
2536 label: "try_blocks",
2537 description: r##"# `try_blocks`
2538
2539The tracking issue for this feature is: [#31436]
2540
2541[#31436]: https://github.com/rust-lang/rust/issues/31436
2542
2543------------------------
2544
2545The `try_blocks` feature adds support for `try` blocks. A `try`
2546block creates a new scope one can use the `?` operator in.
2547
2548```rust,edition2018
2549#![feature(try_blocks)]
2550
2551use std::num::ParseIntError;
2552
2553let result: Result<i32, ParseIntError> = try {
2554 "1".parse::<i32>()?
2555 + "2".parse::<i32>()?
2556 + "3".parse::<i32>()?
2557};
2558assert_eq!(result, Ok(6));
2559
2560let result: Result<i32, ParseIntError> = try {
2561 "1".parse::<i32>()?
2562 + "foo".parse::<i32>()?
2563 + "3".parse::<i32>()?
2564};
2565assert!(result.is_err());
2566```
2567"##,
2568 },
2569 LintCompletion {
2570 label: "transparent_unions",
2571 description: r##"# `transparent_unions`
2572
2573The tracking issue for this feature is [#60405]
2574
2575[#60405]: https://github.com/rust-lang/rust/issues/60405
2576
2577----
2578
2579The `transparent_unions` feature allows you mark `union`s as
2580`#[repr(transparent)]`. A `union` may be `#[repr(transparent)]` in exactly the
2581same conditions in which a `struct` may be `#[repr(transparent)]` (generally,
2582this means the `union` must have exactly one non-zero-sized field). Some
2583concrete illustrations follow.
2584
2585```rust
2586#![feature(transparent_unions)]
2587
2588// This union has the same representation as `f32`.
2589#[repr(transparent)]
2590union SingleFieldUnion {
2591 field: f32,
2592}
2593
2594// This union has the same representation as `usize`.
2595#[repr(transparent)]
2596union MultiFieldUnion {
2597 field: usize,
2598 nothing: (),
2599}
2600```
2601
2602For consistency with transparent `struct`s, `union`s must have exactly one
2603non-zero-sized field. If all fields are zero-sized, the `union` must not be
2604`#[repr(transparent)]`:
2605
2606```rust
2607#![feature(transparent_unions)]
2608
2609// This (non-transparent) union is already valid in stable Rust:
2610pub union GoodUnion {
2611 pub nothing: (),
2612}
2613
2614// Error: transparent union needs exactly one non-zero-sized field, but has 0
2615// #[repr(transparent)]
2616// pub union BadUnion {
2617// pub nothing: (),
2618// }
2619```
2620
2621The one exception is if the `union` is generic over `T` and has a field of type
2622`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type:
2623
2624```rust
2625#![feature(transparent_unions)]
2626
2627// This union has the same representation as `T`.
2628#[repr(transparent)]
2629pub union GenericUnion<T: Copy> { // Unions with non-`Copy` fields are unstable.
2630 pub field: T,
2631 pub nothing: (),
2632}
2633
2634// This is okay even though `()` is a zero-sized type.
2635pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () };
2636```
2637
2638Like transarent `struct`s, a transparent `union` of type `U` has the same
2639layout, size, and ABI as its single non-ZST field. If it is generic over a type
2640`T`, and all its fields are ZSTs except for exactly one field of type `T`, then
2641it has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized).
2642
2643Like transparent `struct`s, transparent `union`s are FFI-safe if and only if
2644their underlying representation type is also FFI-safe.
2645
2646A `union` may not be eligible for the same nonnull-style optimizations that a
2647`struct` or `enum` (with the same fields) are eligible for. Adding
2648`#[repr(transparent)]` to `union` does not change this. To give a more concrete
2649example, it is unspecified whether `size_of::<T>()` is equal to
2650`size_of::<Option<T>>()`, where `T` is a `union` (regardless of whether or not
2651it is transparent). The Rust compiler is free to perform this optimization if
2652possible, but is not required to, and different compiler versions may differ in
2653their application of these optimizations.
2654"##,
2655 },
2656 LintCompletion {
2657 label: "const_eval_limit",
2658 description: r##"# `const_eval_limit`
2659
2660The tracking issue for this feature is: [#67217]
2661
2662[#67217]: https://github.com/rust-lang/rust/issues/67217
2663
2664The `const_eval_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`.
2665"##,
2666 },
2667 LintCompletion {
2668 label: "link_args",
2669 description: r##"# `link_args`
2670
2671The tracking issue for this feature is: [#29596]
2672
2673[#29596]: https://github.com/rust-lang/rust/issues/29596
2674
2675------------------------
2676
2677You can tell `rustc` how to customize linking, and that is via the `link_args`
2678attribute. This attribute is applied to `extern` blocks and specifies raw flags
2679which need to get passed to the linker when producing an artifact. An example
2680usage would be:
2681
2682```rust,no_run
2683#![feature(link_args)]
2684
2685#[link_args = "-foo -bar -baz"]
2686extern "C" {}
2687# fn main() {}
2688```
2689
2690Note that this feature is currently hidden behind the `feature(link_args)` gate
2691because this is not a sanctioned way of performing linking. Right now `rustc`
2692shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), so
2693it makes sense to provide extra command line arguments, but this will not
2694always be the case. In the future `rustc` may use LLVM directly to link native
2695libraries, in which case `link_args` will have no meaning. You can achieve the
2696same effect as the `link_args` attribute with the `-C link-args` argument to
2697`rustc`.
2698
2699It is highly recommended to *not* use this attribute, and rather use the more
2700formal `#[link(...)]` attribute on `extern` blocks instead.
2701"##,
2702 },
2703 LintCompletion {
2704 label: "internal_output_capture",
2705 description: r##"# `internal_output_capture`
2706
2707This feature is internal to the Rust compiler and is not intended for general use.
2708
2709------------------------
2710"##,
2711 },
2712 LintCompletion {
2713 label: "windows_handle",
2714 description: r##"# `windows_handle`
2715
2716This feature is internal to the Rust compiler and is not intended for general use.
2717
2718------------------------
2719"##,
2720 },
2721 LintCompletion {
2722 label: "asm",
2723 description: r##"# `asm`
2724
2725The tracking issue for this feature is: [#72016]
2726
2727[#72016]: https://github.com/rust-lang/rust/issues/72016
2728
2729------------------------
2730
2731For extremely low-level manipulations and performance reasons, one
2732might wish to control the CPU directly. Rust supports using inline
2733assembly to do this via the `asm!` macro.
2734
2735# Guide-level explanation
2736[guide-level-explanation]: #guide-level-explanation
2737
2738Rust provides support for inline assembly via the `asm!` macro.
2739It can be used to embed handwritten assembly in the assembly output generated by the compiler.
2740Generally this should not be necessary, but might be where the required performance or timing
2741cannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality.
2742
2743> **Note**: the examples here are given in x86/x86-64 assembly, but other architectures are also supported.
2744
2745Inline assembly is currently supported on the following architectures:
2746- x86 and x86-64
2747- ARM
2748- AArch64
2749- RISC-V
2750- NVPTX
2751- Hexagon
2752- MIPS32r2 and MIPS64r2
2753- wasm32
2754
2755## Basic usage
2756
2757Let us start with the simplest possible example:
2758
2759```rust,allow_fail
2760# #![feature(asm)]
2761unsafe {
2762 asm!("nop");
2763}
2764```
2765
2766This will insert a NOP (no operation) instruction into the assembly generated by the compiler.
2767Note that all `asm!` invocations have to be inside an `unsafe` block, as they could insert
2768arbitrary instructions and break various invariants. The instructions to be inserted are listed
2769in the first argument of the `asm!` macro as a string literal.
2770
2771## Inputs and outputs
2772
2773Now inserting an instruction that does nothing is rather boring. Let us do something that
2774actually acts on data:
2775
2776```rust,allow_fail
2777# #![feature(asm)]
2778let x: u64;
2779unsafe {
2780 asm!("mov {}, 5", out(reg) x);
2781}
2782assert_eq!(x, 5);
2783```
2784
2785This will write the value `5` into the `u64` variable `x`.
2786You can see that the string literal we use to specify instructions is actually a template string.
2787It is governed by the same rules as Rust [format strings][format-syntax].
2788The arguments that are inserted into the template however look a bit different then you may
2789be familiar with. First we need to specify if the variable is an input or an output of the
2790inline assembly. In this case it is an output. We declared this by writing `out`.
2791We also need to specify in what kind of register the assembly expects the variable.
2792In this case we put it in an arbitrary general purpose register by specifying `reg`.
2793The compiler will choose an appropriate register to insert into
2794the template and will read the variable from there after the inline assembly finishes executing.
2795
2796Let us see another example that also uses an input:
2797
2798```rust,allow_fail
2799# #![feature(asm)]
2800let i: u64 = 3;
2801let o: u64;
2802unsafe {
2803 asm!(
2804 "mov {0}, {1}",
2805 "add {0}, {number}",
2806 out(reg) o,
2807 in(reg) i,
2808 number = const 5,
2809 );
2810}
2811assert_eq!(o, 8);
2812```
2813
2814This will add `5` to the input in variable `i` and write the result to variable `o`.
2815The particular way this assembly does this is first copying the value from `i` to the output,
2816and then adding `5` to it.
2817
2818The example shows a few things:
2819
2820First, we can see that `asm!` allows multiple template string arguments; each
2821one is treated as a separate line of assembly code, as if they were all joined
2822together with newlines between them. This makes it easy to format assembly
2823code.
2824
2825Second, we can see that inputs are declared by writing `in` instead of `out`.
2826
2827Third, one of our operands has a type we haven't seen yet, `const`.
2828This tells the compiler to expand this argument to value directly inside the assembly template.
2829This is only possible for constants and literals.
2830
2831Fourth, we can see that we can specify an argument number, or name as in any format string.
2832For inline assembly templates this is particularly useful as arguments are often used more than once.
2833For more complex inline assembly using this facility is generally recommended, as it improves
2834readability, and allows reordering instructions without changing the argument order.
2835
2836We can further refine the above example to avoid the `mov` instruction:
2837
2838```rust,allow_fail
2839# #![feature(asm)]
2840let mut x: u64 = 3;
2841unsafe {
2842 asm!("add {0}, {number}", inout(reg) x, number = const 5);
2843}
2844assert_eq!(x, 8);
2845```
2846
2847We can see that `inout` is used to specify an argument that is both input and output.
2848This is different from specifying an input and output separately in that it is guaranteed to assign both to the same register.
2849
2850It is also possible to specify different variables for the input and output parts of an `inout` operand:
2851
2852```rust,allow_fail
2853# #![feature(asm)]
2854let x: u64 = 3;
2855let y: u64;
2856unsafe {
2857 asm!("add {0}, {number}", inout(reg) x => y, number = const 5);
2858}
2859assert_eq!(y, 8);
2860```
2861
2862## Late output operands
2863
2864The Rust compiler is conservative with its allocation of operands. It is assumed that an `out`
2865can be written at any time, and can therefore not share its location with any other argument.
2866However, to guarantee optimal performance it is important to use as few registers as possible,
2867so they won't have to be saved and reloaded around the inline assembly block.
2868To achieve this Rust provides a `lateout` specifier. This can be used on any output that is
2869written only after all inputs have been consumed.
2870There is also a `inlateout` variant of this specifier.
2871
2872Here is an example where `inlateout` *cannot* be used:
2873
2874```rust,allow_fail
2875# #![feature(asm)]
2876let mut a: u64 = 4;
2877let b: u64 = 4;
2878let c: u64 = 4;
2879unsafe {
2880 asm!(
2881 "add {0}, {1}",
2882 "add {0}, {2}",
2883 inout(reg) a,
2884 in(reg) b,
2885 in(reg) c,
2886 );
2887}
2888assert_eq!(a, 12);
2889```
2890
2891Here the compiler is free to allocate the same register for inputs `b` and `c` since it knows they have the same value. However it must allocate a separate register for `a` since it uses `inout` and not `inlateout`. If `inlateout` was used, then `a` and `c` could be allocated to the same register, in which case the first instruction to overwrite the value of `c` and cause the assembly code to produce the wrong result.
2892
2893However the following example can use `inlateout` since the output is only modified after all input registers have been read:
2894
2895```rust,allow_fail
2896# #![feature(asm)]
2897let mut a: u64 = 4;
2898let b: u64 = 4;
2899unsafe {
2900 asm!("add {0}, {1}", inlateout(reg) a, in(reg) b);
2901}
2902assert_eq!(a, 8);
2903```
2904
2905As you can see, this assembly fragment will still work correctly if `a` and `b` are assigned to the same register.
2906
2907## Explicit register operands
2908
2909Some instructions require that the operands be in a specific register.
2910Therefore, Rust inline assembly provides some more specific constraint specifiers.
2911While `reg` is generally available on any architecture, these are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi`
2912among others can be addressed by their name.
2913
2914```rust,allow_fail,no_run
2915# #![feature(asm)]
2916let cmd = 0xd1;
2917unsafe {
2918 asm!("out 0x64, eax", in("eax") cmd);
2919}
2920```
2921
2922In this example we call the `out` instruction to output the content of the `cmd` variable
2923to port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand
2924we had to use the `eax` constraint specifier.
2925
2926Note that unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types.
2927
2928Consider this example which uses the x86 `mul` instruction:
2929
2930```rust,allow_fail
2931# #![feature(asm)]
2932fn mul(a: u64, b: u64) -> u128 {
2933 let lo: u64;
2934 let hi: u64;
2935
2936 unsafe {
2937 asm!(
2938 // The x86 mul instruction takes rax as an implicit input and writes
2939 // the 128-bit result of the multiplication to rax:rdx.
2940 "mul {}",
2941 in(reg) a,
2942 inlateout("rax") b => lo,
2943 lateout("rdx") hi
2944 );
2945 }
2946
2947 ((hi as u128) << 64) + lo as u128
2948}
2949```
2950
2951This uses the `mul` instruction to multiply two 64-bit inputs with a 128-bit result.
2952The only explicit operand is a register, that we fill from the variable `a`.
2953The second operand is implicit, and must be the `rax` register, which we fill from the variable `b`.
2954The lower 64 bits of the result are stored in `rax` from which we fill the variable `lo`.
2955The higher 64 bits are stored in `rdx` from which we fill the variable `hi`.
2956
2957## Clobbered registers
2958
2959In many cases inline assembly will modify state that is not needed as an output.
2960Usually this is either because we have to use a scratch register in the assembly,
2961or instructions modify state that we don't need to further examine.
2962This state is generally referred to as being "clobbered".
2963We need to tell the compiler about this since it may need to save and restore this state
2964around the inline assembly block.
2965
2966```rust,allow_fail
2967# #![feature(asm)]
2968let ebx: u32;
2969let ecx: u32;
2970
2971unsafe {
2972 asm!(
2973 "cpuid",
2974 // EAX 4 selects the "Deterministic Cache Parameters" CPUID leaf
2975 inout("eax") 4 => _,
2976 // ECX 0 selects the L0 cache information.
2977 inout("ecx") 0 => ecx,
2978 lateout("ebx") ebx,
2979 lateout("edx") _,
2980 );
2981}
2982
2983println!(
2984 "L1 Cache: {}",
2985 ((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1)
2986);
2987```
2988
2989In the example above we use the `cpuid` instruction to get the L1 cache size.
2990This instruction writes to `eax`, `ebx`, `ecx`, and `edx`, but for the cache size we only care about the contents of `ebx` and `ecx`.
2991
2992However we still need to tell the compiler that `eax` and `edx` have been modified so that it can save any values that were in these registers before the asm. This is done by declaring these as outputs but with `_` instead of a variable name, which indicates that the output value is to be discarded.
2993
2994This can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:
2995
2996```rust,allow_fail
2997# #![feature(asm)]
2998// Multiply x by 6 using shifts and adds
2999let mut x: u64 = 4;
3000unsafe {
3001 asm!(
3002 "mov {tmp}, {x}",
3003 "shl {tmp}, 1",
3004 "shl {x}, 2",
3005 "add {x}, {tmp}",
3006 x = inout(reg) x,
3007 tmp = out(reg) _,
3008 );
3009}
3010assert_eq!(x, 4 * 6);
3011```
3012
3013## Symbol operands
3014
3015A special operand type, `sym`, allows you to use the symbol name of a `fn` or `static` in inline assembly code.
3016This allows you to call a function or access a global variable without needing to keep its address in a register.
3017
3018```rust,allow_fail
3019# #![feature(asm)]
3020extern "C" fn foo(arg: i32) {
3021 println!("arg = {}", arg);
3022}
3023
3024fn call_foo(arg: i32) {
3025 unsafe {
3026 asm!(
3027 "call {}",
3028 sym foo,
3029 // 1st argument in rdi, which is caller-saved
3030 inout("rdi") arg => _,
3031 // All caller-saved registers must be marked as clobberred
3032 out("rax") _, out("rcx") _, out("rdx") _, out("rsi") _,
3033 out("r8") _, out("r9") _, out("r10") _, out("r11") _,
3034 out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
3035 out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
3036 out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
3037 out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
3038 )
3039 }
3040}
3041```
3042
3043Note that the `fn` or `static` item does not need to be public or `#[no_mangle]`:
3044the compiler will automatically insert the appropriate mangled symbol name into the assembly code.
3045
3046## Register template modifiers
3047
3048In some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a "view" over a subset of the register (e.g. the low 32 bits of a 64-bit register).
3049
3050By default the compiler will always choose the name that refers to the full register size (e.g. `rax` on x86-64, `eax` on x86, etc).
3051
3052This default can be overriden by using modifiers on the template string operands, just like you would with format strings:
3053
3054```rust,allow_fail
3055# #![feature(asm)]
3056let mut x: u16 = 0xab;
3057
3058unsafe {
3059 asm!("mov {0:h}, {0:l}", inout(reg_abcd) x);
3060}
3061
3062assert_eq!(x, 0xabab);
3063```
3064
3065In this example, we use the `reg_abcd` register class to restrict the register allocator to the 4 legacy x86 register (`ax`, `bx`, `cx`, `dx`) of which the first two bytes can be addressed independently.
3066
3067Let us assume that the register allocator has chosen to allocate `x` in the `ax` register.
3068The `h` modifier will emit the register name for the high byte of that register and the `l` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte.
3069
3070If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.
3071
3072## Memory address operands
3073
3074Sometimes assembly instructions require operands passed via memory addresses/memory locations.
3075You have to manually use the memory address syntax specified by the respectively architectures.
3076For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]`
3077to indicate they are memory operands:
3078
3079```rust,allow_fail
3080# #![feature(asm, llvm_asm)]
3081# fn load_fpu_control_word(control: u16) {
3082unsafe {
3083 asm!("fldcw [{}]", in(reg) &control, options(nostack));
3084
3085 // Previously this would have been written with the deprecated `llvm_asm!` like this
3086 llvm_asm!("fldcw $0" :: "m" (control) :: "volatile");
3087}
3088# }
3089```
3090
3091## Options
3092
3093By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
3094
3095Let's take our previous example of an `add` instruction:
3096
3097```rust,allow_fail
3098# #![feature(asm)]
3099let mut a: u64 = 4;
3100let b: u64 = 4;
3101unsafe {
3102 asm!(
3103 "add {0}, {1}",
3104 inlateout(reg) a, in(reg) b,
3105 options(pure, nomem, nostack),
3106 );
3107}
3108assert_eq!(a, 8);
3109```
3110
3111Options can be provided as an optional final argument to the `asm!` macro. We specified three options here:
3112- `pure` means that the asm code has no observable side effects and that its output depends only on its inputs. This allows the compiler optimizer to call the inline asm fewer times or even eliminate it entirely.
3113- `nomem` means that the asm code does not read or write to memory. By default the compiler will assume that inline assembly can read or write any memory address that is accessible to it (e.g. through a pointer passed as an operand, or a global).
3114- `nostack` means that the asm code does not push any data onto the stack. This allows the compiler to use optimizations such as the stack red zone on x86-64 to avoid stack pointer adjustments.
3115
3116These allow the compiler to better optimize code using `asm!`, for example by eliminating pure `asm!` blocks whose outputs are not needed.
3117
3118See the reference for the full list of available options and their effects.
3119
3120# Reference-level explanation
3121[reference-level-explanation]: #reference-level-explanation
3122
3123Inline assembler is implemented as an unsafe macro `asm!()`.
3124The first argument to this macro is a template string literal used to build the final assembly.
3125The following arguments specify input and output operands.
3126When required, options are specified as the final argument.
3127
3128The following ABNF specifies the general syntax:
3129
3130```text
3131dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout"
3132reg_spec := <register class> / "<explicit register>"
3133operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_"
3134reg_operand := dir_spec "(" reg_spec ")" operand_expr
3135operand := reg_operand / "const" const_expr / "sym" path
3136option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax"
3137options := "options(" option *["," option] [","] ")"
3138asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")"
3139```
3140
3141The macro will initially be supported only on ARM, AArch64, Hexagon, x86, x86-64 and RISC-V targets. Support for more targets may be added in the future. The compiler will emit an error if `asm!` is used on an unsupported target.
3142
3143[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
3144
3145## Template string arguments
3146
3147The assembler template uses the same syntax as [format strings][format-syntax] (i.e. placeholders are specified by curly braces). The corresponding arguments are accessed in order, by index, or by name. However, implicit named arguments (introduced by [RFC #2795][rfc-2795]) are not supported.
3148
3149An `asm!` invocation may have one or more template string arguments; an `asm!` with multiple template string arguments is treated as if all the strings were concatenated with a `\n` between them. The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments.
3150
3151As with format strings, named arguments must appear after positional arguments. Explicit register operands must appear at the end of the operand list, after named arguments if any.
3152
3153Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated.
3154
3155The exact assembly code syntax is target-specific and opaque to the compiler except for the way operands are substituted into the template string to form the code passed to the assembler.
3156
3157The 5 targets specified in this RFC (x86, ARM, AArch64, RISC-V, Hexagon) all use the assembly code syntax of the GNU assembler (GAS). On x86, the `.intel_syntax noprefix` mode of GAS is used by default. On ARM, the `.syntax unified` mode is used. These targets impose an additional restriction on the assembly code: any assembler state (e.g. the current section which can be changed with `.section`) must be restored to its original value at the end of the asm string. Assembly code that does not conform to the GAS syntax will result in assembler-specific behavior.
3158
3159[rfc-2795]: https://github.com/rust-lang/rfcs/pull/2795
3160
3161## Operand type
3162
3163Several types of operands are supported:
3164
3165* `in(<reg>) <expr>`
3166 - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
3167 - The allocated register will contain the value of `<expr>` at the start of the asm code.
3168 - The allocated register must contain the same value at the end of the asm code (except if a `lateout` is allocated to the same register).
3169* `out(<reg>) <expr>`
3170 - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
3171 - The allocated register will contain an undefined value at the start of the asm code.
3172 - `<expr>` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.
3173 - An underscore (`_`) may be specified instead of an expression, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).
3174* `lateout(<reg>) <expr>`
3175 - Identical to `out` except that the register allocator can reuse a register allocated to an `in`.
3176 - You should only write to the register after all inputs are read, otherwise you may clobber an input.
3177* `inout(<reg>) <expr>`
3178 - `<reg>` can refer to a register class or an explicit register. The allocated register name is substituted into the asm template string.
3179 - The allocated register will contain the value of `<expr>` at the start of the asm code.
3180 - `<expr>` must be a mutable initialized place expression, to which the contents of the allocated register is written to at the end of the asm code.
3181* `inout(<reg>) <in expr> => <out expr>`
3182 - Same as `inout` except that the initial value of the register is taken from the value of `<in expr>`.
3183 - `<out expr>` must be a (possibly uninitialized) place expression, to which the contents of the allocated register is written to at the end of the asm code.
3184 - An underscore (`_`) may be specified instead of an expression for `<out expr>`, which will cause the contents of the register to be discarded at the end of the asm code (effectively acting as a clobber).
3185 - `<in expr>` and `<out expr>` may have different types.
3186* `inlateout(<reg>) <expr>` / `inlateout(<reg>) <in expr> => <out expr>`
3187 - Identical to `inout` except that the register allocator can reuse a register allocated to an `in` (this can happen if the compiler knows the `in` has the same initial value as the `inlateout`).
3188 - You should only write to the register after all inputs are read, otherwise you may clobber an input.
3189* `const <expr>`
3190 - `<expr>` must be an integer or floating-point constant expression.
3191 - The value of the expression is formatted as a string and substituted directly into the asm template string.
3192* `sym <path>`
3193 - `<path>` must refer to a `fn` or `static`.
3194 - A mangled symbol name referring to the item is substituted into the asm template string.
3195 - The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).
3196 - `<path>` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data.
3197
3198Operand expressions are evaluated from left to right, just like function call arguments. After the `asm!` has executed, outputs are written to in left to right order. This is significant if two outputs point to the same place: that place will contain the value of the rightmost output.
3199
3200## Register operands
3201
3202Input and output operands can be specified either as an explicit register or as a register class from which the register allocator can select a register. Explicit registers are specified as string literals (e.g. `"eax"`) while register classes are specified as identifiers (e.g. `reg`). Using string literals for register names enables support for architectures that use special characters in register names, such as MIPS (`$0`, `$1`, etc).
3203
3204Note that explicit registers treat register aliases (e.g. `r14` vs `lr` on ARM) and smaller views of a register (e.g. `eax` vs `rax`) as equivalent to the base register. It is a compile-time error to use the same explicit register for two input operands or two output operands. Additionally, it is also a compile-time error to use overlapping registers (e.g. ARM VFP) in input operands or in output operands.
3205
3206Only the following types are allowed as operands for inline assembly:
3207- Integers (signed and unsigned)
3208- Floating-point numbers
3209- Pointers (thin only)
3210- Function pointers
3211- SIMD vectors (structs defined with `#[repr(simd)]` and which implement `Copy`). This includes architecture-specific vector types defined in `std::arch` such as `__m128` (x86) or `int8x16_t` (ARM).
3212
3213Here is the list of currently supported register classes:
3214
3215| Architecture | Register class | Registers | LLVM constraint code |
3216| ------------ | -------------- | --------- | -------------------- |
3217| x86 | `reg` | `ax`, `bx`, `cx`, `dx`, `si`, `di`, `r[8-15]` (x86-64 only) | `r` |
3218| x86 | `reg_abcd` | `ax`, `bx`, `cx`, `dx` | `Q` |
3219| x86-32 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `ah`, `bh`, `ch`, `dh` | `q` |
3220| x86-64 | `reg_byte` | `al`, `bl`, `cl`, `dl`, `sil`, `dil`, `r[8-15]b`, `ah`\*, `bh`\*, `ch`\*, `dh`\* | `q` |
3221| x86 | `xmm_reg` | `xmm[0-7]` (x86) `xmm[0-15]` (x86-64) | `x` |
3222| x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
3223| x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
3224| x86 | `kreg` | `k[1-7]` | `Yk` |
3225| AArch64 | `reg` | `x[0-28]`, `x30` | `r` |
3226| AArch64 | `vreg` | `v[0-31]` | `w` |
3227| AArch64 | `vreg_low16` | `v[0-15]` | `x` |
3228| ARM | `reg` | `r[0-5]` `r7`\*, `r[8-10]`, `r11`\*, `r12`, `r14` | `r` |
3229| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
3230| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |
3231| ARM | `sreg` | `s[0-31]` | `t` |
3232| ARM | `sreg_low16` | `s[0-15]` | `x` |
3233| ARM | `dreg` | `d[0-31]` | `w` |
3234| ARM | `dreg_low16` | `d[0-15]` | `t` |
3235| ARM | `dreg_low8` | `d[0-8]` | `x` |
3236| ARM | `qreg` | `q[0-15]` | `w` |
3237| ARM | `qreg_low8` | `q[0-7]` | `t` |
3238| ARM | `qreg_low4` | `q[0-3]` | `x` |
3239| MIPS | `reg` | `$[2-25]` | `r` |
3240| MIPS | `freg` | `$f[0-31]` | `f` |
3241| NVPTX | `reg16` | None\* | `h` |
3242| NVPTX | `reg32` | None\* | `r` |
3243| NVPTX | `reg64` | None\* | `l` |
3244| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
3245| RISC-V | `freg` | `f[0-31]` | `f` |
3246| Hexagon | `reg` | `r[0-28]` | `r` |
3247| wasm32 | `local` | None\* | `r` |
3248
3249> **Note**: On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register.
3250>
3251> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.
3252>
3253> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
3254>
3255> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
3256>
3257> Note #5: WebAssembly doesn't have registers, so named registers are not supported.
3258
3259Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
3260
3261Each register class has constraints on which value types they can be used with. This is necessary because the way a value is loaded into a register depends on its type. For example, on big-endian systems, loading a `i32x4` and a `i8x16` into a SIMD register may result in different register contents even if the byte-wise memory representation of both values is identical. The availability of supported types for a particular register class may depend on what target features are currently enabled.
3262
3263| Architecture | Register class | Target feature | Allowed types |
3264| ------------ | -------------- | -------------- | ------------- |
3265| x86-32 | `reg` | None | `i16`, `i32`, `f32` |
3266| x86-64 | `reg` | None | `i16`, `i32`, `f32`, `i64`, `f64` |
3267| x86 | `reg_byte` | None | `i8` |
3268| x86 | `xmm_reg` | `sse` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
3269| x86 | `ymm_reg` | `avx` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` <br> `i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` |
3270| x86 | `zmm_reg` | `avx512f` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` <br> `i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` <br> `i8x64`, `i16x32`, `i32x16`, `i64x8`, `f32x16`, `f64x8` |
3271| x86 | `kreg` | `axv512f` | `i8`, `i16` |
3272| x86 | `kreg` | `axv512bw` | `i32`, `i64` |
3273| AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
3274| AArch64 | `vreg` | `fp` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
3275| ARM | `reg` | None | `i8`, `i16`, `i32`, `f32` |
3276| ARM | `sreg` | `vfp2` | `i32`, `f32` |
3277| ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
3278| ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
3279| MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
3280| MIPS32 | `freg` | None | `f32`, `f64` |
3281| MIPS64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
3282| MIPS64 | `freg` | None | `f32`, `f64` |
3283| NVPTX | `reg16` | None | `i8`, `i16` |
3284| NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
3285| NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
3286| RISC-V32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
3287| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
3288| RISC-V | `freg` | `f` | `f32` |
3289| RISC-V | `freg` | `d` | `f64` |
3290| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
3291| wasm32 | `local` | None | `i8` `i16` `i32` `i64` `f32` `f64` |
3292
3293> **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target).
3294
3295If a value is of a smaller size than the register it is allocated in then the upper bits of that register will have an undefined value for inputs and will be ignored for outputs. The only exception is the `freg` register class on RISC-V where `f32` values are NaN-boxed in a `f64` as required by the RISC-V architecture.
3296
3297When separate input and output expressions are specified for an `inout` operand, both expressions must have the same type. The only exception is if both operands are pointers or integers, in which case they are only required to have the same size. This restriction exists because the register allocators in LLVM and GCC sometimes cannot handle tied operands with different types.
3298
3299## Register names
3300
3301Some registers have multiple names. These are all treated by the compiler as identical to the base register name. Here is the list of all supported register aliases:
3302
3303| Architecture | Base register | Aliases |
3304| ------------ | ------------- | ------- |
3305| x86 | `ax` | `eax`, `rax` |
3306| x86 | `bx` | `ebx`, `rbx` |
3307| x86 | `cx` | `ecx`, `rcx` |
3308| x86 | `dx` | `edx`, `rdx` |
3309| x86 | `si` | `esi`, `rsi` |
3310| x86 | `di` | `edi`, `rdi` |
3311| x86 | `bp` | `bpl`, `ebp`, `rbp` |
3312| x86 | `sp` | `spl`, `esp`, `rsp` |
3313| x86 | `ip` | `eip`, `rip` |
3314| x86 | `st(0)` | `st` |
3315| x86 | `r[8-15]` | `r[8-15]b`, `r[8-15]w`, `r[8-15]d` |
3316| x86 | `xmm[0-31]` | `ymm[0-31]`, `zmm[0-31]` |
3317| AArch64 | `x[0-30]` | `w[0-30]` |
3318| AArch64 | `x29` | `fp` |
3319| AArch64 | `x30` | `lr` |
3320| AArch64 | `sp` | `wsp` |
3321| AArch64 | `xzr` | `wzr` |
3322| AArch64 | `v[0-31]` | `b[0-31]`, `h[0-31]`, `s[0-31]`, `d[0-31]`, `q[0-31]` |
3323| ARM | `r[0-3]` | `a[1-4]` |
3324| ARM | `r[4-9]` | `v[1-6]` |
3325| ARM | `r9` | `rfp` |
3326| ARM | `r10` | `sl` |
3327| ARM | `r11` | `fp` |
3328| ARM | `r12` | `ip` |
3329| ARM | `r13` | `sp` |
3330| ARM | `r14` | `lr` |
3331| ARM | `r15` | `pc` |
3332| RISC-V | `x0` | `zero` |
3333| RISC-V | `x1` | `ra` |
3334| RISC-V | `x2` | `sp` |
3335| RISC-V | `x3` | `gp` |
3336| RISC-V | `x4` | `tp` |
3337| RISC-V | `x[5-7]` | `t[0-2]` |
3338| RISC-V | `x8` | `fp`, `s0` |
3339| RISC-V | `x9` | `s1` |
3340| RISC-V | `x[10-17]` | `a[0-7]` |
3341| RISC-V | `x[18-27]` | `s[2-11]` |
3342| RISC-V | `x[28-31]` | `t[3-6]` |
3343| RISC-V | `f[0-7]` | `ft[0-7]` |
3344| RISC-V | `f[8-9]` | `fs[0-1]` |
3345| RISC-V | `f[10-17]` | `fa[0-7]` |
3346| RISC-V | `f[18-27]` | `fs[2-11]` |
3347| RISC-V | `f[28-31]` | `ft[8-11]` |
3348| Hexagon | `r29` | `sp` |
3349| Hexagon | `r30` | `fr` |
3350| Hexagon | `r31` | `lr` |
3351
3352Some registers cannot be used for input or output operands:
3353
3354| Architecture | Unsupported register | Reason |
3355| ------------ | -------------------- | ------ |
3356| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
3357| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. |
3358| ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
3359| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |
3360| x86 | `k0` | This is a constant zero register which can't be modified. |
3361| x86 | `ip` | This is the program counter, not a real register. |
3362| x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |
3363| x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |
3364| AArch64 | `xzr` | This is a constant zero register which can't be modified. |
3365| ARM | `pc` | This is the program counter, not a real register. |
3366| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
3367| MIPS | `$1` or `$at` | Reserved for assembler. |
3368| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
3369| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
3370| MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
3371| RISC-V | `x0` | This is a constant zero register which can't be modified. |
3372| RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
3373| Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
3374
3375In some cases LLVM will allocate a "reserved register" for `reg` operands even though this register cannot be explicitly specified. Assembly code making use of reserved registers should be careful since `reg` operands may alias with those registers. Reserved registers are:
3376- The frame pointer on all architectures.
3377- `r6` on ARM.
3378
3379## Template modifiers
3380
3381The placeholders can be augmented by modifiers which are specified after the `:` in the curly braces. These modifiers do not affect register allocation, but change the way operands are formatted when inserted into the template string. Only one modifier is allowed per template placeholder.
3382
3383The supported modifiers are a subset of LLVM's (and GCC's) [asm template argument modifiers][llvm-argmod], but do not use the same letter codes.
3384
3385| Architecture | Register class | Modifier | Example output | LLVM modifier |
3386| ------------ | -------------- | -------- | -------------- | ------------- |
3387| x86-32 | `reg` | None | `eax` | `k` |
3388| x86-64 | `reg` | None | `rax` | `q` |
3389| x86-32 | `reg_abcd` | `l` | `al` | `b` |
3390| x86-64 | `reg` | `l` | `al` | `b` |
3391| x86 | `reg_abcd` | `h` | `ah` | `h` |
3392| x86 | `reg` | `x` | `ax` | `w` |
3393| x86 | `reg` | `e` | `eax` | `k` |
3394| x86-64 | `reg` | `r` | `rax` | `q` |
3395| x86 | `reg_byte` | None | `al` / `ah` | None |
3396| x86 | `xmm_reg` | None | `xmm0` | `x` |
3397| x86 | `ymm_reg` | None | `ymm0` | `t` |
3398| x86 | `zmm_reg` | None | `zmm0` | `g` |
3399| x86 | `*mm_reg` | `x` | `xmm0` | `x` |
3400| x86 | `*mm_reg` | `y` | `ymm0` | `t` |
3401| x86 | `*mm_reg` | `z` | `zmm0` | `g` |
3402| x86 | `kreg` | None | `k1` | None |
3403| AArch64 | `reg` | None | `x0` | `x` |
3404| AArch64 | `reg` | `w` | `w0` | `w` |
3405| AArch64 | `reg` | `x` | `x0` | `x` |
3406| AArch64 | `vreg` | None | `v0` | None |
3407| AArch64 | `vreg` | `v` | `v0` | None |
3408| AArch64 | `vreg` | `b` | `b0` | `b` |
3409| AArch64 | `vreg` | `h` | `h0` | `h` |
3410| AArch64 | `vreg` | `s` | `s0` | `s` |
3411| AArch64 | `vreg` | `d` | `d0` | `d` |
3412| AArch64 | `vreg` | `q` | `q0` | `q` |
3413| ARM | `reg` | None | `r0` | None |
3414| ARM | `sreg` | None | `s0` | None |
3415| ARM | `dreg` | None | `d0` | `P` |
3416| ARM | `qreg` | None | `q0` | `q` |
3417| ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
3418| MIPS | `reg` | None | `$2` | None |
3419| MIPS | `freg` | None | `$f0` | None |
3420| NVPTX | `reg16` | None | `rs0` | None |
3421| NVPTX | `reg32` | None | `r0` | None |
3422| NVPTX | `reg64` | None | `rd0` | None |
3423| RISC-V | `reg` | None | `x1` | None |
3424| RISC-V | `freg` | None | `f0` | None |
3425| Hexagon | `reg` | None | `r0` | None |
3426
3427> Notes:
3428> - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register.
3429> - on x86: our behavior for `reg` with no modifiers differs from what GCC does. GCC will infer the modifier based on the operand value type, while we default to the full register size.
3430> - on x86 `xmm_reg`: the `x`, `t` and `g` LLVM modifiers are not yet implemented in LLVM (they are supported by GCC only), but this should be a simple change.
3431
3432As stated in the previous section, passing an input value smaller than the register width will result in the upper bits of the register containing undefined values. This is not a problem if the inline asm only accesses the lower bits of the register, which can be done by using a template modifier to use a subregister name in the asm code (e.g. `ax` instead of `rax`). Since this an easy pitfall, the compiler will suggest a template modifier to use where appropriate given the input type. If all references to an operand already have modifiers then the warning is suppressed for that operand.
3433
3434[llvm-argmod]: http://llvm.org/docs/LangRef.html#asm-template-argument-modifiers
3435
3436## Options
3437
3438Flags are used to further influence the behavior of the inline assembly block.
3439Currently the following options are defined:
3440- `pure`: The `asm` block has no side effects, and its outputs depend only on its direct inputs (i.e. the values themselves, not what they point to) or values read from memory (unless the `nomem` options is also set). This allows the compiler to execute the `asm` block fewer times than specified in the program (e.g. by hoisting it out of a loop) or even eliminate it entirely if the outputs are not used.
3441- `nomem`: The `asm` blocks does not read or write to any memory. This allows the compiler to cache the values of modified global variables in registers across the `asm` block since it knows that they are not read or written to by the `asm`.
3442- `readonly`: The `asm` block does not write to any memory. This allows the compiler to cache the values of unmodified global variables in registers across the `asm` block since it knows that they are not written to by the `asm`.
3443- `preserves_flags`: The `asm` block does not modify the flags register (defined in the rules below). This allows the compiler to avoid recomputing the condition flags after the `asm` block.
3444- `noreturn`: The `asm` block never returns, and its return type is defined as `!` (never). Behavior is undefined if execution falls through past the end of the asm code. A `noreturn` asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.
3445- `nostack`: The `asm` block does not push data to the stack, or write to the stack red-zone (if supported by the target). If this option is *not* used then the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
3446- `att_syntax`: This option is only valid on x86, and causes the assembler to use the `.att_syntax prefix` mode of the GNU assembler. Register operands are substituted in with a leading `%`.
3447
3448The compiler performs some additional checks on options:
3449- The `nomem` and `readonly` options are mutually exclusive: it is a compile-time error to specify both.
3450- The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted.
3451- It is a compile-time error to specify `pure` on an asm block with no outputs or only discarded outputs (`_`).
3452- It is a compile-time error to specify `noreturn` on an asm block with outputs.
3453
3454## Rules for inline assembly
3455
3456- Any registers not specified as inputs will contain an undefined value on entry to the asm block.
3457 - An "undefined value" in the context of inline assembly means that the register can (non-deterministically) have any one of the possible values allowed by the architecture. Notably it is not the same as an LLVM `undef` which can have a different value every time you read it (since such a concept does not exist in assembly code).
3458- Any registers not specified as outputs must have the same value upon exiting the asm block as they had on entry, otherwise behavior is undefined.
3459 - This only applies to registers which can be specified as an input or output. Other registers follow target-specific rules.
3460 - Note that a `lateout` may be allocated to the same register as an `in`, in which case this rule does not apply. Code should not rely on this however since it depends on the results of register allocation.
3461- Behavior is undefined if execution unwinds out of an asm block.
3462 - This also applies if the assembly code calls a function which then unwinds.
3463- The set of memory locations that assembly code is allowed the read and write are the same as those allowed for an FFI function.
3464 - Refer to the unsafe code guidelines for the exact rules.
3465 - If the `readonly` option is set, then only memory reads are allowed.
3466 - If the `nomem` option is set then no reads or writes to memory are allowed.
3467 - These rules do not apply to memory which is private to the asm code, such as stack space allocated within the asm block.
3468- The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed.
3469 - This effectively means that the compiler must treat the `asm!` as a black box and only take the interface specification into account, not the instructions themselves.
3470 - Runtime code patching is allowed, via target-specific mechanisms (outside the scope of this RFC).
3471- Unless the `nostack` option is set, asm code is allowed to use stack space below the stack pointer.
3472 - On entry to the asm block the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call.
3473 - You are responsible for making sure you don't overflow the stack (e.g. use stack probing to ensure you hit a guard page).
3474 - You should adjust the stack pointer when allocating stack memory as required by the target ABI.
3475 - The stack pointer must be restored to its original value before leaving the asm block.
3476- If the `noreturn` option is set then behavior is undefined if execution falls through to the end of the asm block.
3477- If the `pure` option is set then behavior is undefined if the `asm` has side-effects other than its direct outputs. Behavior is also undefined if two executions of the `asm` code with the same inputs result in different outputs.
3478 - When used with the `nomem` option, "inputs" are just the direct inputs of the `asm!`.
3479 - When used with the `readonly` option, "inputs" comprise the direct inputs of the `asm!` and any memory that the `asm!` block is allowed to read.
3480- These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:
3481 - x86
3482 - Status flags in `EFLAGS` (CF, PF, AF, ZF, SF, OF).
3483 - Floating-point status word (all).
3484 - Floating-point exception flags in `MXCSR` (PE, UE, OE, ZE, DE, IE).
3485 - ARM
3486 - Condition flags in `CPSR` (N, Z, C, V)
3487 - Saturation flag in `CPSR` (Q)
3488 - Greater than or equal flags in `CPSR` (GE).
3489 - Condition flags in `FPSCR` (N, Z, C, V)
3490 - Saturation flag in `FPSCR` (QC)
3491 - Floating-point exception flags in `FPSCR` (IDC, IXC, UFC, OFC, DZC, IOC).
3492 - AArch64
3493 - Condition flags (`NZCV` register).
3494 - Floating-point status (`FPSR` register).
3495 - RISC-V
3496 - Floating-point exception flags in `fcsr` (`fflags`).
3497- On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit.
3498 - Behavior is undefined if the direction flag is set on exiting an asm block.
3499- The requirement of restoring the stack pointer and non-output registers to their original value only applies when exiting an `asm!` block.
3500 - This means that `asm!` blocks that never return (even if not marked `noreturn`) don't need to preserve these registers.
3501 - When returning to a different `asm!` block than you entered (e.g. for context switching), these registers must contain the value they had upon entering the `asm!` block that you are *exiting*.
3502 - You cannot exit an `asm!` block that has not been entered. Neither can you exit an `asm!` block that has already been exited.
3503 - You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).
3504 - The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.
3505- You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.
3506 - As a consequence, you should only use [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.
3507
3508> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
3509
3510[local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
3511"##,
3512 },
3513 LintCompletion {
3514 label: "flt2dec",
3515 description: r##"# `flt2dec`
3516
3517This feature is internal to the Rust compiler and is not intended for general use.
3518
3519------------------------
3520"##,
3521 },
3522 LintCompletion {
3523 label: "global_asm",
3524 description: r##"# `global_asm`
3525
3526The tracking issue for this feature is: [#35119]
3527
3528[#35119]: https://github.com/rust-lang/rust/issues/35119
3529
3530------------------------
3531
3532The `global_asm!` macro allows the programmer to write arbitrary
3533assembly outside the scope of a function body, passing it through
3534`rustc` and `llvm` to the assembler. The macro is a no-frills
3535interface to LLVM's concept of [module-level inline assembly]. That is,
3536all caveats applicable to LLVM's module-level inline assembly apply
3537to `global_asm!`.
3538
3539[module-level inline assembly]: http://llvm.org/docs/LangRef.html#module-level-inline-assembly
3540
3541`global_asm!` fills a role not currently satisfied by either `asm!`
3542or `#[naked]` functions. The programmer has _all_ features of the
3543assembler at their disposal. The linker will expect to resolve any
3544symbols defined in the inline assembly, modulo any symbols marked as
3545external. It also means syntax for directives and assembly follow the
3546conventions of the assembler in your toolchain.
3547
3548A simple usage looks like this:
3549
3550```rust,ignore (requires-external-file)
3551#![feature(global_asm)]
3552# // you also need relevant target_arch cfgs
3553global_asm!(include_str!("something_neato.s"));
3554```
3555
3556And a more complicated usage looks like this:
3557
3558```rust,no_run
3559#![feature(global_asm)]
3560# #[cfg(any(target_arch="x86", target_arch="x86_64"))]
3561# mod x86 {
3562
3563pub mod sally {
3564 global_asm!(r#"
3565 .global foo
3566 foo:
3567 jmp baz
3568 "#);
3569
3570 #[no_mangle]
3571 pub unsafe extern "C" fn baz() {}
3572}
3573
3574// the symbols `foo` and `bar` are global, no matter where
3575// `global_asm!` was used.
3576extern "C" {
3577 fn foo();
3578 fn bar();
3579}
3580
3581pub mod harry {
3582 global_asm!(r#"
3583 .global bar
3584 bar:
3585 jmp quux
3586 "#);
3587
3588 #[no_mangle]
3589 pub unsafe extern "C" fn quux() {}
3590}
3591# }
3592```
3593
3594You may use `global_asm!` multiple times, anywhere in your crate, in
3595whatever way suits you. The effect is as if you concatenated all
3596usages and placed the larger, single usage in the crate root.
3597
3598------------------------
3599
3600If you don't need quite as much power and flexibility as
3601`global_asm!` provides, and you don't mind restricting your inline
3602assembly to `fn` bodies only, you might try the
3603[asm](asm.md) feature instead.
3604"##,
3605 },
3606 LintCompletion {
3607 label: "derive_eq",
3608 description: r##"# `derive_eq`
3609
3610This feature is internal to the Rust compiler and is not intended for general use.
3611
3612------------------------
3613"##,
3614 },
3615 LintCompletion {
3616 label: "default_free_fn",
3617 description: r##"# `default_free_fn`
3618
3619The tracking issue for this feature is: [#73014]
3620
3621[#73014]: https://github.com/rust-lang/rust/issues/73014
3622
3623------------------------
3624
3625Adds a free `default()` function to the `std::default` module. This function
3626just forwards to [`Default::default()`], but may remove repetition of the word
3627"default" from the call site.
3628
3629[`Default::default()`]: https://doc.rust-lang.org/nightly/std/default/trait.Default.html#tymethod.default
3630
3631Here is an example:
3632
3633```rust
3634#![feature(default_free_fn)]
3635use std::default::default;
3636
3637#[derive(Default)]
3638struct AppConfig {
3639 foo: FooConfig,
3640 bar: BarConfig,
3641}
3642
3643#[derive(Default)]
3644struct FooConfig {
3645 foo: i32,
3646}
3647
3648#[derive(Default)]
3649struct BarConfig {
3650 bar: f32,
3651 baz: u8,
3652}
3653
3654fn main() {
3655 let options = AppConfig {
3656 foo: default(),
3657 bar: BarConfig {
3658 bar: 10.1,
3659 ..default()
3660 },
3661 };
3662}
3663```
3664"##,
3665 },
3666 LintCompletion {
3667 label: "char_error_internals",
3668 description: r##"# `char_error_internals`
3669
3670This feature is internal to the Rust compiler and is not intended for general use.
3671
3672------------------------
3673"##,
3674 },
3675 LintCompletion {
3676 label: "libstd_sys_internals",
3677 description: r##"# `libstd_sys_internals`
3678
3679This feature is internal to the Rust compiler and is not intended for general use.
3680
3681------------------------
3682"##,
3683 },
3684 LintCompletion {
3685 label: "is_sorted",
3686 description: r##"# `is_sorted`
3687
3688The tracking issue for this feature is: [#53485]
3689
3690[#53485]: https://github.com/rust-lang/rust/issues/53485
3691
3692------------------------
3693
3694Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`;
3695add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to
3696`Iterator`.
3697"##,
3698 },
3699 LintCompletion {
3700 label: "c_void_variant",
3701 description: r##"# `c_void_variant`
3702
3703This feature is internal to the Rust compiler and is not intended for general use.
3704
3705------------------------
3706"##,
3707 },
3708 LintCompletion {
3709 label: "concat_idents",
3710 description: r##"# `concat_idents`
3711
3712The tracking issue for this feature is: [#29599]
3713
3714[#29599]: https://github.com/rust-lang/rust/issues/29599
3715
3716------------------------
3717
3718The `concat_idents` feature adds a macro for concatenating multiple identifiers
3719into one identifier.
3720
3721## Examples
3722
3723```rust
3724#![feature(concat_idents)]
3725
3726fn main() {
3727 fn foobar() -> u32 { 23 }
3728 let f = concat_idents!(foo, bar);
3729 assert_eq!(f(), 23);
3730}
3731```
3732"##,
3733 },
3734 LintCompletion {
3735 label: "format_args_capture",
3736 description: r##"# `format_args_capture`
3737
3738The tracking issue for this feature is: [#67984]
3739
3740[#67984]: https://github.com/rust-lang/rust/issues/67984
3741
3742------------------------
3743
3744Enables `format_args!` (and macros which use `format_args!` in their implementation, such
3745as `format!`, `print!` and `panic!`) to capture variables from the surrounding scope.
3746This avoids the need to pass named parameters when the binding in question
3747already exists in scope.
3748
3749```rust
3750#![feature(format_args_capture)]
3751
3752let (person, species, name) = ("Charlie Brown", "dog", "Snoopy");
3753
3754// captures named argument `person`
3755print!("Hello {person}");
3756
3757// captures named arguments `species` and `name`
3758format!("The {species}'s name is {name}.");
3759```
3760
3761This also works for formatting parameters such as width and precision:
3762
3763```rust
3764#![feature(format_args_capture)]
3765
3766let precision = 2;
3767let s = format!("{:.precision$}", 1.324223);
3768
3769assert_eq!(&s, "1.32");
3770```
3771
3772A non-exhaustive list of macros which benefit from this functionality include:
3773- `format!`
3774- `print!` and `println!`
3775- `eprint!` and `eprintln!`
3776- `write!` and `writeln!`
3777- `panic!`
3778- `unreachable!`
3779- `unimplemented!`
3780- `todo!`
3781- `assert!` and similar
3782- macros in many thirdparty crates, such as `log`
3783"##,
3784 },
3785 LintCompletion {
3786 label: "print_internals",
3787 description: r##"# `print_internals`
3788
3789This feature is internal to the Rust compiler and is not intended for general use.
3790
3791------------------------
3792"##,
3793 },
3794 LintCompletion {
3795 label: "llvm_asm",
3796 description: r##"# `llvm_asm`
3797
3798The tracking issue for this feature is: [#70173]
3799
3800[#70173]: https://github.com/rust-lang/rust/issues/70173
3801
3802------------------------
3803
3804For extremely low-level manipulations and performance reasons, one
3805might wish to control the CPU directly. Rust supports using inline
3806assembly to do this via the `llvm_asm!` macro.
3807
3808```rust,ignore (pseudo-code)
3809llvm_asm!(assembly template
3810 : output operands
3811 : input operands
3812 : clobbers
3813 : options
3814 );
3815```
3816
3817Any use of `llvm_asm` is feature gated (requires `#![feature(llvm_asm)]` on the
3818crate to allow) and of course requires an `unsafe` block.
3819
3820> **Note**: the examples here are given in x86/x86-64 assembly, but
3821> all platforms are supported.
3822
3823## Assembly template
3824
3825The `assembly template` is the only required parameter and must be a
3826literal string (i.e. `""`)
3827
3828```rust
3829#![feature(llvm_asm)]
3830
3831#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3832fn foo() {
3833 unsafe {
3834 llvm_asm!("NOP");
3835 }
3836}
3837
3838// Other platforms:
3839#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
3840fn foo() { /* ... */ }
3841
3842fn main() {
3843 // ...
3844 foo();
3845 // ...
3846}
3847```
3848
3849(The `feature(llvm_asm)` and `#[cfg]`s are omitted from now on.)
3850
3851Output operands, input operands, clobbers and options are all optional
3852but you must add the right number of `:` if you skip them:
3853
3854```rust
3855# #![feature(llvm_asm)]
3856# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3857# fn main() { unsafe {
3858llvm_asm!("xor %eax, %eax"
3859 :
3860 :
3861 : "eax"
3862 );
3863# } }
3864# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
3865# fn main() {}
3866```
3867
3868Whitespace also doesn't matter:
3869
3870```rust
3871# #![feature(llvm_asm)]
3872# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3873# fn main() { unsafe {
3874llvm_asm!("xor %eax, %eax" ::: "eax");
3875# } }
3876# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
3877# fn main() {}
3878```
3879
3880## Operands
3881
3882Input and output operands follow the same format: `:
3883"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
3884expressions must be mutable place, or not yet assigned:
3885
3886```rust
3887# #![feature(llvm_asm)]
3888# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3889fn add(a: i32, b: i32) -> i32 {
3890 let c: i32;
3891 unsafe {
3892 llvm_asm!("add $2, $0"
3893 : "=r"(c)
3894 : "0"(a), "r"(b)
3895 );
3896 }
3897 c
3898}
3899# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
3900# fn add(a: i32, b: i32) -> i32 { a + b }
3901
3902fn main() {
3903 assert_eq!(add(3, 14159), 14162)
3904}
3905```
3906
3907If you would like to use real operands in this position, however,
3908you are required to put curly braces `{}` around the register that
3909you want, and you are required to put the specific size of the
3910operand. This is useful for very low level programming, where
3911which register you use is important:
3912
3913```rust
3914# #![feature(llvm_asm)]
3915# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3916# unsafe fn read_byte_in(port: u16) -> u8 {
3917let result: u8;
3918llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port));
3919result
3920# }
3921```
3922
3923## Clobbers
3924
3925Some instructions modify registers which might otherwise have held
3926different values so we use the clobbers list to indicate to the
3927compiler not to assume any values loaded into those registers will
3928stay valid.
3929
3930```rust
3931# #![feature(llvm_asm)]
3932# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3933# fn main() { unsafe {
3934// Put the value 0x200 in eax:
3935llvm_asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
3936# } }
3937# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
3938# fn main() {}
3939```
3940
3941Input and output registers need not be listed since that information
3942is already communicated by the given constraints. Otherwise, any other
3943registers used either implicitly or explicitly should be listed.
3944
3945If the assembly changes the condition code register `cc` should be
3946specified as one of the clobbers. Similarly, if the assembly modifies
3947memory, `memory` should also be specified.
3948
3949## Options
3950
3951The last section, `options` is specific to Rust. The format is comma
3952separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
3953specify some extra info about the inline assembly:
3954
3955Current valid options are:
3956
39571. `volatile` - specifying this is analogous to
3958 `__asm__ __volatile__ (...)` in gcc/clang.
39592. `alignstack` - certain instructions expect the stack to be
3960 aligned a certain way (i.e. SSE) and specifying this indicates to
3961 the compiler to insert its usual stack alignment code
39623. `intel` - use intel syntax instead of the default AT&T.
3963
3964```rust
3965# #![feature(llvm_asm)]
3966# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3967# fn main() {
3968let result: i32;
3969unsafe {
3970 llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
3971}
3972println!("eax is currently {}", result);
3973# }
3974# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
3975# fn main() {}
3976```
3977
3978## More Information
3979
3980The current implementation of the `llvm_asm!` macro is a direct binding to [LLVM's
3981inline assembler expressions][llvm-docs], so be sure to check out [their
3982documentation as well][llvm-docs] for more information about clobbers,
3983constraints, etc.
3984
3985[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
3986
3987If you need more power and don't mind losing some of the niceties of
3988`llvm_asm!`, check out [global_asm](global-asm.md).
3989"##,
3990 },
3991 LintCompletion {
3992 label: "core_intrinsics",
3993 description: r##"# `core_intrinsics`
3994
3995This feature is internal to the Rust compiler and is not intended for general use.
3996
3997------------------------
3998"##,
3999 },
4000 LintCompletion {
4001 label: "trace_macros",
4002 description: r##"# `trace_macros`
4003
4004The tracking issue for this feature is [#29598].
4005
4006[#29598]: https://github.com/rust-lang/rust/issues/29598
4007
4008------------------------
4009
4010With `trace_macros` you can trace the expansion of macros in your code.
4011
4012## Examples
4013
4014```rust
4015#![feature(trace_macros)]
4016
4017fn main() {
4018 trace_macros!(true);
4019 println!("Hello, Rust!");
4020 trace_macros!(false);
4021}
4022```
4023
4024The `cargo build` output:
4025
4026```txt
4027note: trace_macro
4028 --> src/main.rs:5:5
4029 |
40305 | println!("Hello, Rust!");
4031 | ^^^^^^^^^^^^^^^^^^^^^^^^^
4032 |
4033 = note: expanding `println! { "Hello, Rust!" }`
4034 = note: to `print ! ( concat ! ( "Hello, Rust!" , "\n" ) )`
4035 = note: expanding `print! { concat ! ( "Hello, Rust!" , "\n" ) }`
4036 = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( "Hello, Rust!" , "\n" ) )
4037 )`
4038
4039 Finished dev [unoptimized + debuginfo] target(s) in 0.60 secs
4040```
4041"##,
4042 },
4043 LintCompletion {
4044 label: "update_panic_count",
4045 description: r##"# `update_panic_count`
4046
4047This feature is internal to the Rust compiler and is not intended for general use.
4048
4049------------------------
4050"##,
4051 },
4052 LintCompletion {
4053 label: "core_private_bignum",
4054 description: r##"# `core_private_bignum`
4055
4056This feature is internal to the Rust compiler and is not intended for general use.
4057
4058------------------------
4059"##,
4060 },
4061 LintCompletion {
4062 label: "sort_internals",
4063 description: r##"# `sort_internals`
4064
4065This feature is internal to the Rust compiler and is not intended for general use.
4066
4067------------------------
4068"##,
4069 },
4070 LintCompletion {
4071 label: "windows_net",
4072 description: r##"# `windows_net`
4073
4074This feature is internal to the Rust compiler and is not intended for general use.
4075
4076------------------------
4077"##,
4078 },
4079 LintCompletion {
4080 label: "c_variadic",
4081 description: r##"# `c_variadic`
4082
4083The tracking issue for this feature is: [#44930]
4084
4085[#44930]: https://github.com/rust-lang/rust/issues/44930
4086
4087------------------------
4088
4089The `c_variadic` library feature exposes the `VaList` structure,
4090Rust's analogue of C's `va_list` type.
4091
4092## Examples
4093
4094```rust
4095#![feature(c_variadic)]
4096
4097use std::ffi::VaList;
4098
4099pub unsafe extern "C" fn vadd(n: usize, mut args: VaList) -> usize {
4100 let mut sum = 0;
4101 for _ in 0..n {
4102 sum += args.arg::<usize>();
4103 }
4104 sum
4105}
4106```
4107"##,
4108 },
4109 LintCompletion {
4110 label: "core_private_diy_float",
4111 description: r##"# `core_private_diy_float`
4112
4113This feature is internal to the Rust compiler and is not intended for general use.
4114
4115------------------------
4116"##,
4117 },
4118 LintCompletion {
4119 label: "profiler_runtime_lib",
4120 description: r##"# `profiler_runtime_lib`
4121
4122This feature is internal to the Rust compiler and is not intended for general use.
4123
4124------------------------
4125"##,
4126 },
4127 LintCompletion {
4128 label: "thread_local_internals",
4129 description: r##"# `thread_local_internals`
4130
4131This feature is internal to the Rust compiler and is not intended for general use.
4132
4133------------------------
4134"##,
4135 },
4136 LintCompletion {
4137 label: "int_error_internals",
4138 description: r##"# `int_error_internals`
4139
4140This feature is internal to the Rust compiler and is not intended for general use.
4141
4142------------------------
4143"##,
4144 },
4145 LintCompletion {
4146 label: "windows_stdio",
4147 description: r##"# `windows_stdio`
4148
4149This feature is internal to the Rust compiler and is not intended for general use.
4150
4151------------------------
4152"##,
4153 },
4154 LintCompletion {
4155 label: "fmt_internals",
4156 description: r##"# `fmt_internals`
4157
4158This feature is internal to the Rust compiler and is not intended for general use.
4159
4160------------------------
4161"##,
4162 },
4163 LintCompletion {
4164 label: "fd_read",
4165 description: r##"# `fd_read`
4166
4167This feature is internal to the Rust compiler and is not intended for general use.
4168
4169------------------------
4170"##,
4171 },
4172 LintCompletion {
4173 label: "str_internals",
4174 description: r##"# `str_internals`
4175
4176This feature is internal to the Rust compiler and is not intended for general use.
4177
4178------------------------
4179"##,
4180 },
4181 LintCompletion {
4182 label: "test",
4183 description: r##"# `test`
4184
4185The tracking issue for this feature is: None.
4186
4187------------------------
4188
4189The internals of the `test` crate are unstable, behind the `test` flag. The
4190most widely used part of the `test` crate are benchmark tests, which can test
4191the performance of your code. Let's make our `src/lib.rs` look like this
4192(comments elided):
4193
4194```rust,no_run
4195#![feature(test)]
4196
4197extern crate test;
4198
4199pub fn add_two(a: i32) -> i32 {
4200 a + 2
4201}
4202
4203#[cfg(test)]
4204mod tests {
4205 use super::*;
4206 use test::Bencher;
4207
4208 #[test]
4209 fn it_works() {
4210 assert_eq!(4, add_two(2));
4211 }
4212
4213 #[bench]
4214 fn bench_add_two(b: &mut Bencher) {
4215 b.iter(|| add_two(2));
4216 }
4217}
4218```
4219
4220Note the `test` feature gate, which enables this unstable feature.
4221
4222We've imported the `test` crate, which contains our benchmarking support.
4223We have a new function as well, with the `bench` attribute. Unlike regular
4224tests, which take no arguments, benchmark tests take a `&mut Bencher`. This
4225`Bencher` provides an `iter` method, which takes a closure. This closure
4226contains the code we'd like to benchmark.
4227
4228We can run benchmark tests with `cargo bench`:
4229
4230```bash
4231$ cargo bench
4232 Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
4233 Running target/release/adder-91b3e234d4ed382a
4234
4235running 2 tests
4236test tests::it_works ... ignored
4237test tests::bench_add_two ... bench: 1 ns/iter (+/- 0)
4238
4239test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured
4240```
4241
4242Our non-benchmark test was ignored. You may have noticed that `cargo bench`
4243takes a bit longer than `cargo test`. This is because Rust runs our benchmark
4244a number of times, and then takes the average. Because we're doing so little
4245work in this example, we have a `1 ns/iter (+/- 0)`, but this would show
4246the variance if there was one.
4247
4248Advice on writing benchmarks:
4249
4250
4251* Move setup code outside the `iter` loop; only put the part you want to measure inside
4252* Make the code do "the same thing" on each iteration; do not accumulate or change state
4253* Make the outer function idempotent too; the benchmark runner is likely to run
4254 it many times
4255* Make the inner `iter` loop short and fast so benchmark runs are fast and the
4256 calibrator can adjust the run-length at fine resolution
4257* Make the code in the `iter` loop do something simple, to assist in pinpointing
4258 performance improvements (or regressions)
4259
4260## Gotcha: optimizations
4261
4262There's another tricky part to writing benchmarks: benchmarks compiled with
4263optimizations activated can be dramatically changed by the optimizer so that
4264the benchmark is no longer benchmarking what one expects. For example, the
4265compiler might recognize that some calculation has no external effects and
4266remove it entirely.
4267
4268```rust,no_run
4269#![feature(test)]
4270
4271extern crate test;
4272use test::Bencher;
4273
4274#[bench]
4275fn bench_xor_1000_ints(b: &mut Bencher) {
4276 b.iter(|| {
4277 (0..1000).fold(0, |old, new| old ^ new);
4278 });
4279}
4280```
4281
4282gives the following results
4283
4284```text
4285running 1 test
4286test bench_xor_1000_ints ... bench: 0 ns/iter (+/- 0)
4287
4288test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
4289```
4290
4291The benchmarking runner offers two ways to avoid this. Either, the closure that
4292the `iter` method receives can return an arbitrary value which forces the
4293optimizer to consider the result used and ensures it cannot remove the
4294computation entirely. This could be done for the example above by adjusting the
4295`b.iter` call to
4296
4297```rust
4298# struct X;
4299# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
4300b.iter(|| {
4301 // Note lack of `;` (could also use an explicit `return`).
4302 (0..1000).fold(0, |old, new| old ^ new)
4303});
4304```
4305
4306Or, the other option is to call the generic `test::black_box` function, which
4307is an opaque "black box" to the optimizer and so forces it to consider any
4308argument as used.
4309
4310```rust
4311#![feature(test)]
4312
4313extern crate test;
4314
4315# fn main() {
4316# struct X;
4317# impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
4318b.iter(|| {
4319 let n = test::black_box(1000);
4320
4321 (0..n).fold(0, |a, b| a ^ b)
4322})
4323# }
4324```
4325
4326Neither of these read or modify the value, and are very cheap for small values.
4327Larger values can be passed indirectly to reduce overhead (e.g.
4328`black_box(&huge_struct)`).
4329
4330Performing either of the above changes gives the following benchmarking results
4331
4332```text
4333running 1 test
4334test bench_xor_1000_ints ... bench: 131 ns/iter (+/- 3)
4335
4336test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured
4337```
4338
4339However, the optimizer can still modify a testcase in an undesirable manner
4340even when using either of the above.
4341"##,
4342 },
4343 LintCompletion {
4344 label: "windows_c",
4345 description: r##"# `windows_c`
4346
4347This feature is internal to the Rust compiler and is not intended for general use.
4348
4349------------------------
4350"##,
4351 },
4352 LintCompletion {
4353 label: "dec2flt",
4354 description: r##"# `dec2flt`
4355
4356This feature is internal to the Rust compiler and is not intended for general use.
4357
4358------------------------
4359"##,
4360 },
4361 LintCompletion {
4362 label: "derive_clone_copy",
4363 description: r##"# `derive_clone_copy`
4364
4365This feature is internal to the Rust compiler and is not intended for general use.
4366
4367------------------------
4368"##,
4369 },
4370 LintCompletion {
4371 label: "allocator_api",
4372 description: r##"# `allocator_api`
4373
4374The tracking issue for this feature is [#32838]
4375
4376[#32838]: https://github.com/rust-lang/rust/issues/32838
4377
4378------------------------
4379
4380Sometimes you want the memory for one collection to use a different
4381allocator than the memory for another collection. In this case,
4382replacing the global allocator is not a workable option. Instead,
4383you need to pass in an instance of an `AllocRef` to each collection
4384for which you want a custom allocator.
4385
4386TBD
4387"##,
4388 },
4389 LintCompletion {
4390 label: "core_panic",
4391 description: r##"# `core_panic`
4392
4393This feature is internal to the Rust compiler and is not intended for general use.
4394
4395------------------------
4396"##,
4397 },
4398 LintCompletion {
4399 label: "fn_traits",
4400 description: r##"# `fn_traits`
4401
4402The tracking issue for this feature is [#29625]
4403
4404See Also: [`unboxed_closures`](../language-features/unboxed-closures.md)
4405
4406[#29625]: https://github.com/rust-lang/rust/issues/29625
4407
4408----
4409
4410The `fn_traits` feature allows for implementation of the [`Fn*`] traits
4411for creating custom closure-like types.
4412
4413[`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
4414
4415```rust
4416#![feature(unboxed_closures)]
4417#![feature(fn_traits)]
4418
4419struct Adder {
4420 a: u32
4421}
4422
4423impl FnOnce<(u32, )> for Adder {
4424 type Output = u32;
4425 extern "rust-call" fn call_once(self, b: (u32, )) -> Self::Output {
4426 self.a + b.0
4427 }
4428}
4429
4430fn main() {
4431 let adder = Adder { a: 3 };
4432 assert_eq!(adder(2), 5);
4433}
4434```
4435"##,
4436 },
4437 LintCompletion {
4438 label: "try_trait",
4439 description: r##"# `try_trait`
4440
4441The tracking issue for this feature is: [#42327]
4442
4443[#42327]: https://github.com/rust-lang/rust/issues/42327
4444
4445------------------------
4446
4447This introduces a new trait `Try` for extending the `?` operator to types
4448other than `Result` (a part of [RFC 1859]). The trait provides the canonical
4449way to _view_ a type in terms of a success/failure dichotomy. This will
4450allow `?` to supplant the `try_opt!` macro on `Option` and the `try_ready!`
4451macro on `Poll`, among other things.
4452
4453[RFC 1859]: https://github.com/rust-lang/rfcs/pull/1859
4454
4455Here's an example implementation of the trait:
4456
4457```rust,ignore (cannot-reimpl-Try)
4458/// A distinct type to represent the `None` value of an `Option`.
4459///
4460/// This enables using the `?` operator on `Option`; it's rarely useful alone.
4461#[derive(Debug)]
4462#[unstable(feature = "try_trait", issue = "42327")]
4463pub struct None { _priv: () }
4464
4465#[unstable(feature = "try_trait", issue = "42327")]
4466impl<T> ops::Try for Option<T> {
4467 type Ok = T;
4468 type Error = None;
4469
4470 fn into_result(self) -> Result<T, None> {
4471 self.ok_or(None { _priv: () })
4472 }
4473
4474 fn from_ok(v: T) -> Self {
4475 Some(v)
4476 }
4477
4478 fn from_error(_: None) -> Self {
4479 None
4480 }
4481}
4482```
4483
4484Note the `Error` associated type here is a new marker. The `?` operator
4485allows interconversion between different `Try` implementers only when
4486the error type can be converted `Into` the error type of the enclosing
4487function (or catch block). Having a distinct error type (as opposed to
4488just `()`, or similar) restricts this to where it's semantically meaningful.
4489"##,
4490 },
4491 LintCompletion {
4492 label: "rt",
4493 description: r##"# `rt`
4494
4495This feature is internal to the Rust compiler and is not intended for general use.
4496
4497------------------------
4498"##,
4499 },
4500 LintCompletion {
4501 label: "fd",
4502 description: r##"# `fd`
4503
4504This feature is internal to the Rust compiler and is not intended for general use.
4505
4506------------------------
4507"##,
4508 },
4509 LintCompletion {
4510 label: "libstd_thread_internals",
4511 description: r##"# `libstd_thread_internals`
4512
4513This feature is internal to the Rust compiler and is not intended for general use.
4514
4515------------------------
4516"##,
4517 },
4518];
4519
4520pub(super) const CLIPPY_LINTS: &[LintCompletion] = &[
4521 LintCompletion {
4522 label: "clippy::absurd_extreme_comparisons",
4523 description: r##"Checks for comparisons where one side of the relation is\neither the minimum or maximum value for its type and warns if it involves a\ncase that is always true or always false. Only integer and boolean types are\nchecked."##,
4524 },
4525 LintCompletion {
4526 label: "clippy::almost_swapped",
4527 description: r##"Checks for `foo = bar; bar = foo` sequences."##,
4528 },
4529 LintCompletion {
4530 label: "clippy::approx_constant",
4531 description: r##"Checks for floating point literals that approximate\nconstants which are defined in\n[`std::f32::consts`](https://doc.rust-lang.org/stable/std/f32/consts/#constants)\nor\n[`std::f64::consts`](https://doc.rust-lang.org/stable/std/f64/consts/#constants),\nrespectively, suggesting to use the predefined constant."##,
4532 },
4533 LintCompletion {
4534 label: "clippy::as_conversions",
4535 description: r##"Checks for usage of `as` conversions.\n\nNote that this lint is specialized in linting *every single* use of `as`\nregardless of whether good alternatives exist or not.\nIf you want more precise lints for `as`, please consider using these separate lints:\n`unnecessary_cast`, `cast_lossless/possible_truncation/possible_wrap/precision_loss/sign_loss`,\n`fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`.\nThere is a good explanation the reason why this lint should work in this way and how it is useful\n[in this issue](https://github.com/rust-lang/rust-clippy/issues/5122)."##,
4536 },
4537 LintCompletion {
4538 label: "clippy::assertions_on_constants",
4539 description: r##"Checks for `assert!(true)` and `assert!(false)` calls."##,
4540 },
4541 LintCompletion {
4542 label: "clippy::assign_op_pattern",
4543 description: r##"Checks for `a = a op b` or `a = b commutative_op a`\npatterns."##,
4544 },
4545 LintCompletion {
4546 label: "clippy::assign_ops",
4547 description: r##"Nothing. This lint has been deprecated."##,
4548 },
4549 LintCompletion {
4550 label: "clippy::async_yields_async",
4551 description: r##"Checks for async blocks that yield values of types\nthat can themselves be awaited."##,
4552 },
4553 LintCompletion {
4554 label: "clippy::await_holding_lock",
4555 description: r##"Checks for calls to await while holding a\nnon-async-aware MutexGuard."##,
4556 },
4557 LintCompletion {
4558 label: "clippy::await_holding_refcell_ref",
4559 description: r##"Checks for calls to await while holding a\n`RefCell` `Ref` or `RefMut`."##,
4560 },
4561 LintCompletion {
4562 label: "clippy::bad_bit_mask",
4563 description: r##"Checks for incompatible bit masks in comparisons.\n\nThe formula for detecting if an expression of the type `_ <bit_op> m\n<cmp_op> c` (where `<bit_op>` is one of {`&`, `|`} and `<cmp_op>` is one of\n{`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following\ntable:\n\n|Comparison |Bit Op|Example |is always|Formula |\n|------------|------|------------|---------|----------------------|\n|`==` or `!=`| `&` |`x & 2 == 3`|`false` |`c & m != c` |\n|`<` or `>=`| `&` |`x & 2 < 3` |`true` |`m < c` |\n|`>` or `<=`| `&` |`x & 1 > 1` |`false` |`m <= c` |\n|`==` or `!=`| `|` |`x | 1 == 0`|`false` |`c | m != c` |\n|`<` or `>=`| `|` |`x | 1 < 1` |`false` |`m >= c` |\n|`<=` or `>` | `|` |`x | 1 > 0` |`true` |`m > c` |"##,
4564 },
4565 LintCompletion {
4566 label: "clippy::bind_instead_of_map",
4567 description: r##"Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or\n`_.or_else(|x| Err(y))`."##,
4568 },
4569 LintCompletion {
4570 label: "clippy::blacklisted_name",
4571 description: r##"Checks for usage of blacklisted names for variables, such\nas `foo`."##,
4572 },
4573 LintCompletion {
4574 label: "clippy::blanket_clippy_restriction_lints",
4575 description: r##"Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category."##,
4576 },
4577 LintCompletion {
4578 label: "clippy::blocks_in_if_conditions",
4579 description: r##"Checks for `if` conditions that use blocks containing an\nexpression, statements or conditions that use closures with blocks."##,
4580 },
4581 LintCompletion {
4582 label: "clippy::bool_comparison",
4583 description: r##"Checks for expressions of the form `x == true`,\n`x != true` and order comparisons such as `x < true` (or vice versa) and\nsuggest using the variable directly."##,
4584 },
4585 LintCompletion {
4586 label: "clippy::borrow_interior_mutable_const",
4587 description: r##"Checks if `const` items which is interior mutable (e.g.,\ncontains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly."##,
4588 },
4589 LintCompletion {
4590 label: "clippy::borrowed_box",
4591 description: r##"Checks for use of `&Box<T>` anywhere in the code.\nCheck the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##,
4592 },
4593 LintCompletion {
4594 label: "clippy::box_vec",
4595 description: r##"Checks for use of `Box<Vec<_>>` anywhere in the code.\nCheck the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##,
4596 },
4597 LintCompletion {
4598 label: "clippy::boxed_local",
4599 description: r##"Checks for usage of `Box<T>` where an unboxed `T` would\nwork fine."##,
4600 },
4601 LintCompletion {
4602 label: "clippy::builtin_type_shadow",
4603 description: r##"Warns if a generic shadows a built-in type."##,
4604 },
4605 LintCompletion {
4606 label: "clippy::bytes_nth",
4607 description: r##"Checks for the use of `.bytes().nth()`."##,
4608 },
4609 LintCompletion {
4610 label: "clippy::cargo_common_metadata",
4611 description: r##"Checks to see if all common metadata is defined in\n`Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata"##,
4612 },
4613 LintCompletion {
4614 label: "clippy::case_sensitive_file_extension_comparisons",
4615 description: r##"Checks for calls to `ends_with` with possible file extensions\nand suggests to use a case-insensitive approach instead."##,
4616 },
4617 LintCompletion {
4618 label: "clippy::cast_lossless",
4619 description: r##"Checks for casts between numerical types that may\nbe replaced by safe conversion functions."##,
4620 },
4621 LintCompletion {
4622 label: "clippy::cast_possible_truncation",
4623 description: r##"Checks for casts between numerical types that may\ntruncate large values. This is expected behavior, so the cast is `Allow` by\ndefault."##,
4624 },
4625 LintCompletion {
4626 label: "clippy::cast_possible_wrap",
4627 description: r##"Checks for casts from an unsigned type to a signed type of\nthe same size. Performing such a cast is a 'no-op' for the compiler,\ni.e., nothing is changed at the bit level, and the binary representation of\nthe value is reinterpreted. This can cause wrapping if the value is too big\nfor the target signed type. However, the cast works as defined, so this lint\nis `Allow` by default."##,
4628 },
4629 LintCompletion {
4630 label: "clippy::cast_precision_loss",
4631 description: r##"Checks for casts from any numerical to a float type where\nthe receiving type cannot store all values from the original type without\nrounding errors. This possible rounding is to be expected, so this lint is\n`Allow` by default.\n\nBasically, this warns on casting any integer with 32 or more bits to `f32`\nor any 64-bit integer to `f64`."##,
4632 },
4633 LintCompletion {
4634 label: "clippy::cast_ptr_alignment",
4635 description: r##"Checks for casts, using `as` or `pointer::cast`,\nfrom a less-strictly-aligned pointer to a more-strictly-aligned pointer"##,
4636 },
4637 LintCompletion {
4638 label: "clippy::cast_ref_to_mut",
4639 description: r##"Checks for casts of `&T` to `&mut T` anywhere in the code."##,
4640 },
4641 LintCompletion {
4642 label: "clippy::cast_sign_loss",
4643 description: r##"Checks for casts from a signed to an unsigned numerical\ntype. In this case, negative values wrap around to large positive values,\nwhich can be quite surprising in practice. However, as the cast works as\ndefined, this lint is `Allow` by default."##,
4644 },
4645 LintCompletion {
4646 label: "clippy::char_lit_as_u8",
4647 description: r##"Checks for expressions where a character literal is cast\nto `u8` and suggests using a byte literal instead."##,
4648 },
4649 LintCompletion {
4650 label: "clippy::chars_last_cmp",
4651 description: r##"Checks for usage of `_.chars().last()` or\n`_.chars().next_back()` on a `str` to check if it ends with a given char."##,
4652 },
4653 LintCompletion {
4654 label: "clippy::chars_next_cmp",
4655 description: r##"Checks for usage of `.chars().next()` on a `str` to check\nif it starts with a given char."##,
4656 },
4657 LintCompletion {
4658 label: "clippy::checked_conversions",
4659 description: r##"Checks for explicit bounds checking when casting."##,
4660 },
4661 LintCompletion {
4662 label: "clippy::clone_double_ref",
4663 description: r##"Checks for usage of `.clone()` on an `&&T`."##,
4664 },
4665 LintCompletion {
4666 label: "clippy::clone_on_copy",
4667 description: r##"Checks for usage of `.clone()` on a `Copy` type."##,
4668 },
4669 LintCompletion {
4670 label: "clippy::clone_on_ref_ptr",
4671 description: r##"Checks for usage of `.clone()` on a ref-counted pointer,\n(`Rc`, `Arc`, `rc::Weak`, or `sync::Weak`), and suggests calling Clone via unified\nfunction syntax instead (e.g., `Rc::clone(foo)`)."##,
4672 },
4673 LintCompletion { label: "clippy::cmp_nan", description: r##"Checks for comparisons to NaN."## },
4674 LintCompletion {
4675 label: "clippy::cmp_null",
4676 description: r##"This lint checks for equality comparisons with `ptr::null`"##,
4677 },
4678 LintCompletion {
4679 label: "clippy::cmp_owned",
4680 description: r##"Checks for conversions to owned values just for the sake\nof a comparison."##,
4681 },
4682 LintCompletion {
4683 label: "clippy::cognitive_complexity",
4684 description: r##"Checks for methods with high cognitive complexity."##,
4685 },
4686 LintCompletion {
4687 label: "clippy::collapsible_else_if",
4688 description: r##"Checks for collapsible `else { if ... }` expressions\nthat can be collapsed to `else if ...`."##,
4689 },
4690 LintCompletion {
4691 label: "clippy::collapsible_if",
4692 description: r##"Checks for nested `if` statements which can be collapsed\nby `&&`-combining their conditions."##,
4693 },
4694 LintCompletion {
4695 label: "clippy::collapsible_match",
4696 description: r##"Finds nested `match` or `if let` expressions where the patterns may be \"collapsed\" together\nwithout adding any branches.\n\nNote that this lint is not intended to find _all_ cases where nested match patterns can be merged, but only\ncases where merging would most likely make the code more readable."##,
4697 },
4698 LintCompletion {
4699 label: "clippy::comparison_chain",
4700 description: r##"Checks comparison chains written with `if` that can be\nrewritten with `match` and `cmp`."##,
4701 },
4702 LintCompletion {
4703 label: "clippy::comparison_to_empty",
4704 description: r##"Checks for comparing to an empty slice such as `\"\"` or `[]`,\nand suggests using `.is_empty()` where applicable."##,
4705 },
4706 LintCompletion {
4707 label: "clippy::copy_iterator",
4708 description: r##"Checks for types that implement `Copy` as well as\n`Iterator`."##,
4709 },
4710 LintCompletion {
4711 label: "clippy::create_dir",
4712 description: r##"Checks usage of `std::fs::create_dir` and suggest using `std::fs::create_dir_all` instead."##,
4713 },
4714 LintCompletion {
4715 label: "clippy::crosspointer_transmute",
4716 description: r##"Checks for transmutes between a type `T` and `*T`."##,
4717 },
4718 LintCompletion {
4719 label: "clippy::dbg_macro",
4720 description: r##"Checks for usage of dbg!() macro."##,
4721 },
4722 LintCompletion {
4723 label: "clippy::debug_assert_with_mut_call",
4724 description: r##"Checks for function/method calls with a mutable\nparameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros."##,
4725 },
4726 LintCompletion {
4727 label: "clippy::decimal_literal_representation",
4728 description: r##"Warns if there is a better representation for a numeric literal."##,
4729 },
4730 LintCompletion {
4731 label: "clippy::declare_interior_mutable_const",
4732 description: r##"Checks for declaration of `const` items which is interior\nmutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.)."##,
4733 },
4734 LintCompletion {
4735 label: "clippy::default_numeric_fallback",
4736 description: r##"Checks for usage of unconstrained numeric literals which may cause default numeric fallback in type\ninference.\n\nDefault numeric fallback means that if numeric types have not yet been bound to concrete\ntypes at the end of type inference, then integer type is bound to `i32`, and similarly\nfloating type is bound to `f64`.\n\nSee [RFC0212](https://github.com/rust-lang/rfcs/blob/master/text/0212-restore-int-fallback.md) for more information about the fallback."##,
4737 },
4738 LintCompletion {
4739 label: "clippy::default_trait_access",
4740 description: r##"Checks for literal calls to `Default::default()`."##,
4741 },
4742 LintCompletion {
4743 label: "clippy::deprecated_cfg_attr",
4744 description: r##"Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it\nwith `#[rustfmt::skip]`."##,
4745 },
4746 LintCompletion {
4747 label: "clippy::deprecated_semver",
4748 description: r##"Checks for `#[deprecated]` annotations with a `since`\nfield that is not a valid semantic version."##,
4749 },
4750 LintCompletion {
4751 label: "clippy::deref_addrof",
4752 description: r##"Checks for usage of `*&` and `*&mut` in expressions."##,
4753 },
4754 LintCompletion {
4755 label: "clippy::derive_hash_xor_eq",
4756 description: r##"Checks for deriving `Hash` but implementing `PartialEq`\nexplicitly or vice versa."##,
4757 },
4758 LintCompletion {
4759 label: "clippy::derive_ord_xor_partial_ord",
4760 description: r##"Checks for deriving `Ord` but implementing `PartialOrd`\nexplicitly or vice versa."##,
4761 },
4762 LintCompletion {
4763 label: "clippy::disallowed_method",
4764 description: r##"Denies the configured methods and functions in clippy.toml"##,
4765 },
4766 LintCompletion {
4767 label: "clippy::diverging_sub_expression",
4768 description: r##"Checks for diverging calls that are not match arms or\nstatements."##,
4769 },
4770 LintCompletion {
4771 label: "clippy::doc_markdown",
4772 description: r##"Checks for the presence of `_`, `::` or camel-case words\noutside ticks in documentation."##,
4773 },
4774 LintCompletion {
4775 label: "clippy::double_comparisons",
4776 description: r##"Checks for double comparisons that could be simplified to a single expression."##,
4777 },
4778 LintCompletion {
4779 label: "clippy::double_must_use",
4780 description: r##"Checks for a [`#[must_use]`] attribute without\nfurther information on functions and methods that return a type already\nmarked as `#[must_use]`.\n\n[`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"##,
4781 },
4782 LintCompletion {
4783 label: "clippy::double_neg",
4784 description: r##"Detects expressions of the form `--x`."##,
4785 },
4786 LintCompletion {
4787 label: "clippy::double_parens",
4788 description: r##"Checks for unnecessary double parentheses."##,
4789 },
4790 LintCompletion {
4791 label: "clippy::drop_bounds",
4792 description: r##"Nothing. This lint has been deprecated."##,
4793 },
4794 LintCompletion {
4795 label: "clippy::drop_copy",
4796 description: r##"Checks for calls to `std::mem::drop` with a value\nthat derives the Copy trait"##,
4797 },
4798 LintCompletion {
4799 label: "clippy::drop_ref",
4800 description: r##"Checks for calls to `std::mem::drop` with a reference\ninstead of an owned value."##,
4801 },
4802 LintCompletion {
4803 label: "clippy::duplicate_underscore_argument",
4804 description: r##"Checks for function arguments having the similar names\ndiffering by an underscore."##,
4805 },
4806 LintCompletion {
4807 label: "clippy::duration_subsec",
4808 description: r##"Checks for calculation of subsecond microseconds or milliseconds\nfrom other `Duration` methods."##,
4809 },
4810 LintCompletion {
4811 label: "clippy::else_if_without_else",
4812 description: r##"Checks for usage of if expressions with an `else if` branch,\nbut without a final `else` branch."##,
4813 },
4814 LintCompletion {
4815 label: "clippy::empty_enum",
4816 description: r##"Checks for `enum`s with no variants.\n\nAs of this writing, the `never_type` is still a\nnightly-only experimental API. Therefore, this lint is only triggered\nif the `never_type` is enabled."##,
4817 },
4818 LintCompletion {
4819 label: "clippy::empty_line_after_outer_attr",
4820 description: r##"Checks for empty lines after outer attributes"##,
4821 },
4822 LintCompletion {
4823 label: "clippy::empty_loop",
4824 description: r##"Checks for empty `loop` expressions."##,
4825 },
4826 LintCompletion {
4827 label: "clippy::enum_clike_unportable_variant",
4828 description: r##"Checks for C-like enumerations that are\n`repr(isize/usize)` and have values that don't fit into an `i32`."##,
4829 },
4830 LintCompletion {
4831 label: "clippy::enum_glob_use",
4832 description: r##"Checks for `use Enum::*`."##,
4833 },
4834 LintCompletion {
4835 label: "clippy::enum_variant_names",
4836 description: r##"Detects enumeration variants that are prefixed or suffixed\nby the same characters."##,
4837 },
4838 LintCompletion {
4839 label: "clippy::eq_op",
4840 description: r##"Checks for equal operands to comparison, logical and\nbitwise, difference and division binary operators (`==`, `>`, etc., `&&`,\n`||`, `&`, `|`, `^`, `-` and `/`)."##,
4841 },
4842 LintCompletion {
4843 label: "clippy::erasing_op",
4844 description: r##"Checks for erasing operations, e.g., `x * 0`."##,
4845 },
4846 LintCompletion {
4847 label: "clippy::eval_order_dependence",
4848 description: r##"Checks for a read and a write to the same variable where\nwhether the read occurs before or after the write depends on the evaluation\norder of sub-expressions."##,
4849 },
4850 LintCompletion {
4851 label: "clippy::excessive_precision",
4852 description: r##"Checks for float literals with a precision greater\nthan that supported by the underlying type."##,
4853 },
4854 LintCompletion {
4855 label: "clippy::exhaustive_enums",
4856 description: r##"Warns on any exported `enum`s that are not tagged `#[non_exhaustive]`"##,
4857 },
4858 LintCompletion {
4859 label: "clippy::exhaustive_structs",
4860 description: r##"Warns on any exported `structs`s that are not tagged `#[non_exhaustive]`"##,
4861 },
4862 LintCompletion {
4863 label: "clippy::exit",
4864 description: r##"`exit()` terminates the program and doesn't provide a\nstack trace."##,
4865 },
4866 LintCompletion {
4867 label: "clippy::expect_fun_call",
4868 description: r##"Checks for calls to `.expect(&format!(...))`, `.expect(foo(..))`,\netc., and suggests to use `unwrap_or_else` instead"##,
4869 },
4870 LintCompletion {
4871 label: "clippy::expect_used",
4872 description: r##"Checks for `.expect()` calls on `Option`s and `Result`s."##,
4873 },
4874 LintCompletion {
4875 label: "clippy::expl_impl_clone_on_copy",
4876 description: r##"Checks for explicit `Clone` implementations for `Copy`\ntypes."##,
4877 },
4878 LintCompletion {
4879 label: "clippy::explicit_counter_loop",
4880 description: r##"Checks `for` loops over slices with an explicit counter\nand suggests the use of `.enumerate()`."##,
4881 },
4882 LintCompletion {
4883 label: "clippy::explicit_deref_methods",
4884 description: r##"Checks for explicit `deref()` or `deref_mut()` method calls."##,
4885 },
4886 LintCompletion {
4887 label: "clippy::explicit_into_iter_loop",
4888 description: r##"Checks for loops on `y.into_iter()` where `y` will do, and\nsuggests the latter."##,
4889 },
4890 LintCompletion {
4891 label: "clippy::explicit_iter_loop",
4892 description: r##"Checks for loops on `x.iter()` where `&x` will do, and\nsuggests the latter."##,
4893 },
4894 LintCompletion {
4895 label: "clippy::explicit_write",
4896 description: r##"Checks for usage of `write!()` / `writeln()!` which can be\nreplaced with `(e)print!()` / `(e)println!()`"##,
4897 },
4898 LintCompletion {
4899 label: "clippy::extend_from_slice",
4900 description: r##"Nothing. This lint has been deprecated."##,
4901 },
4902 LintCompletion {
4903 label: "clippy::extra_unused_lifetimes",
4904 description: r##"Checks for lifetimes in generics that are never used\nanywhere else."##,
4905 },
4906 LintCompletion {
4907 label: "clippy::fallible_impl_from",
4908 description: r##"Checks for impls of `From<..>` that contain `panic!()` or `unwrap()`"##,
4909 },
4910 LintCompletion {
4911 label: "clippy::field_reassign_with_default",
4912 description: r##"Checks for immediate reassignment of fields initialized\nwith Default::default()."##,
4913 },
4914 LintCompletion {
4915 label: "clippy::filetype_is_file",
4916 description: r##"Checks for `FileType::is_file()`."##,
4917 },
4918 LintCompletion {
4919 label: "clippy::filter_map",
4920 description: r##"Checks for usage of `_.filter(_).map(_)`,\n`_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar."##,
4921 },
4922 LintCompletion {
4923 label: "clippy::filter_map_identity",
4924 description: r##"Checks for usage of `filter_map(|x| x)`."##,
4925 },
4926 LintCompletion {
4927 label: "clippy::filter_map_next",
4928 description: r##"Checks for usage of `_.filter_map(_).next()`."##,
4929 },
4930 LintCompletion {
4931 label: "clippy::filter_next",
4932 description: r##"Checks for usage of `_.filter(_).next()`."##,
4933 },
4934 LintCompletion {
4935 label: "clippy::find_map",
4936 description: r##"Nothing. This lint has been deprecated."##,
4937 },
4938 LintCompletion {
4939 label: "clippy::flat_map_identity",
4940 description: r##"Checks for usage of `flat_map(|x| x)`."##,
4941 },
4942 LintCompletion {
4943 label: "clippy::float_arithmetic",
4944 description: r##"Checks for float arithmetic."##,
4945 },
4946 LintCompletion {
4947 label: "clippy::float_cmp",
4948 description: r##"Checks for (in-)equality comparisons on floating-point\nvalues (apart from zero), except in functions called `*eq*` (which probably\nimplement equality for a type involving floats)."##,
4949 },
4950 LintCompletion {
4951 label: "clippy::float_cmp_const",
4952 description: r##"Checks for (in-)equality comparisons on floating-point\nvalue and constant, except in functions called `*eq*` (which probably\nimplement equality for a type involving floats)."##,
4953 },
4954 LintCompletion {
4955 label: "clippy::float_equality_without_abs",
4956 description: r##"Checks for statements of the form `(a - b) < f32::EPSILON` or\n`(a - b) < f64::EPSILON`. Notes the missing `.abs()`."##,
4957 },
4958 LintCompletion {
4959 label: "clippy::fn_address_comparisons",
4960 description: r##"Checks for comparisons with an address of a function item."##,
4961 },
4962 LintCompletion {
4963 label: "clippy::fn_params_excessive_bools",
4964 description: r##"Checks for excessive use of\nbools in function definitions."##,
4965 },
4966 LintCompletion {
4967 label: "clippy::fn_to_numeric_cast",
4968 description: r##"Checks for casts of function pointers to something other than usize"##,
4969 },
4970 LintCompletion {
4971 label: "clippy::fn_to_numeric_cast_with_truncation",
4972 description: r##"Checks for casts of a function pointer to a numeric type not wide enough to\nstore address."##,
4973 },
4974 LintCompletion {
4975 label: "clippy::for_kv_map",
4976 description: r##"Checks for iterating a map (`HashMap` or `BTreeMap`) and\nignoring either the keys or values."##,
4977 },
4978 LintCompletion {
4979 label: "clippy::for_loops_over_fallibles",
4980 description: r##"Checks for `for` loops over `Option` or `Result` values."##,
4981 },
4982 LintCompletion {
4983 label: "clippy::forget_copy",
4984 description: r##"Checks for calls to `std::mem::forget` with a value that\nderives the Copy trait"##,
4985 },
4986 LintCompletion {
4987 label: "clippy::forget_ref",
4988 description: r##"Checks for calls to `std::mem::forget` with a reference\ninstead of an owned value."##,
4989 },
4990 LintCompletion {
4991 label: "clippy::from_iter_instead_of_collect",
4992 description: r##"Checks for `from_iter()` function calls on types that implement the `FromIterator`\ntrait."##,
4993 },
4994 LintCompletion {
4995 label: "clippy::from_over_into",
4996 description: r##"Searches for implementations of the `Into<..>` trait and suggests to implement `From<..>` instead."##,
4997 },
4998 LintCompletion {
4999 label: "clippy::from_str_radix_10",
5000 description: r##"Checks for function invocations of the form `primitive::from_str_radix(s, 10)`"##,
5001 },
5002 LintCompletion {
5003 label: "clippy::future_not_send",
5004 description: r##"This lint requires Future implementations returned from\nfunctions and methods to implement the `Send` marker trait. It is mostly\nused by library authors (public and internal) that target an audience where\nmultithreaded executors are likely to be used for running these Futures."##,
5005 },
5006 LintCompletion {
5007 label: "clippy::get_last_with_len",
5008 description: r##"Checks for using `x.get(x.len() - 1)` instead of\n`x.last()`."##,
5009 },
5010 LintCompletion {
5011 label: "clippy::get_unwrap",
5012 description: r##"Checks for use of `.get().unwrap()` (or\n`.get_mut().unwrap`) on a standard library type which implements `Index`"##,
5013 },
5014 LintCompletion {
5015 label: "clippy::identity_op",
5016 description: r##"Checks for identity operations, e.g., `x + 0`."##,
5017 },
5018 LintCompletion {
5019 label: "clippy::if_let_mutex",
5020 description: r##"Checks for `Mutex::lock` calls in `if let` expression\nwith lock calls in any of the else blocks."##,
5021 },
5022 LintCompletion {
5023 label: "clippy::if_let_redundant_pattern_matching",
5024 description: r##"Nothing. This lint has been deprecated."##,
5025 },
5026 LintCompletion {
5027 label: "clippy::if_let_some_result",
5028 description: r##"* Checks for unnecessary `ok()` in if let."##,
5029 },
5030 LintCompletion {
5031 label: "clippy::if_not_else",
5032 description: r##"Checks for usage of `!` or `!=` in an if condition with an\nelse branch."##,
5033 },
5034 LintCompletion {
5035 label: "clippy::if_same_then_else",
5036 description: r##"Checks for `if/else` with the same body as the *then* part\nand the *else* part."##,
5037 },
5038 LintCompletion {
5039 label: "clippy::ifs_same_cond",
5040 description: r##"Checks for consecutive `if`s with the same condition."##,
5041 },
5042 LintCompletion {
5043 label: "clippy::implicit_clone",
5044 description: r##"Checks for the usage of `_.to_owned()`, `vec.to_vec()`, or similar when calling `_.clone()` would be clearer."##,
5045 },
5046 LintCompletion {
5047 label: "clippy::implicit_hasher",
5048 description: r##"Checks for public `impl` or `fn` missing generalization\nover different hashers and implicitly defaulting to the default hashing\nalgorithm (`SipHash`)."##,
5049 },
5050 LintCompletion {
5051 label: "clippy::implicit_return",
5052 description: r##"Checks for missing return statements at the end of a block."##,
5053 },
5054 LintCompletion {
5055 label: "clippy::implicit_saturating_sub",
5056 description: r##"Checks for implicit saturating subtraction."##,
5057 },
5058 LintCompletion {
5059 label: "clippy::imprecise_flops",
5060 description: r##"Looks for floating-point expressions that\ncan be expressed using built-in methods to improve accuracy\nat the cost of performance."##,
5061 },
5062 LintCompletion {
5063 label: "clippy::inconsistent_digit_grouping",
5064 description: r##"Warns if an integral or floating-point constant is\ngrouped inconsistently with underscores."##,
5065 },
5066 LintCompletion {
5067 label: "clippy::inconsistent_struct_constructor",
5068 description: r##"Checks for struct constructors where the order of the field init\nshorthand in the constructor is inconsistent with the order in the struct definition."##,
5069 },
5070 LintCompletion {
5071 label: "clippy::indexing_slicing",
5072 description: r##"Checks for usage of indexing or slicing. Arrays are special cases, this lint\ndoes report on arrays if we can tell that slicing operations are in bounds and does not\nlint on constant `usize` indexing on arrays because that is handled by rustc's `const_err` lint."##,
5073 },
5074 LintCompletion {
5075 label: "clippy::ineffective_bit_mask",
5076 description: r##"Checks for bit masks in comparisons which can be removed\nwithout changing the outcome. The basic structure can be seen in the\nfollowing table:\n\n|Comparison| Bit Op |Example |equals |\n|----------|---------|-----------|-------|\n|`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|\n|`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|"##,
5077 },
5078 LintCompletion {
5079 label: "clippy::inefficient_to_string",
5080 description: r##"Checks for usage of `.to_string()` on an `&&T` where\n`T` implements `ToString` directly (like `&&str` or `&&String`)."##,
5081 },
5082 LintCompletion {
5083 label: "clippy::infallible_destructuring_match",
5084 description: r##"Checks for matches being used to destructure a single-variant enum\nor tuple struct where a `let` will suffice."##,
5085 },
5086 LintCompletion {
5087 label: "clippy::infinite_iter",
5088 description: r##"Checks for iteration that is guaranteed to be infinite."##,
5089 },
5090 LintCompletion {
5091 label: "clippy::inherent_to_string",
5092 description: r##"Checks for the definition of inherent methods with a signature of `to_string(&self) -> String`."##,
5093 },
5094 LintCompletion {
5095 label: "clippy::inherent_to_string_shadow_display",
5096 description: r##"Checks for the definition of inherent methods with a signature of `to_string(&self) -> String` and if the type implementing this method also implements the `Display` trait."##,
5097 },
5098 LintCompletion {
5099 label: "clippy::inline_always",
5100 description: r##"Checks for items annotated with `#[inline(always)]`,\nunless the annotated function is empty or simply panics."##,
5101 },
5102 LintCompletion {
5103 label: "clippy::inline_asm_x86_att_syntax",
5104 description: r##"Checks for usage of AT&T x86 assembly syntax."##,
5105 },
5106 LintCompletion {
5107 label: "clippy::inline_asm_x86_intel_syntax",
5108 description: r##"Checks for usage of Intel x86 assembly syntax."##,
5109 },
5110 LintCompletion {
5111 label: "clippy::inline_fn_without_body",
5112 description: r##"Checks for `#[inline]` on trait methods without bodies"##,
5113 },
5114 LintCompletion {
5115 label: "clippy::inspect_for_each",
5116 description: r##"Checks for usage of `inspect().for_each()`."##,
5117 },
5118 LintCompletion {
5119 label: "clippy::int_plus_one",
5120 description: r##"Checks for usage of `x >= y + 1` or `x - 1 >= y` (and `<=`) in a block"##,
5121 },
5122 LintCompletion {
5123 label: "clippy::integer_arithmetic",
5124 description: r##"Checks for integer arithmetic operations which could overflow or panic.\n\nSpecifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable\nof overflowing according to the [Rust\nReference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow),\nor which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is\nattempted."##,
5125 },
5126 LintCompletion {
5127 label: "clippy::integer_division",
5128 description: r##"Checks for division of integers"##,
5129 },
5130 LintCompletion {
5131 label: "clippy::into_iter_on_array",
5132 description: r##"Nothing. This lint has been deprecated."##,
5133 },
5134 LintCompletion {
5135 label: "clippy::into_iter_on_ref",
5136 description: r##"Checks for `into_iter` calls on references which should be replaced by `iter`\nor `iter_mut`."##,
5137 },
5138 LintCompletion {
5139 label: "clippy::invalid_atomic_ordering",
5140 description: r##"Checks for usage of invalid atomic\nordering in atomic loads/stores/exchanges/updates and\nmemory fences."##,
5141 },
5142 LintCompletion {
5143 label: "clippy::invalid_ref",
5144 description: r##"Nothing. This lint has been deprecated."##,
5145 },
5146 LintCompletion {
5147 label: "clippy::invalid_regex",
5148 description: r##"Checks [regex](https://crates.io/crates/regex) creation\n(with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct\nregex syntax."##,
5149 },
5150 LintCompletion {
5151 label: "clippy::invalid_upcast_comparisons",
5152 description: r##"Checks for comparisons where the relation is always either\ntrue or false, but where one side has been upcast so that the comparison is\nnecessary. Only integer types are checked."##,
5153 },
5154 LintCompletion {
5155 label: "clippy::invisible_characters",
5156 description: r##"Checks for invisible Unicode characters in the code."##,
5157 },
5158 LintCompletion {
5159 label: "clippy::items_after_statements",
5160 description: r##"Checks for items declared after some statement in a block."##,
5161 },
5162 LintCompletion {
5163 label: "clippy::iter_cloned_collect",
5164 description: r##"Checks for the use of `.cloned().collect()` on slice to\ncreate a `Vec`."##,
5165 },
5166 LintCompletion {
5167 label: "clippy::iter_next_loop",
5168 description: r##"Checks for loops on `x.next()`."##,
5169 },
5170 LintCompletion {
5171 label: "clippy::iter_next_slice",
5172 description: r##"Checks for usage of `iter().next()` on a Slice or an Array"##,
5173 },
5174 LintCompletion {
5175 label: "clippy::iter_nth",
5176 description: r##"Checks for use of `.iter().nth()` (and the related\n`.iter_mut().nth()`) on standard library types with O(1) element access."##,
5177 },
5178 LintCompletion {
5179 label: "clippy::iter_nth_zero",
5180 description: r##"Checks for the use of `iter.nth(0)`."##,
5181 },
5182 LintCompletion {
5183 label: "clippy::iter_skip_next",
5184 description: r##"Checks for use of `.skip(x).next()` on iterators."##,
5185 },
5186 LintCompletion {
5187 label: "clippy::iterator_step_by_zero",
5188 description: r##"Checks for calling `.step_by(0)` on iterators which panics."##,
5189 },
5190 LintCompletion {
5191 label: "clippy::just_underscores_and_digits",
5192 description: r##"Checks if you have variables whose name consists of just\nunderscores and digits."##,
5193 },
5194 LintCompletion {
5195 label: "clippy::large_const_arrays",
5196 description: r##"Checks for large `const` arrays that should\nbe defined as `static` instead."##,
5197 },
5198 LintCompletion {
5199 label: "clippy::large_digit_groups",
5200 description: r##"Warns if the digits of an integral or floating-point\nconstant are grouped into groups that\nare too large."##,
5201 },
5202 LintCompletion {
5203 label: "clippy::large_enum_variant",
5204 description: r##"Checks for large size differences between variants on\n`enum`s."##,
5205 },
5206 LintCompletion {
5207 label: "clippy::large_stack_arrays",
5208 description: r##"Checks for local arrays that may be too large."##,
5209 },
5210 LintCompletion {
5211 label: "clippy::large_types_passed_by_value",
5212 description: r##"Checks for functions taking arguments by value, where\nthe argument type is `Copy` and large enough to be worth considering\npassing by reference. Does not trigger if the function is being exported,\nbecause that might induce API breakage, if the parameter is declared as mutable,\nor if the argument is a `self`."##,
5213 },
5214 LintCompletion {
5215 label: "clippy::len_without_is_empty",
5216 description: r##"Checks for items that implement `.len()` but not\n`.is_empty()`."##,
5217 },
5218 LintCompletion {
5219 label: "clippy::len_zero",
5220 description: r##"Checks for getting the length of something via `.len()`\njust to compare to zero, and suggests using `.is_empty()` where applicable."##,
5221 },
5222 LintCompletion {
5223 label: "clippy::let_and_return",
5224 description: r##"Checks for `let`-bindings, which are subsequently\nreturned."##,
5225 },
5226 LintCompletion {
5227 label: "clippy::let_underscore_drop",
5228 description: r##"Checks for `let _ = <expr>`\nwhere expr has a type that implements `Drop`"##,
5229 },
5230 LintCompletion {
5231 label: "clippy::let_underscore_lock",
5232 description: r##"Checks for `let _ = sync_lock`"##,
5233 },
5234 LintCompletion {
5235 label: "clippy::let_underscore_must_use",
5236 description: r##"Checks for `let _ = <expr>`\nwhere expr is #[must_use]"##,
5237 },
5238 LintCompletion {
5239 label: "clippy::let_unit_value",
5240 description: r##"Checks for binding a unit value."##,
5241 },
5242 LintCompletion {
5243 label: "clippy::linkedlist",
5244 description: r##"Checks for usage of any `LinkedList`, suggesting to use a\n`Vec` or a `VecDeque` (formerly called `RingBuf`)."##,
5245 },
5246 LintCompletion {
5247 label: "clippy::logic_bug",
5248 description: r##"Checks for boolean expressions that contain terminals that\ncan be eliminated."##,
5249 },
5250 LintCompletion {
5251 label: "clippy::lossy_float_literal",
5252 description: r##"Checks for whole number float literals that\ncannot be represented as the underlying type without loss."##,
5253 },
5254 LintCompletion {
5255 label: "clippy::macro_use_imports",
5256 description: r##"Checks for `#[macro_use] use...`."##,
5257 },
5258 LintCompletion {
5259 label: "clippy::main_recursion",
5260 description: r##"Checks for recursion using the entrypoint."##,
5261 },
5262 LintCompletion {
5263 label: "clippy::manual_async_fn",
5264 description: r##"It checks for manual implementations of `async` functions."##,
5265 },
5266 LintCompletion {
5267 label: "clippy::manual_filter_map",
5268 description: r##"Checks for usage of `_.filter(_).map(_)` that can be written more simply\nas `filter_map(_)`."##,
5269 },
5270 LintCompletion {
5271 label: "clippy::manual_find_map",
5272 description: r##"Checks for usage of `_.find(_).map(_)` that can be written more simply\nas `find_map(_)`."##,
5273 },
5274 LintCompletion {
5275 label: "clippy::manual_flatten",
5276 description: r##"Check for unnecessary `if let` usage in a for loop\nwhere only the `Some` or `Ok` variant of the iterator element is used."##,
5277 },
5278 LintCompletion {
5279 label: "clippy::manual_map",
5280 description: r##"Checks for usages of `match` which could be implemented using `map`"##,
5281 },
5282 LintCompletion {
5283 label: "clippy::manual_memcpy",
5284 description: r##"Checks for for-loops that manually copy items between\nslices that could be optimized by having a memcpy."##,
5285 },
5286 LintCompletion {
5287 label: "clippy::manual_non_exhaustive",
5288 description: r##"Checks for manual implementations of the non-exhaustive pattern."##,
5289 },
5290 LintCompletion {
5291 label: "clippy::manual_ok_or",
5292 description: r##"Finds patterns that reimplement `Option::ok_or`."##,
5293 },
5294 LintCompletion {
5295 label: "clippy::manual_range_contains",
5296 description: r##"Checks for expressions like `x >= 3 && x < 8` that could\nbe more readably expressed as `(3..8).contains(x)`."##,
5297 },
5298 LintCompletion {
5299 label: "clippy::manual_saturating_arithmetic",
5300 description: r##"Checks for `.checked_add/sub(x).unwrap_or(MAX/MIN)`."##,
5301 },
5302 LintCompletion {
5303 label: "clippy::manual_strip",
5304 description: r##"Suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing using\nthe pattern's length."##,
5305 },
5306 LintCompletion {
5307 label: "clippy::manual_swap",
5308 description: r##"Checks for manual swapping."##,
5309 },
5310 LintCompletion {
5311 label: "clippy::manual_unwrap_or",
5312 description: r##"Finds patterns that reimplement `Option::unwrap_or` or `Result::unwrap_or`."##,
5313 },
5314 LintCompletion {
5315 label: "clippy::many_single_char_names",
5316 description: r##"Checks for too many variables whose name consists of a\nsingle character."##,
5317 },
5318 LintCompletion {
5319 label: "clippy::map_clone",
5320 description: r##"Checks for usage of `map(|x| x.clone())` or\ndereferencing closures for `Copy` types, on `Iterator` or `Option`,\nand suggests `cloned()` or `copied()` instead"##,
5321 },
5322 LintCompletion {
5323 label: "clippy::map_collect_result_unit",
5324 description: r##"Checks for usage of `_.map(_).collect::<Result<(), _>()`."##,
5325 },
5326 LintCompletion {
5327 label: "clippy::map_entry",
5328 description: r##"Checks for uses of `contains_key` + `insert` on `HashMap`\nor `BTreeMap`."##,
5329 },
5330 LintCompletion {
5331 label: "clippy::map_err_ignore",
5332 description: r##"Checks for instances of `map_err(|_| Some::Enum)`"##,
5333 },
5334 LintCompletion {
5335 label: "clippy::map_flatten",
5336 description: r##"Checks for usage of `_.map(_).flatten(_)`,"##,
5337 },
5338 LintCompletion {
5339 label: "clippy::map_identity",
5340 description: r##"Checks for instances of `map(f)` where `f` is the identity function."##,
5341 },
5342 LintCompletion {
5343 label: "clippy::map_unwrap_or",
5344 description: r##"Checks for usage of `option.map(_).unwrap_or(_)` or `option.map(_).unwrap_or_else(_)` or\n`result.map(_).unwrap_or_else(_)`."##,
5345 },
5346 LintCompletion {
5347 label: "clippy::match_as_ref",
5348 description: r##"Checks for match which is used to add a reference to an\n`Option` value."##,
5349 },
5350 LintCompletion {
5351 label: "clippy::match_bool",
5352 description: r##"Checks for matches where match expression is a `bool`. It\nsuggests to replace the expression with an `if...else` block."##,
5353 },
5354 LintCompletion {
5355 label: "clippy::match_like_matches_macro",
5356 description: r##"Checks for `match` or `if let` expressions producing a\n`bool` that could be written using `matches!`"##,
5357 },
5358 LintCompletion {
5359 label: "clippy::match_on_vec_items",
5360 description: r##"Checks for `match vec[idx]` or `match vec[n..m]`."##,
5361 },
5362 LintCompletion {
5363 label: "clippy::match_overlapping_arm",
5364 description: r##"Checks for overlapping match arms."##,
5365 },
5366 LintCompletion {
5367 label: "clippy::match_ref_pats",
5368 description: r##"Checks for matches where all arms match a reference,\nsuggesting to remove the reference and deref the matched expression\ninstead. It also checks for `if let &foo = bar` blocks."##,
5369 },
5370 LintCompletion {
5371 label: "clippy::match_same_arms",
5372 description: r##"Checks for `match` with identical arm bodies."##,
5373 },
5374 LintCompletion {
5375 label: "clippy::match_single_binding",
5376 description: r##"Checks for useless match that binds to only one value."##,
5377 },
5378 LintCompletion {
5379 label: "clippy::match_wild_err_arm",
5380 description: r##"Checks for arm which matches all errors with `Err(_)`\nand take drastic actions like `panic!`."##,
5381 },
5382 LintCompletion {
5383 label: "clippy::match_wildcard_for_single_variants",
5384 description: r##"Checks for wildcard enum matches for a single variant."##,
5385 },
5386 LintCompletion {
5387 label: "clippy::maybe_infinite_iter",
5388 description: r##"Checks for iteration that may be infinite."##,
5389 },
5390 LintCompletion {
5391 label: "clippy::mem_discriminant_non_enum",
5392 description: r##"Checks for calls of `mem::discriminant()` on a non-enum type."##,
5393 },
5394 LintCompletion {
5395 label: "clippy::mem_forget",
5396 description: r##"Checks for usage of `std::mem::forget(t)` where `t` is\n`Drop`."##,
5397 },
5398 LintCompletion {
5399 label: "clippy::mem_replace_option_with_none",
5400 description: r##"Checks for `mem::replace()` on an `Option` with\n`None`."##,
5401 },
5402 LintCompletion {
5403 label: "clippy::mem_replace_with_default",
5404 description: r##"Checks for `std::mem::replace` on a value of type\n`T` with `T::default()`."##,
5405 },
5406 LintCompletion {
5407 label: "clippy::mem_replace_with_uninit",
5408 description: r##"Checks for `mem::replace(&mut _, mem::uninitialized())`\nand `mem::replace(&mut _, mem::zeroed())`."##,
5409 },
5410 LintCompletion {
5411 label: "clippy::min_max",
5412 description: r##"Checks for expressions where `std::cmp::min` and `max` are\nused to clamp values, but switched so that the result is constant."##,
5413 },
5414 LintCompletion {
5415 label: "clippy::misaligned_transmute",
5416 description: r##"Nothing. This lint has been deprecated."##,
5417 },
5418 LintCompletion {
5419 label: "clippy::mismatched_target_os",
5420 description: r##"Checks for cfg attributes having operating systems used in target family position."##,
5421 },
5422 LintCompletion {
5423 label: "clippy::misrefactored_assign_op",
5424 description: r##"Checks for `a op= a op b` or `a op= b op a` patterns."##,
5425 },
5426 LintCompletion {
5427 label: "clippy::missing_const_for_fn",
5428 description: r##"Suggests the use of `const` in functions and methods where possible."##,
5429 },
5430 LintCompletion {
5431 label: "clippy::missing_docs_in_private_items",
5432 description: r##"Warns if there is missing doc for any documentable item\n(public or private)."##,
5433 },
5434 LintCompletion {
5435 label: "clippy::missing_errors_doc",
5436 description: r##"Checks the doc comments of publicly visible functions that\nreturn a `Result` type and warns if there is no `# Errors` section."##,
5437 },
5438 LintCompletion {
5439 label: "clippy::missing_inline_in_public_items",
5440 description: r##"it lints if an exported function, method, trait method with default impl,\nor trait method impl is not `#[inline]`."##,
5441 },
5442 LintCompletion {
5443 label: "clippy::missing_panics_doc",
5444 description: r##"Checks the doc comments of publicly visible functions that\nmay panic and warns if there is no `# Panics` section."##,
5445 },
5446 LintCompletion {
5447 label: "clippy::missing_safety_doc",
5448 description: r##"Checks for the doc comments of publicly visible\nunsafe functions and warns if there is no `# Safety` section."##,
5449 },
5450 LintCompletion {
5451 label: "clippy::mistyped_literal_suffixes",
5452 description: r##"Warns for mistyped suffix in literals"##,
5453 },
5454 LintCompletion {
5455 label: "clippy::mixed_case_hex_literals",
5456 description: r##"Warns on hexadecimal literals with mixed-case letter\ndigits."##,
5457 },
5458 LintCompletion {
5459 label: "clippy::module_inception",
5460 description: r##"Checks for modules that have the same name as their\nparent module"##,
5461 },
5462 LintCompletion {
5463 label: "clippy::module_name_repetitions",
5464 description: r##"Detects type names that are prefixed or suffixed by the\ncontaining module's name."##,
5465 },
5466 LintCompletion {
5467 label: "clippy::modulo_arithmetic",
5468 description: r##"Checks for modulo arithmetic."##,
5469 },
5470 LintCompletion {
5471 label: "clippy::modulo_one",
5472 description: r##"Checks for getting the remainder of a division by one or minus\none."##,
5473 },
5474 LintCompletion {
5475 label: "clippy::multiple_crate_versions",
5476 description: r##"Checks to see if multiple versions of a crate are being\nused."##,
5477 },
5478 LintCompletion {
5479 label: "clippy::multiple_inherent_impl",
5480 description: r##"Checks for multiple inherent implementations of a struct"##,
5481 },
5482 LintCompletion {
5483 label: "clippy::must_use_candidate",
5484 description: r##"Checks for public functions that have no\n[`#[must_use]`] attribute, but return something not already marked\nmust-use, have no mutable arg and mutate no statics.\n\n[`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"##,
5485 },
5486 LintCompletion {
5487 label: "clippy::must_use_unit",
5488 description: r##"Checks for a [`#[must_use]`] attribute on\nunit-returning functions and methods.\n\n[`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"##,
5489 },
5490 LintCompletion {
5491 label: "clippy::mut_from_ref",
5492 description: r##"This lint checks for functions that take immutable\nreferences and return mutable ones."##,
5493 },
5494 LintCompletion {
5495 label: "clippy::mut_mut",
5496 description: r##"Checks for instances of `mut mut` references."##,
5497 },
5498 LintCompletion {
5499 label: "clippy::mut_mutex_lock",
5500 description: r##"Checks for `&mut Mutex::lock` calls"##,
5501 },
5502 LintCompletion {
5503 label: "clippy::mut_range_bound",
5504 description: r##"Checks for loops which have a range bound that is a mutable variable"##,
5505 },
5506 LintCompletion {
5507 label: "clippy::mutable_key_type",
5508 description: r##"Checks for sets/maps with mutable key types."##,
5509 },
5510 LintCompletion {
5511 label: "clippy::mutex_atomic",
5512 description: r##"Checks for usages of `Mutex<X>` where an atomic will do."##,
5513 },
5514 LintCompletion {
5515 label: "clippy::mutex_integer",
5516 description: r##"Checks for usages of `Mutex<X>` where `X` is an integral\ntype."##,
5517 },
5518 LintCompletion {
5519 label: "clippy::naive_bytecount",
5520 description: r##"Checks for naive byte counts"##,
5521 },
5522 LintCompletion {
5523 label: "clippy::needless_arbitrary_self_type",
5524 description: r##"The lint checks for `self` in fn parameters that\nspecify the `Self`-type explicitly"##,
5525 },
5526 LintCompletion {
5527 label: "clippy::needless_bool",
5528 description: r##"Checks for expressions of the form `if c { true } else {\nfalse }` (or vice versa) and suggests using the condition directly."##,
5529 },
5530 LintCompletion {
5531 label: "clippy::needless_borrow",
5532 description: r##"Checks for address of operations (`&`) that are going to\nbe dereferenced immediately by the compiler."##,
5533 },
5534 LintCompletion {
5535 label: "clippy::needless_borrowed_reference",
5536 description: r##"Checks for useless borrowed references."##,
5537 },
5538 LintCompletion {
5539 label: "clippy::needless_collect",
5540 description: r##"Checks for functions collecting an iterator when collect\nis not needed."##,
5541 },
5542 LintCompletion {
5543 label: "clippy::needless_continue",
5544 description: r##"The lint checks for `if`-statements appearing in loops\nthat contain a `continue` statement in either their main blocks or their\n`else`-blocks, when omitting the `else`-block possibly with some\nrearrangement of code can make the code easier to understand."##,
5545 },
5546 LintCompletion {
5547 label: "clippy::needless_doctest_main",
5548 description: r##"Checks for `fn main() { .. }` in doctests"##,
5549 },
5550 LintCompletion {
5551 label: "clippy::needless_lifetimes",
5552 description: r##"Checks for lifetime annotations which can be removed by\nrelying on lifetime elision."##,
5553 },
5554 LintCompletion {
5555 label: "clippy::needless_pass_by_value",
5556 description: r##"Checks for functions taking arguments by value, but not\nconsuming them in its\nbody."##,
5557 },
5558 LintCompletion {
5559 label: "clippy::needless_question_mark",
5560 description: r##"Suggests alternatives for useless applications of `?` in terminating expressions"##,
5561 },
5562 LintCompletion {
5563 label: "clippy::needless_range_loop",
5564 description: r##"Checks for looping over the range of `0..len` of some\ncollection just to get the values by index."##,
5565 },
5566 LintCompletion {
5567 label: "clippy::needless_return",
5568 description: r##"Checks for return statements at the end of a block."##,
5569 },
5570 LintCompletion {
5571 label: "clippy::needless_update",
5572 description: r##"Checks for needlessly including a base struct on update\nwhen all fields are changed anyway.\n\nThis lint is not applied to structs marked with\n[non_exhaustive](https://doc.rust-lang.org/reference/attributes/type_system.html)."##,
5573 },
5574 LintCompletion {
5575 label: "clippy::neg_cmp_op_on_partial_ord",
5576 description: r##"Checks for the usage of negated comparison operators on types which only implement\n`PartialOrd` (e.g., `f64`)."##,
5577 },
5578 LintCompletion {
5579 label: "clippy::neg_multiply",
5580 description: r##"Checks for multiplication by -1 as a form of negation."##,
5581 },
5582 LintCompletion {
5583 label: "clippy::never_loop",
5584 description: r##"Checks for loops that will always `break`, `return` or\n`continue` an outer loop."##,
5585 },
5586 LintCompletion {
5587 label: "clippy::new_ret_no_self",
5588 description: r##"Checks for `new` not returning a type that contains `Self`."##,
5589 },
5590 LintCompletion {
5591 label: "clippy::new_without_default",
5592 description: r##"Checks for types with a `fn new() -> Self` method and no\nimplementation of\n[`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)."##,
5593 },
5594 LintCompletion {
5595 label: "clippy::no_effect",
5596 description: r##"Checks for statements which have no effect."##,
5597 },
5598 LintCompletion {
5599 label: "clippy::non_ascii_literal",
5600 description: r##"Checks for non-ASCII characters in string literals."##,
5601 },
5602 LintCompletion {
5603 label: "clippy::nonminimal_bool",
5604 description: r##"Checks for boolean expressions that can be written more\nconcisely."##,
5605 },
5606 LintCompletion {
5607 label: "clippy::nonsensical_open_options",
5608 description: r##"Checks for duplicate open options as well as combinations\nthat make no sense."##,
5609 },
5610 LintCompletion {
5611 label: "clippy::not_unsafe_ptr_arg_deref",
5612 description: r##"Checks for public functions that dereference raw pointer\narguments but are not marked unsafe."##,
5613 },
5614 LintCompletion {
5615 label: "clippy::ok_expect",
5616 description: r##"Checks for usage of `ok().expect(..)`."##,
5617 },
5618 LintCompletion {
5619 label: "clippy::op_ref",
5620 description: r##"Checks for arguments to `==` which have their address\ntaken to satisfy a bound\nand suggests to dereference the other argument instead"##,
5621 },
5622 LintCompletion {
5623 label: "clippy::option_as_ref_deref",
5624 description: r##"Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str)."##,
5625 },
5626 LintCompletion {
5627 label: "clippy::option_env_unwrap",
5628 description: r##"Checks for usage of `option_env!(...).unwrap()` and\nsuggests usage of the `env!` macro."##,
5629 },
5630 LintCompletion {
5631 label: "clippy::option_if_let_else",
5632 description: r##"Lints usage of `if let Some(v) = ... { y } else { x }` which is more\nidiomatically done with `Option::map_or` (if the else bit is a pure\nexpression) or `Option::map_or_else` (if the else bit is an impure\nexpression)."##,
5633 },
5634 LintCompletion {
5635 label: "clippy::option_map_or_none",
5636 description: r##"Checks for usage of `_.map_or(None, _)`."##,
5637 },
5638 LintCompletion {
5639 label: "clippy::option_map_unit_fn",
5640 description: r##"Checks for usage of `option.map(f)` where f is a function\nor closure that returns the unit type `()`."##,
5641 },
5642 LintCompletion {
5643 label: "clippy::option_option",
5644 description: r##"Checks for use of `Option<Option<_>>` in function signatures and type\ndefinitions"##,
5645 },
5646 LintCompletion {
5647 label: "clippy::or_fun_call",
5648 description: r##"Checks for calls to `.or(foo(..))`, `.unwrap_or(foo(..))`,\netc., and suggests to use `or_else`, `unwrap_or_else`, etc., or\n`unwrap_or_default` instead."##,
5649 },
5650 LintCompletion {
5651 label: "clippy::out_of_bounds_indexing",
5652 description: r##"Checks for out of bounds array indexing with a constant\nindex."##,
5653 },
5654 LintCompletion {
5655 label: "clippy::overflow_check_conditional",
5656 description: r##"Detects classic underflow/overflow checks."##,
5657 },
5658 LintCompletion { label: "clippy::panic", description: r##"Checks for usage of `panic!`."## },
5659 LintCompletion {
5660 label: "clippy::panic_in_result_fn",
5661 description: r##"Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result."##,
5662 },
5663 LintCompletion {
5664 label: "clippy::panic_params",
5665 description: r##"Nothing. This lint has been deprecated."##,
5666 },
5667 LintCompletion {
5668 label: "clippy::panicking_unwrap",
5669 description: r##"Checks for calls of `unwrap[_err]()` that will always fail."##,
5670 },
5671 LintCompletion {
5672 label: "clippy::partialeq_ne_impl",
5673 description: r##"Checks for manual re-implementations of `PartialEq::ne`."##,
5674 },
5675 LintCompletion {
5676 label: "clippy::path_buf_push_overwrite",
5677 description: r##"* Checks for [push](https://doc.rust-lang.org/std/path/struct.PathBuf.html#method.push)\ncalls on `PathBuf` that can cause overwrites."##,
5678 },
5679 LintCompletion {
5680 label: "clippy::pattern_type_mismatch",
5681 description: r##"Checks for patterns that aren't exact representations of the types\nthey are applied to.\n\nTo satisfy this lint, you will have to adjust either the expression that is matched\nagainst or the pattern itself, as well as the bindings that are introduced by the\nadjusted patterns. For matching you will have to either dereference the expression\nwith the `*` operator, or amend the patterns to explicitly match against `&<pattern>`\nor `&mut <pattern>` depending on the reference mutability. For the bindings you need\nto use the inverse. You can leave them as plain bindings if you wish for the value\nto be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct\na reference into the matched structure.\n\nIf you are looking for a way to learn about ownership semantics in more detail, it\nis recommended to look at IDE options available to you to highlight types, lifetimes\nand reference semantics in your code. The available tooling would expose these things\nin a general way even outside of the various pattern matching mechanics. Of course\nthis lint can still be used to highlight areas of interest and ensure a good understanding\nof ownership semantics."##,
5682 },
5683 LintCompletion {
5684 label: "clippy::possible_missing_comma",
5685 description: r##"Checks for possible missing comma in an array. It lints if\nan array element is a binary operator expression and it lies on two lines."##,
5686 },
5687 LintCompletion {
5688 label: "clippy::precedence",
5689 description: r##"Checks for operations where precedence may be unclear\nand suggests to add parentheses. Currently it catches the following:\n* mixed usage of arithmetic and bit shifting/combining operators without\nparentheses\n* a \"negative\" numeric literal (which is really a unary `-` followed by a\nnumeric literal)\n followed by a method call"##,
5690 },
5691 LintCompletion {
5692 label: "clippy::print_literal",
5693 description: r##"This lint warns about the use of literals as `print!`/`println!` args."##,
5694 },
5695 LintCompletion {
5696 label: "clippy::print_stderr",
5697 description: r##"Checks for printing on *stderr*. The purpose of this lint\nis to catch debugging remnants."##,
5698 },
5699 LintCompletion {
5700 label: "clippy::print_stdout",
5701 description: r##"Checks for printing on *stdout*. The purpose of this lint\nis to catch debugging remnants."##,
5702 },
5703 LintCompletion {
5704 label: "clippy::print_with_newline",
5705 description: r##"This lint warns when you use `print!()` with a format\nstring that ends in a newline."##,
5706 },
5707 LintCompletion {
5708 label: "clippy::println_empty_string",
5709 description: r##"This lint warns when you use `println!(\"\")` to\nprint a newline."##,
5710 },
5711 LintCompletion {
5712 label: "clippy::ptr_arg",
5713 description: r##"This lint checks for function arguments of type `&String`\nor `&Vec` unless the references are mutable. It will also suggest you\nreplace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`\ncalls."##,
5714 },
5715 LintCompletion {
5716 label: "clippy::ptr_as_ptr",
5717 description: r##"Checks for `as` casts between raw pointers without changing its mutability,\nnamely `*const T` to `*const U` and `*mut T` to `*mut U`."##,
5718 },
5719 LintCompletion {
5720 label: "clippy::ptr_eq",
5721 description: r##"Use `std::ptr::eq` when applicable"##,
5722 },
5723 LintCompletion {
5724 label: "clippy::ptr_offset_with_cast",
5725 description: r##"Checks for usage of the `offset` pointer method with a `usize` casted to an\n`isize`."##,
5726 },
5727 LintCompletion {
5728 label: "clippy::pub_enum_variant_names",
5729 description: r##"Detects public enumeration variants that are\nprefixed or suffixed by the same characters."##,
5730 },
5731 LintCompletion {
5732 label: "clippy::question_mark",
5733 description: r##"Checks for expressions that could be replaced by the question mark operator."##,
5734 },
5735 LintCompletion {
5736 label: "clippy::range_minus_one",
5737 description: r##"Checks for inclusive ranges where 1 is subtracted from\nthe upper bound, e.g., `x..=(y-1)`."##,
5738 },
5739 LintCompletion {
5740 label: "clippy::range_plus_one",
5741 description: r##"Checks for exclusive ranges where 1 is added to the\nupper bound, e.g., `x..(y+1)`."##,
5742 },
5743 LintCompletion {
5744 label: "clippy::range_step_by_zero",
5745 description: r##"Nothing. This lint has been deprecated."##,
5746 },
5747 LintCompletion {
5748 label: "clippy::range_zip_with_len",
5749 description: r##"Checks for zipping a collection with the range of\n`0.._.len()`."##,
5750 },
5751 LintCompletion {
5752 label: "clippy::rc_buffer",
5753 description: r##"Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`."##,
5754 },
5755 LintCompletion {
5756 label: "clippy::redundant_allocation",
5757 description: r##"Checks for use of redundant allocations anywhere in the code."##,
5758 },
5759 LintCompletion {
5760 label: "clippy::redundant_clone",
5761 description: r##"Checks for a redundant `clone()` (and its relatives) which clones an owned\nvalue that is going to be dropped without further use."##,
5762 },
5763 LintCompletion {
5764 label: "clippy::redundant_closure",
5765 description: r##"Checks for closures which just call another function where\nthe function can be called directly. `unsafe` functions or calls where types\nget adjusted are ignored."##,
5766 },
5767 LintCompletion {
5768 label: "clippy::redundant_closure_call",
5769 description: r##"Detects closures called in the same expression where they\nare defined."##,
5770 },
5771 LintCompletion {
5772 label: "clippy::redundant_closure_for_method_calls",
5773 description: r##"Checks for closures which only invoke a method on the closure\nargument and can be replaced by referencing the method directly."##,
5774 },
5775 LintCompletion {
5776 label: "clippy::redundant_else",
5777 description: r##"Checks for `else` blocks that can be removed without changing semantics."##,
5778 },
5779 LintCompletion {
5780 label: "clippy::redundant_field_names",
5781 description: r##"Checks for fields in struct literals where shorthands\ncould be used."##,
5782 },
5783 LintCompletion {
5784 label: "clippy::redundant_pattern",
5785 description: r##"Checks for patterns in the form `name @ _`."##,
5786 },
5787 LintCompletion {
5788 label: "clippy::redundant_pattern_matching",
5789 description: r##"Lint for redundant pattern matching over `Result`, `Option`,\n`std::task::Poll` or `std::net::IpAddr`"##,
5790 },
5791 LintCompletion {
5792 label: "clippy::redundant_pub_crate",
5793 description: r##"Checks for items declared `pub(crate)` that are not crate visible because they\nare inside a private module."##,
5794 },
5795 LintCompletion {
5796 label: "clippy::redundant_slicing",
5797 description: r##"Checks for redundant slicing expressions which use the full range, and\ndo not change the type."##,
5798 },
5799 LintCompletion {
5800 label: "clippy::redundant_static_lifetimes",
5801 description: r##"Checks for constants and statics with an explicit `'static` lifetime."##,
5802 },
5803 LintCompletion {
5804 label: "clippy::ref_in_deref",
5805 description: r##"Checks for references in expressions that use\nauto dereference."##,
5806 },
5807 LintCompletion {
5808 label: "clippy::ref_option_ref",
5809 description: r##"Checks for usage of `&Option<&T>`."##,
5810 },
5811 LintCompletion {
5812 label: "clippy::regex_macro",
5813 description: r##"Nothing. This lint has been deprecated."##,
5814 },
5815 LintCompletion {
5816 label: "clippy::repeat_once",
5817 description: r##"Checks for usage of `.repeat(1)` and suggest the following method for each types.\n- `.to_string()` for `str`\n- `.clone()` for `String`\n- `.to_vec()` for `slice`"##,
5818 },
5819 LintCompletion {
5820 label: "clippy::replace_consts",
5821 description: r##"Nothing. This lint has been deprecated."##,
5822 },
5823 LintCompletion {
5824 label: "clippy::rest_pat_in_fully_bound_structs",
5825 description: r##"Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched."##,
5826 },
5827 LintCompletion {
5828 label: "clippy::result_map_or_into_option",
5829 description: r##"Checks for usage of `_.map_or(None, Some)`."##,
5830 },
5831 LintCompletion {
5832 label: "clippy::result_map_unit_fn",
5833 description: r##"Checks for usage of `result.map(f)` where f is a function\nor closure that returns the unit type `()`."##,
5834 },
5835 LintCompletion {
5836 label: "clippy::result_unit_err",
5837 description: r##"Checks for public functions that return a `Result`\nwith an `Err` type of `()`. It suggests using a custom type that\nimplements [`std::error::Error`]."##,
5838 },
5839 LintCompletion {
5840 label: "clippy::reversed_empty_ranges",
5841 description: r##"Checks for range expressions `x..y` where both `x` and `y`\nare constant and `x` is greater or equal to `y`."##,
5842 },
5843 LintCompletion {
5844 label: "clippy::same_functions_in_if_condition",
5845 description: r##"Checks for consecutive `if`s with the same function call."##,
5846 },
5847 LintCompletion {
5848 label: "clippy::same_item_push",
5849 description: r##"Checks whether a for loop is being used to push a constant\nvalue into a Vec."##,
5850 },
5851 LintCompletion {
5852 label: "clippy::search_is_some",
5853 description: r##"Checks for an iterator or string search (such as `find()`,\n`position()`, or `rposition()`) followed by a call to `is_some()`."##,
5854 },
5855 LintCompletion {
5856 label: "clippy::self_assignment",
5857 description: r##"Checks for explicit self-assignments."##,
5858 },
5859 LintCompletion {
5860 label: "clippy::semicolon_if_nothing_returned",
5861 description: r##"Looks for blocks of expressions and fires if the last expression returns `()`\nbut is not followed by a semicolon."##,
5862 },
5863 LintCompletion {
5864 label: "clippy::serde_api_misuse",
5865 description: r##"Checks for mis-uses of the serde API."##,
5866 },
5867 LintCompletion {
5868 label: "clippy::shadow_reuse",
5869 description: r##"Checks for bindings that shadow other bindings already in\nscope, while reusing the original value."##,
5870 },
5871 LintCompletion {
5872 label: "clippy::shadow_same",
5873 description: r##"Checks for bindings that shadow other bindings already in\nscope, while just changing reference level or mutability."##,
5874 },
5875 LintCompletion {
5876 label: "clippy::shadow_unrelated",
5877 description: r##"Checks for bindings that shadow other bindings already in\nscope, either without a initialization or with one that does not even use\nthe original value."##,
5878 },
5879 LintCompletion {
5880 label: "clippy::short_circuit_statement",
5881 description: r##"Checks for the use of short circuit boolean conditions as\na\nstatement."##,
5882 },
5883 LintCompletion {
5884 label: "clippy::should_assert_eq",
5885 description: r##"Nothing. This lint has been deprecated."##,
5886 },
5887 LintCompletion {
5888 label: "clippy::should_implement_trait",
5889 description: r##"Checks for methods that should live in a trait\nimplementation of a `std` trait (see [llogiq's blog\npost](http://llogiq.github.io/2015/07/30/traits.html) for further\ninformation) instead of an inherent implementation."##,
5890 },
5891 LintCompletion {
5892 label: "clippy::similar_names",
5893 description: r##"Checks for names that are very similar and thus confusing."##,
5894 },
5895 LintCompletion {
5896 label: "clippy::single_char_add_str",
5897 description: r##"Warns when using `push_str`/`insert_str` with a single-character string literal\nwhere `push`/`insert` with a `char` would work fine."##,
5898 },
5899 LintCompletion {
5900 label: "clippy::single_char_pattern",
5901 description: r##"Checks for string methods that receive a single-character\n`str` as an argument, e.g., `_.split(\"x\")`."##,
5902 },
5903 LintCompletion {
5904 label: "clippy::single_component_path_imports",
5905 description: r##"Checking for imports with single component use path."##,
5906 },
5907 LintCompletion {
5908 label: "clippy::single_element_loop",
5909 description: r##"Checks whether a for loop has a single element."##,
5910 },
5911 LintCompletion {
5912 label: "clippy::single_match",
5913 description: r##"Checks for matches with a single arm where an `if let`\nwill usually suffice."##,
5914 },
5915 LintCompletion {
5916 label: "clippy::single_match_else",
5917 description: r##"Checks for matches with two arms where an `if let else` will\nusually suffice."##,
5918 },
5919 LintCompletion {
5920 label: "clippy::size_of_in_element_count",
5921 description: r##"Detects expressions where\n`size_of::<T>` or `size_of_val::<T>` is used as a\ncount of elements of type `T`"##,
5922 },
5923 LintCompletion {
5924 label: "clippy::skip_while_next",
5925 description: r##"Checks for usage of `_.skip_while(condition).next()`."##,
5926 },
5927 LintCompletion {
5928 label: "clippy::slow_vector_initialization",
5929 description: r##"Checks slow zero-filled vector initialization"##,
5930 },
5931 LintCompletion {
5932 label: "clippy::stable_sort_primitive",
5933 description: r##"When sorting primitive values (integers, bools, chars, as well\nas arrays, slices, and tuples of such items), it is better to\nuse an unstable sort than a stable sort."##,
5934 },
5935 LintCompletion {
5936 label: "clippy::str_to_string",
5937 description: r##"This lint checks for `.to_string()` method calls on values of type `&str`."##,
5938 },
5939 LintCompletion {
5940 label: "clippy::string_add",
5941 description: r##"Checks for all instances of `x + _` where `x` is of type\n`String`, but only if [`string_add_assign`](#string_add_assign) does *not*\nmatch."##,
5942 },
5943 LintCompletion {
5944 label: "clippy::string_add_assign",
5945 description: r##"Checks for string appends of the form `x = x + y` (without\n`let`!)."##,
5946 },
5947 LintCompletion {
5948 label: "clippy::string_extend_chars",
5949 description: r##"Checks for the use of `.extend(s.chars())` where s is a\n`&str` or `String`."##,
5950 },
5951 LintCompletion {
5952 label: "clippy::string_from_utf8_as_bytes",
5953 description: r##"Check if the string is transformed to byte array and casted back to string."##,
5954 },
5955 LintCompletion {
5956 label: "clippy::string_lit_as_bytes",
5957 description: r##"Checks for the `as_bytes` method called on string literals\nthat contain only ASCII characters."##,
5958 },
5959 LintCompletion {
5960 label: "clippy::string_to_string",
5961 description: r##"This lint checks for `.to_string()` method calls on values of type `String`."##,
5962 },
5963 LintCompletion {
5964 label: "clippy::struct_excessive_bools",
5965 description: r##"Checks for excessive\nuse of bools in structs."##,
5966 },
5967 LintCompletion {
5968 label: "clippy::suboptimal_flops",
5969 description: r##"Looks for floating-point expressions that\ncan be expressed using built-in methods to improve both\naccuracy and performance."##,
5970 },
5971 LintCompletion {
5972 label: "clippy::suspicious_arithmetic_impl",
5973 description: r##"Lints for suspicious operations in impls of arithmetic operators, e.g.\nsubtracting elements in an Add impl."##,
5974 },
5975 LintCompletion {
5976 label: "clippy::suspicious_assignment_formatting",
5977 description: r##"Checks for use of the non-existent `=*`, `=!` and `=-`\noperators."##,
5978 },
5979 LintCompletion {
5980 label: "clippy::suspicious_else_formatting",
5981 description: r##"Checks for formatting of `else`. It lints if the `else`\nis followed immediately by a newline or the `else` seems to be missing."##,
5982 },
5983 LintCompletion {
5984 label: "clippy::suspicious_map",
5985 description: r##"Checks for calls to `map` followed by a `count`."##,
5986 },
5987 LintCompletion {
5988 label: "clippy::suspicious_op_assign_impl",
5989 description: r##"Lints for suspicious operations in impls of OpAssign, e.g.\nsubtracting elements in an AddAssign impl."##,
5990 },
5991 LintCompletion {
5992 label: "clippy::suspicious_operation_groupings",
5993 description: r##"Checks for unlikely usages of binary operators that are almost\ncertainly typos and/or copy/paste errors, given the other usages\nof binary operators nearby."##,
5994 },
5995 LintCompletion {
5996 label: "clippy::suspicious_unary_op_formatting",
5997 description: r##"Checks the formatting of a unary operator on the right hand side\nof a binary operator. It lints if there is no space between the binary and unary operators,\nbut there is a space between the unary and its operand."##,
5998 },
5999 LintCompletion {
6000 label: "clippy::tabs_in_doc_comments",
6001 description: r##"Checks doc comments for usage of tab characters."##,
6002 },
6003 LintCompletion {
6004 label: "clippy::temporary_assignment",
6005 description: r##"Checks for construction of a structure or tuple just to\nassign a value in it."##,
6006 },
6007 LintCompletion {
6008 label: "clippy::temporary_cstring_as_ptr",
6009 description: r##"Nothing. This lint has been deprecated."##,
6010 },
6011 LintCompletion {
6012 label: "clippy::to_digit_is_some",
6013 description: r##"Checks for `.to_digit(..).is_some()` on `char`s."##,
6014 },
6015 LintCompletion {
6016 label: "clippy::to_string_in_display",
6017 description: r##"Checks for uses of `to_string()` in `Display` traits."##,
6018 },
6019 LintCompletion { label: "clippy::todo", description: r##"Checks for usage of `todo!`."## },
6020 LintCompletion {
6021 label: "clippy::too_many_arguments",
6022 description: r##"Checks for functions with too many parameters."##,
6023 },
6024 LintCompletion {
6025 label: "clippy::too_many_lines",
6026 description: r##"Checks for functions with a large amount of lines."##,
6027 },
6028 LintCompletion {
6029 label: "clippy::toplevel_ref_arg",
6030 description: r##"Checks for function arguments and let bindings denoted as\n`ref`."##,
6031 },
6032 LintCompletion {
6033 label: "clippy::trait_duplication_in_bounds",
6034 description: r##"Checks for cases where generics are being used and multiple\nsyntax specifications for trait bounds are used simultaneously."##,
6035 },
6036 LintCompletion {
6037 label: "clippy::transmute_bytes_to_str",
6038 description: r##"Checks for transmutes from a `&[u8]` to a `&str`."##,
6039 },
6040 LintCompletion {
6041 label: "clippy::transmute_float_to_int",
6042 description: r##"Checks for transmutes from a float to an integer."##,
6043 },
6044 LintCompletion {
6045 label: "clippy::transmute_int_to_bool",
6046 description: r##"Checks for transmutes from an integer to a `bool`."##,
6047 },
6048 LintCompletion {
6049 label: "clippy::transmute_int_to_char",
6050 description: r##"Checks for transmutes from an integer to a `char`."##,
6051 },
6052 LintCompletion {
6053 label: "clippy::transmute_int_to_float",
6054 description: r##"Checks for transmutes from an integer to a float."##,
6055 },
6056 LintCompletion {
6057 label: "clippy::transmute_ptr_to_ptr",
6058 description: r##"Checks for transmutes from a pointer to a pointer, or\nfrom a reference to a reference."##,
6059 },
6060 LintCompletion {
6061 label: "clippy::transmute_ptr_to_ref",
6062 description: r##"Checks for transmutes from a pointer to a reference."##,
6063 },
6064 LintCompletion {
6065 label: "clippy::transmutes_expressible_as_ptr_casts",
6066 description: r##"Checks for transmutes that could be a pointer cast."##,
6067 },
6068 LintCompletion {
6069 label: "clippy::transmuting_null",
6070 description: r##"Checks for transmute calls which would receive a null pointer."##,
6071 },
6072 LintCompletion {
6073 label: "clippy::trivial_regex",
6074 description: r##"Checks for trivial [regex](https://crates.io/crates/regex)\ncreation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`)."##,
6075 },
6076 LintCompletion {
6077 label: "clippy::trivially_copy_pass_by_ref",
6078 description: r##"Checks for functions taking arguments by reference, where\nthe argument type is `Copy` and small enough to be more efficient to always\npass by value."##,
6079 },
6080 LintCompletion {
6081 label: "clippy::try_err",
6082 description: r##"Checks for usages of `Err(x)?`."##,
6083 },
6084 LintCompletion {
6085 label: "clippy::type_complexity",
6086 description: r##"Checks for types used in structs, parameters and `let`\ndeclarations above a certain complexity threshold."##,
6087 },
6088 LintCompletion {
6089 label: "clippy::type_repetition_in_bounds",
6090 description: r##"This lint warns about unnecessary type repetitions in trait bounds"##,
6091 },
6092 LintCompletion {
6093 label: "clippy::undropped_manually_drops",
6094 description: r##"Prevents the safe `std::mem::drop` function from being called on `std::mem::ManuallyDrop`."##,
6095 },
6096 LintCompletion {
6097 label: "clippy::unicode_not_nfc",
6098 description: r##"Checks for string literals that contain Unicode in a form\nthat is not equal to its\n[NFC-recomposition](http://www.unicode.org/reports/tr15/#Norm_Forms)."##,
6099 },
6100 LintCompletion {
6101 label: "clippy::unimplemented",
6102 description: r##"Checks for usage of `unimplemented!`."##,
6103 },
6104 LintCompletion {
6105 label: "clippy::uninit_assumed_init",
6106 description: r##"Checks for `MaybeUninit::uninit().assume_init()`."##,
6107 },
6108 LintCompletion {
6109 label: "clippy::unit_arg",
6110 description: r##"Checks for passing a unit value as an argument to a function without using a\nunit literal (`()`)."##,
6111 },
6112 LintCompletion {
6113 label: "clippy::unit_cmp",
6114 description: r##"Checks for comparisons to unit. This includes all binary\ncomparisons (like `==` and `<`) and asserts."##,
6115 },
6116 LintCompletion {
6117 label: "clippy::unit_return_expecting_ord",
6118 description: r##"Checks for functions that expect closures of type\nFn(...) -> Ord where the implemented closure returns the unit type.\nThe lint also suggests to remove the semi-colon at the end of the statement if present."##,
6119 },
6120 LintCompletion {
6121 label: "clippy::unknown_clippy_lints",
6122 description: r##"Nothing. This lint has been deprecated."##,
6123 },
6124 LintCompletion {
6125 label: "clippy::unnecessary_cast",
6126 description: r##"Checks for casts to the same type, casts of int literals to integer types\nand casts of float literals to float types."##,
6127 },
6128 LintCompletion {
6129 label: "clippy::unnecessary_filter_map",
6130 description: r##"Checks for `filter_map` calls which could be replaced by `filter` or `map`.\nMore specifically it checks if the closure provided is only performing one of the\nfilter or map operations and suggests the appropriate option."##,
6131 },
6132 LintCompletion {
6133 label: "clippy::unnecessary_fold",
6134 description: r##"Checks for using `fold` when a more succinct alternative exists.\nSpecifically, this checks for `fold`s which could be replaced by `any`, `all`,\n`sum` or `product`."##,
6135 },
6136 LintCompletion {
6137 label: "clippy::unnecessary_lazy_evaluations",
6138 description: r##"As the counterpart to `or_fun_call`, this lint looks for unnecessary\nlazily evaluated closures on `Option` and `Result`.\n\nThis lint suggests changing the following functions, when eager evaluation results in\nsimpler code:\n - `unwrap_or_else` to `unwrap_or`\n - `and_then` to `and`\n - `or_else` to `or`\n - `get_or_insert_with` to `get_or_insert`\n - `ok_or_else` to `ok_or`"##,
6139 },
6140 LintCompletion {
6141 label: "clippy::unnecessary_mut_passed",
6142 description: r##"Detects passing a mutable reference to a function that only\nrequires an immutable reference."##,
6143 },
6144 LintCompletion {
6145 label: "clippy::unnecessary_operation",
6146 description: r##"Checks for expression statements that can be reduced to a\nsub-expression."##,
6147 },
6148 LintCompletion {
6149 label: "clippy::unnecessary_sort_by",
6150 description: r##"Detects uses of `Vec::sort_by` passing in a closure\nwhich compares the two arguments, either directly or indirectly."##,
6151 },
6152 LintCompletion {
6153 label: "clippy::unnecessary_unwrap",
6154 description: r##"Checks for calls of `unwrap[_err]()` that cannot fail."##,
6155 },
6156 LintCompletion {
6157 label: "clippy::unnecessary_wraps",
6158 description: r##"Checks for private functions that only return `Ok` or `Some`."##,
6159 },
6160 LintCompletion {
6161 label: "clippy::unneeded_field_pattern",
6162 description: r##"Checks for structure field patterns bound to wildcards."##,
6163 },
6164 LintCompletion {
6165 label: "clippy::unneeded_wildcard_pattern",
6166 description: r##"Checks for tuple patterns with a wildcard\npattern (`_`) is next to a rest pattern (`..`).\n\n_NOTE_: While `_, ..` means there is at least one element left, `..`\nmeans there are 0 or more elements left. This can make a difference\nwhen refactoring, but shouldn't result in errors in the refactored code,\nsince the wildcard pattern isn't used anyway."##,
6167 },
6168 LintCompletion {
6169 label: "clippy::unnested_or_patterns",
6170 description: r##"Checks for unnested or-patterns, e.g., `Some(0) | Some(2)` and\nsuggests replacing the pattern with a nested one, `Some(0 | 2)`.\n\nAnother way to think of this is that it rewrites patterns in\n*disjunctive normal form (DNF)* into *conjunctive normal form (CNF)*."##,
6171 },
6172 LintCompletion {
6173 label: "clippy::unreachable",
6174 description: r##"Checks for usage of `unreachable!`."##,
6175 },
6176 LintCompletion {
6177 label: "clippy::unreadable_literal",
6178 description: r##"Warns if a long integral or floating-point constant does\nnot contain underscores."##,
6179 },
6180 LintCompletion {
6181 label: "clippy::unsafe_derive_deserialize",
6182 description: r##"Checks for deriving `serde::Deserialize` on a type that\nhas methods using `unsafe`."##,
6183 },
6184 LintCompletion {
6185 label: "clippy::unsafe_removed_from_name",
6186 description: r##"Checks for imports that remove \"unsafe\" from an item's\nname."##,
6187 },
6188 LintCompletion {
6189 label: "clippy::unsafe_vector_initialization",
6190 description: r##"Nothing. This lint has been deprecated."##,
6191 },
6192 LintCompletion {
6193 label: "clippy::unseparated_literal_suffix",
6194 description: r##"Warns if literal suffixes are not separated by an\nunderscore."##,
6195 },
6196 LintCompletion {
6197 label: "clippy::unsound_collection_transmute",
6198 description: r##"Checks for transmutes between collections whose\ntypes have different ABI, size or alignment."##,
6199 },
6200 LintCompletion {
6201 label: "clippy::unstable_as_mut_slice",
6202 description: r##"Nothing. This lint has been deprecated."##,
6203 },
6204 LintCompletion {
6205 label: "clippy::unstable_as_slice",
6206 description: r##"Nothing. This lint has been deprecated."##,
6207 },
6208 LintCompletion {
6209 label: "clippy::unused_collect",
6210 description: r##"Nothing. This lint has been deprecated."##,
6211 },
6212 LintCompletion {
6213 label: "clippy::unused_io_amount",
6214 description: r##"Checks for unused written/read amount."##,
6215 },
6216 LintCompletion {
6217 label: "clippy::unused_label",
6218 description: r##"Nothing. This lint has been deprecated."##,
6219 },
6220 LintCompletion {
6221 label: "clippy::unused_self",
6222 description: r##"Checks methods that contain a `self` argument but don't use it"##,
6223 },
6224 LintCompletion {
6225 label: "clippy::unused_unit",
6226 description: r##"Checks for unit (`()`) expressions that can be removed."##,
6227 },
6228 LintCompletion {
6229 label: "clippy::unusual_byte_groupings",
6230 description: r##"Warns if hexadecimal or binary literals are not grouped\nby nibble or byte."##,
6231 },
6232 LintCompletion {
6233 label: "clippy::unwrap_in_result",
6234 description: r##"Checks for functions of type Result that contain `expect()` or `unwrap()`"##,
6235 },
6236 LintCompletion {
6237 label: "clippy::unwrap_used",
6238 description: r##"Checks for `.unwrap()` calls on `Option`s and on `Result`s."##,
6239 },
6240 LintCompletion {
6241 label: "clippy::upper_case_acronyms",
6242 description: r##"Checks for fully capitalized names and optionally names containing a capitalized acronym."##,
6243 },
6244 LintCompletion {
6245 label: "clippy::use_debug",
6246 description: r##"Checks for use of `Debug` formatting. The purpose of this\nlint is to catch debugging remnants."##,
6247 },
6248 LintCompletion {
6249 label: "clippy::use_self",
6250 description: r##"Checks for unnecessary repetition of structure name when a\nreplacement with `Self` is applicable."##,
6251 },
6252 LintCompletion {
6253 label: "clippy::used_underscore_binding",
6254 description: r##"Checks for the use of bindings with a single leading\nunderscore."##,
6255 },
6256 LintCompletion {
6257 label: "clippy::useless_asref",
6258 description: r##"Checks for usage of `.as_ref()` or `.as_mut()` where the\ntypes before and after the call are the same."##,
6259 },
6260 LintCompletion {
6261 label: "clippy::useless_attribute",
6262 description: r##"Checks for `extern crate` and `use` items annotated with\nlint attributes.\n\nThis lint permits `#[allow(unused_imports)]`, `#[allow(deprecated)]`,\n`#[allow(unreachable_pub)]`, `#[allow(clippy::wildcard_imports)]` and\n`#[allow(clippy::enum_glob_use)]` on `use` items and `#[allow(unused_imports)]` on\n`extern crate` items with a `#[macro_use]` attribute."##,
6263 },
6264 LintCompletion {
6265 label: "clippy::useless_conversion",
6266 description: r##"Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls\nwhich uselessly convert to the same type."##,
6267 },
6268 LintCompletion {
6269 label: "clippy::useless_format",
6270 description: r##"Checks for the use of `format!(\"string literal with no\nargument\")` and `format!(\"{}\", foo)` where `foo` is a string."##,
6271 },
6272 LintCompletion {
6273 label: "clippy::useless_let_if_seq",
6274 description: r##"Checks for variable declarations immediately followed by a\nconditional affectation."##,
6275 },
6276 LintCompletion {
6277 label: "clippy::useless_transmute",
6278 description: r##"Checks for transmutes to the original type of the object\nand transmutes that could be a cast."##,
6279 },
6280 LintCompletion {
6281 label: "clippy::useless_vec",
6282 description: r##"Checks for usage of `&vec![..]` when using `&[..]` would\nbe possible."##,
6283 },
6284 LintCompletion {
6285 label: "clippy::vec_box",
6286 description: r##"Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code.\nCheck the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information."##,
6287 },
6288 LintCompletion {
6289 label: "clippy::vec_init_then_push",
6290 description: r##"Checks for calls to `push` immediately after creating a new `Vec`."##,
6291 },
6292 LintCompletion {
6293 label: "clippy::vec_resize_to_zero",
6294 description: r##"Finds occurrences of `Vec::resize(0, an_int)`"##,
6295 },
6296 LintCompletion {
6297 label: "clippy::verbose_bit_mask",
6298 description: r##"Checks for bit masks that can be replaced by a call\nto `trailing_zeros`"##,
6299 },
6300 LintCompletion {
6301 label: "clippy::verbose_file_reads",
6302 description: r##"Checks for use of File::read_to_end and File::read_to_string."##,
6303 },
6304 LintCompletion {
6305 label: "clippy::vtable_address_comparisons",
6306 description: r##"Checks for comparisons with an address of a trait vtable."##,
6307 },
6308 LintCompletion {
6309 label: "clippy::while_immutable_condition",
6310 description: r##"Checks whether variables used within while loop condition\ncan be (and are) mutated in the body."##,
6311 },
6312 LintCompletion {
6313 label: "clippy::while_let_loop",
6314 description: r##"Detects `loop + match` combinations that are easier\nwritten as a `while let` loop."##,
6315 },
6316 LintCompletion {
6317 label: "clippy::while_let_on_iterator",
6318 description: r##"Checks for `while let` expressions on iterators."##,
6319 },
6320 LintCompletion {
6321 label: "clippy::wildcard_dependencies",
6322 description: r##"Checks for wildcard dependencies in the `Cargo.toml`."##,
6323 },
6324 LintCompletion {
6325 label: "clippy::wildcard_enum_match_arm",
6326 description: r##"Checks for wildcard enum matches using `_`."##,
6327 },
6328 LintCompletion {
6329 label: "clippy::wildcard_imports",
6330 description: r##"Checks for wildcard imports `use _::*`."##,
6331 },
6332 LintCompletion {
6333 label: "clippy::wildcard_in_or_patterns",
6334 description: r##"Checks for wildcard pattern used with others patterns in same match arm."##,
6335 },
6336 LintCompletion {
6337 label: "clippy::write_literal",
6338 description: r##"This lint warns about the use of literals as `write!`/`writeln!` args."##,
6339 },
6340 LintCompletion {
6341 label: "clippy::write_with_newline",
6342 description: r##"This lint warns when you use `write!()` with a format\nstring that\nends in a newline."##,
6343 },
6344 LintCompletion {
6345 label: "clippy::writeln_empty_string",
6346 description: r##"This lint warns when you use `writeln!(buf, \"\")` to\nprint a newline."##,
6347 },
6348 LintCompletion {
6349 label: "clippy::wrong_pub_self_convention",
6350 description: r##"This is the same as\n[`wrong_self_convention`](#wrong_self_convention), but for public items."##,
6351 },
6352 LintCompletion {
6353 label: "clippy::wrong_self_convention",
6354 description: r##"Checks for methods with certain name prefixes and which\ndoesn't match how self is taken. The actual rules are:\n\n|Prefix |`self` taken |\n|-------|----------------------|\n|`as_` |`&self` or `&mut self`|\n|`from_`| none |\n|`into_`|`self` |\n|`is_` |`&self` or none |\n|`to_` |`&self` |"##,
6355 },
6356 LintCompletion {
6357 label: "clippy::wrong_transmute",
6358 description: r##"Checks for transmutes that can't ever be correct on any\narchitecture."##,
6359 },
6360 LintCompletion {
6361 label: "clippy::zero_divided_by_zero",
6362 description: r##"Checks for `0.0 / 0.0`."##,
6363 },
6364 LintCompletion {
6365 label: "clippy::zero_prefixed_literal",
6366 description: r##"Warns if an integral constant literal starts with `0`."##,
6367 },
6368 LintCompletion {
6369 label: "clippy::zero_ptr",
6370 description: r##"Catch casts from `0` to some pointer type"##,
6371 },
6372 LintCompletion {
6373 label: "clippy::zero_sized_map_values",
6374 description: r##"Checks for maps with zero-sized value types anywhere in the code."##,
6375 },
6376 LintCompletion {
6377 label: "clippy::zst_offset",
6378 description: r##"Checks for `offset(_)`, `wrapping_`{`add`, `sub`}, etc. on raw pointers to\nzero-sized types"##,
6379 },
6380];
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 1152a9850..18983aa01 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -4,7 +4,6 @@ mod config;
4mod item; 4mod item;
5mod context; 5mod context;
6mod patterns; 6mod patterns;
7mod generated_lint_completions;
8#[cfg(test)] 7#[cfg(test)]
9mod test_utils; 8mod test_utils;
10mod render; 9mod render;
@@ -159,7 +158,6 @@ pub fn completions(
159 completions::record::complete_record(&mut acc, &ctx); 158 completions::record::complete_record(&mut acc, &ctx);
160 completions::pattern::complete_pattern(&mut acc, &ctx); 159 completions::pattern::complete_pattern(&mut acc, &ctx);
161 completions::postfix::complete_postfix(&mut acc, &ctx); 160 completions::postfix::complete_postfix(&mut acc, &ctx);
162 completions::macro_in_item_position::complete_macro_in_item_position(&mut acc, &ctx);
163 completions::trait_impl::complete_trait_impl(&mut acc, &ctx); 161 completions::trait_impl::complete_trait_impl(&mut acc, &ctx);
164 completions::mod_::complete_mod(&mut acc, &ctx); 162 completions::mod_::complete_mod(&mut acc, &ctx);
165 completions::flyimport::import_on_the_fly(&mut acc, &ctx); 163 completions::flyimport::import_on_the_fly(&mut acc, &ctx);
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index 080898aef..72e67e3c4 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -4,7 +4,7 @@ use hir::Semantics;
4use ide_db::RootDatabase; 4use ide_db::RootDatabase;
5use syntax::{ 5use syntax::{
6 algo::non_trivia_sibling, 6 algo::non_trivia_sibling,
7 ast::{self, LoopBodyOwner}, 7 ast::{self, ArgListOwner, LoopBodyOwner},
8 match_ast, AstNode, Direction, SyntaxElement, 8 match_ast, AstNode, Direction, SyntaxElement,
9 SyntaxKind::*, 9 SyntaxKind::*,
10 SyntaxNode, SyntaxToken, TextRange, TextSize, T, 10 SyntaxNode, SyntaxToken, TextRange, TextSize, T,
@@ -39,6 +39,7 @@ pub(crate) enum ImmediateLocation {
39 // Original file ast node 39 // Original file ast node
40 MethodCall { 40 MethodCall {
41 receiver: Option<ast::Expr>, 41 receiver: Option<ast::Expr>,
42 has_parens: bool,
42 }, 43 },
43 // Original file ast node 44 // Original file ast node
44 FieldAccess { 45 FieldAccess {
@@ -46,6 +47,9 @@ pub(crate) enum ImmediateLocation {
46 receiver_is_ambiguous_float_literal: bool, 47 receiver_is_ambiguous_float_literal: bool,
47 }, 48 },
48 // Original file ast node 49 // Original file ast node
50 // Only set from a type arg
51 GenericArgList(ast::GenericArgList),
52 // Original file ast node
49 /// The record expr of the field name we are completing 53 /// The record expr of the field name we are completing
50 RecordExpr(ast::RecordExpr), 54 RecordExpr(ast::RecordExpr),
51 // Original file ast node 55 // Original file ast node
@@ -111,12 +115,12 @@ pub(crate) fn determine_location(
111) -> Option<ImmediateLocation> { 115) -> Option<ImmediateLocation> {
112 let node = match name_like { 116 let node = match name_like {
113 ast::NameLike::NameRef(name_ref) => { 117 ast::NameLike::NameRef(name_ref) => {
114 if ast::RecordExprField::for_field_name(&name_ref).is_some() { 118 if ast::RecordExprField::for_field_name(name_ref).is_some() {
115 return sema 119 return sema
116 .find_node_at_offset_with_macros(original_file, offset) 120 .find_node_at_offset_with_macros(original_file, offset)
117 .map(ImmediateLocation::RecordExpr); 121 .map(ImmediateLocation::RecordExpr);
118 } 122 }
119 if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() { 123 if ast::RecordPatField::for_field_name_ref(name_ref).is_some() {
120 return sema 124 return sema
121 .find_node_at_offset_with_macros(original_file, offset) 125 .find_node_at_offset_with_macros(original_file, offset)
122 .map(ImmediateLocation::RecordPat); 126 .map(ImmediateLocation::RecordPat);
@@ -124,7 +128,7 @@ pub(crate) fn determine_location(
124 maximize_name_ref(name_ref) 128 maximize_name_ref(name_ref)
125 } 129 }
126 ast::NameLike::Name(name) => { 130 ast::NameLike::Name(name) => {
127 if ast::RecordPatField::for_field_name(&name).is_some() { 131 if ast::RecordPatField::for_field_name(name).is_some() {
128 return sema 132 return sema
129 .find_node_at_offset_with_macros(original_file, offset) 133 .find_node_at_offset_with_macros(original_file, offset)
130 .map(ImmediateLocation::RecordPat); 134 .map(ImmediateLocation::RecordPat);
@@ -158,7 +162,6 @@ pub(crate) fn determine_location(
158 } 162 }
159 } 163 }
160 }; 164 };
161
162 let res = match_ast! { 165 let res = match_ast! {
163 match parent { 166 match parent {
164 ast::IdentPat(_it) => ImmediateLocation::IdentPat, 167 ast::IdentPat(_it) => ImmediateLocation::IdentPat,
@@ -173,6 +176,9 @@ pub(crate) fn determine_location(
173 Some(TRAIT) => ImmediateLocation::Trait, 176 Some(TRAIT) => ImmediateLocation::Trait,
174 _ => return None, 177 _ => return None,
175 }, 178 },
179 ast::GenericArgList(_it) => sema
180 .find_node_at_offset_with_macros(original_file, offset)
181 .map(ImmediateLocation::GenericArgList)?,
176 ast::Module(it) => { 182 ast::Module(it) => {
177 if it.item_list().is_none() { 183 if it.item_list().is_none() {
178 ImmediateLocation::ModDeclaration(it) 184 ImmediateLocation::ModDeclaration(it)
@@ -204,6 +210,7 @@ pub(crate) fn determine_location(
204 .receiver() 210 .receiver()
205 .map(|e| e.syntax().text_range()) 211 .map(|e| e.syntax().text_range())
206 .and_then(|r| find_node_with_range(original_file, r)), 212 .and_then(|r| find_node_with_range(original_file, r)),
213 has_parens: it.arg_list().map_or(false, |it| it.l_paren_token().is_some())
207 }, 214 },
208 _ => return None, 215 _ => return None,
209 } 216 }
@@ -252,7 +259,7 @@ fn test_inside_impl_trait_block() {
252} 259}
253 260
254pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { 261pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
255 element.into_token().and_then(|it| previous_non_trivia_token(it)) 262 element.into_token().and_then(previous_non_trivia_token)
256} 263}
257 264
258/// Check if the token previous to the previous one is `for`. 265/// Check if the token previous to the previous one is `for`.
@@ -260,8 +267,8 @@ pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> {
260pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { 267pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool {
261 element 268 element
262 .into_token() 269 .into_token()
263 .and_then(|it| previous_non_trivia_token(it)) 270 .and_then(previous_non_trivia_token)
264 .and_then(|it| previous_non_trivia_token(it)) 271 .and_then(previous_non_trivia_token)
265 .filter(|it| it.kind() == T![for]) 272 .filter(|it| it.kind() == T![for])
266 .is_some() 273 .is_some()
267} 274}
@@ -270,9 +277,8 @@ fn test_for_is_prev2() {
270 check_pattern_is_applicable(r"for i i$0", for_is_prev2); 277 check_pattern_is_applicable(r"for i i$0", for_is_prev2);
271} 278}
272 279
273pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { 280pub(crate) fn is_in_loop_body(node: &SyntaxNode) -> bool {
274 element 281 node.ancestors()
275 .ancestors()
276 .take_while(|it| it.kind() != FN && it.kind() != CLOSURE_EXPR) 282 .take_while(|it| it.kind() != FN && it.kind() != CLOSURE_EXPR)
277 .find_map(|it| { 283 .find_map(|it| {
278 let loop_body = match_ast! { 284 let loop_body = match_ast! {
@@ -283,7 +289,7 @@ pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
283 _ => None, 289 _ => None,
284 } 290 }
285 }; 291 };
286 loop_body.filter(|it| it.syntax().text_range().contains_range(element.text_range())) 292 loop_body.filter(|it| it.syntax().text_range().contains_range(node.text_range()))
287 }) 293 })
288 .is_some() 294 .is_some()
289} 295}
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index a49a60711..d8ca18c73 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -18,54 +18,56 @@ use ide_db::{
18use syntax::TextRange; 18use syntax::TextRange;
19 19
20use crate::{ 20use crate::{
21 context::{PathCompletionContext, PathKind},
21 item::{CompletionRelevanceTypeMatch, ImportEdit}, 22 item::{CompletionRelevanceTypeMatch, ImportEdit},
22 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, 23 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
23 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, 24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
24}; 25};
25 26
26pub(crate) fn render_field<'a>( 27pub(crate) fn render_field(
27 ctx: RenderContext<'a>, 28 ctx: RenderContext<'_>,
28 receiver: Option<hir::Name>, 29 receiver: Option<hir::Name>,
29 field: hir::Field, 30 field: hir::Field,
30 ty: &hir::Type, 31 ty: &hir::Type,
31) -> CompletionItem { 32) -> CompletionItem {
32 Render::new(ctx).render_field(receiver, field, ty) 33 render_field_(ctx, receiver, field, ty)
33} 34}
34 35
35pub(crate) fn render_tuple_field<'a>( 36pub(crate) fn render_tuple_field(
36 ctx: RenderContext<'a>, 37 ctx: RenderContext<'_>,
37 receiver: Option<hir::Name>, 38 receiver: Option<hir::Name>,
38 field: usize, 39 field: usize,
39 ty: &hir::Type, 40 ty: &hir::Type,
40) -> CompletionItem { 41) -> CompletionItem {
41 Render::new(ctx).render_tuple_field(receiver, field, ty) 42 render_tuple_field_(ctx, receiver, field, ty)
42} 43}
43 44
44pub(crate) fn render_resolution<'a>( 45pub(crate) fn render_resolution(
45 ctx: RenderContext<'a>, 46 ctx: RenderContext<'_>,
46 local_name: hir::Name, 47 local_name: hir::Name,
47 resolution: &hir::ScopeDef, 48 resolution: &hir::ScopeDef,
48) -> Option<CompletionItem> { 49) -> Option<CompletionItem> {
49 Render::new(ctx).render_resolution(local_name, None, resolution) 50 render_resolution_(ctx, local_name, None, resolution)
50} 51}
51 52
52pub(crate) fn render_resolution_with_import<'a>( 53pub(crate) fn render_resolution_with_import(
53 ctx: RenderContext<'a>, 54 ctx: RenderContext<'_>,
54 import_edit: ImportEdit, 55 import_edit: ImportEdit,
55) -> Option<CompletionItem> { 56) -> Option<CompletionItem> {
56 let resolution = hir::ScopeDef::from(import_edit.import.original_item); 57 let resolution = hir::ScopeDef::from(import_edit.import.original_item);
58 if ctx.completion.expects_type() && resolution.is_value_def() {
59 return None;
60 }
57 let local_name = match resolution { 61 let local_name = match resolution {
58 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), 62 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
59 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, 63 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
60 hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), 64 hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
61 _ => item_name(ctx.db(), import_edit.import.original_item)?, 65 _ => item_name(ctx.db(), import_edit.import.original_item)?,
62 }; 66 };
63 Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map( 67 render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| {
64 |mut item| { 68 item.completion_kind = CompletionKind::Magic;
65 item.completion_kind = CompletionKind::Magic; 69 item
66 item 70 })
67 },
68 )
69} 71}
70 72
71/// Interface for data and methods required for items rendering. 73/// Interface for data and methods required for items rendering.
@@ -84,7 +86,7 @@ impl<'a> RenderContext<'a> {
84 } 86 }
85 87
86 fn db(&self) -> &'a RootDatabase { 88 fn db(&self) -> &'a RootDatabase {
87 &self.completion.db 89 self.completion.db
88 } 90 }
89 91
90 fn source_range(&self) -> TextRange { 92 fn source_range(&self) -> TextRange {
@@ -109,7 +111,10 @@ impl<'a> RenderContext<'a> {
109 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), 111 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
110 }; 112 };
111 is_assoc_deprecated 113 is_assoc_deprecated
112 || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) 114 || assoc
115 .containing_trait_or_trait_impl(db)
116 .map(|trait_| self.is_deprecated(trait_))
117 .unwrap_or(false)
113 } 118 }
114 119
115 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> { 120 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
@@ -117,215 +122,191 @@ impl<'a> RenderContext<'a> {
117 } 122 }
118} 123}
119 124
120/// Generic renderer for completion items. 125fn render_field_(
121#[derive(Debug)] 126 ctx: RenderContext<'_>,
122struct Render<'a> { 127 receiver: Option<hir::Name>,
123 ctx: RenderContext<'a>, 128 field: hir::Field,
124} 129 ty: &hir::Type,
125 130) -> CompletionItem {
126impl<'a> Render<'a> { 131 let is_deprecated = ctx.is_deprecated(field);
127 fn new(ctx: RenderContext<'a>) -> Render<'a> { 132 let name = field.name(ctx.db()).to_string();
128 Render { ctx } 133 let mut item = CompletionItem::new(
134 CompletionKind::Reference,
135 ctx.source_range(),
136 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
137 );
138
139 item.set_relevance(CompletionRelevance {
140 type_match: compute_type_match(ctx.completion, ty),
141 exact_name_match: compute_exact_name_match(ctx.completion, &name),
142 ..CompletionRelevance::default()
143 });
144 item.kind(SymbolKind::Field)
145 .detail(ty.display(ctx.db()).to_string())
146 .set_documentation(field.docs(ctx.db()))
147 .set_deprecated(is_deprecated)
148 .lookup_by(name);
149
150 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
151 // FIXME
152 // For now we don't properly calculate the edits for ref match
153 // completions on struct fields, so we've disabled them. See #8058.
129 } 154 }
130 155
131 fn render_field( 156 item.build()
132 &self, 157}
133 receiver: Option<hir::Name>,
134 field: hir::Field,
135 ty: &hir::Type,
136 ) -> CompletionItem {
137 let is_deprecated = self.ctx.is_deprecated(field);
138 let name = field.name(self.ctx.db()).to_string();
139 let mut item = CompletionItem::new(
140 CompletionKind::Reference,
141 self.ctx.source_range(),
142 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
143 );
144 item.kind(SymbolKind::Field)
145 .detail(ty.display(self.ctx.db()).to_string())
146 .set_documentation(field.docs(self.ctx.db()))
147 .set_deprecated(is_deprecated);
148
149 item.set_relevance(CompletionRelevance {
150 type_match: compute_type_match(self.ctx.completion, ty),
151 exact_name_match: compute_exact_name_match(self.ctx.completion, &name),
152 ..CompletionRelevance::default()
153 });
154
155 if let Some(_ref_match) = compute_ref_match(self.ctx.completion, ty) {
156 // FIXME
157 // For now we don't properly calculate the edits for ref match
158 // completions on struct fields, so we've disabled them. See #8058.
159 }
160 158
161 item.build() 159fn render_tuple_field_(
162 } 160 ctx: RenderContext<'_>,
161 receiver: Option<hir::Name>,
162 field: usize,
163 ty: &hir::Type,
164) -> CompletionItem {
165 let mut item = CompletionItem::new(
166 CompletionKind::Reference,
167 ctx.source_range(),
168 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
169 );
163 170
164 fn render_tuple_field( 171 item.kind(SymbolKind::Field)
165 &self, 172 .detail(ty.display(ctx.db()).to_string())
166 receiver: Option<hir::Name>, 173 .lookup_by(field.to_string());
167 field: usize,
168 ty: &hir::Type,
169 ) -> CompletionItem {
170 let mut item = CompletionItem::new(
171 CompletionKind::Reference,
172 self.ctx.source_range(),
173 receiver
174 .map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
175 );
176 174
177 item.kind(SymbolKind::Field).detail(ty.display(self.ctx.db()).to_string()); 175 item.build()
176}
178 177
179 item.build() 178fn render_resolution_(
180 } 179 ctx: RenderContext<'_>,
180 local_name: hir::Name,
181 import_to_add: Option<ImportEdit>,
182 resolution: &hir::ScopeDef,
183) -> Option<CompletionItem> {
184 let _p = profile::span("render_resolution");
185 use hir::ModuleDef::*;
181 186
182 fn render_resolution( 187 let completion_kind = match resolution {
183 self, 188 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
184 local_name: hir::Name, 189 _ => CompletionKind::Reference,
185 import_to_add: Option<ImportEdit>, 190 };
186 resolution: &hir::ScopeDef,
187 ) -> Option<CompletionItem> {
188 let _p = profile::span("render_resolution");
189 use hir::ModuleDef::*;
190
191 let completion_kind = match resolution {
192 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
193 _ => CompletionKind::Reference,
194 };
195 191
196 let kind = match resolution { 192 let kind = match resolution {
197 hir::ScopeDef::ModuleDef(Function(func)) => { 193 hir::ScopeDef::ModuleDef(Function(func)) => {
198 return render_fn(self.ctx, import_to_add, Some(local_name), *func); 194 return render_fn(ctx, import_to_add, Some(local_name), *func);
199 } 195 }
200 hir::ScopeDef::ModuleDef(Variant(_)) 196 hir::ScopeDef::ModuleDef(Variant(_)) if ctx.completion.is_pat_or_const.is_some() => {
201 if self.ctx.completion.is_pat_or_const.is_some() => 197 CompletionItemKind::SymbolKind(SymbolKind::Variant)
202 { 198 }
203 CompletionItemKind::SymbolKind(SymbolKind::Variant) 199 hir::ScopeDef::ModuleDef(Variant(var)) => {
204 } 200 let item = render_variant(ctx, import_to_add, Some(local_name), *var, None);
205 hir::ScopeDef::ModuleDef(Variant(var)) => { 201 return Some(item);
206 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); 202 }
207 return Some(item); 203 hir::ScopeDef::MacroDef(mac) => {
208 } 204 let item = render_macro(ctx, import_to_add, local_name, *mac);
209 hir::ScopeDef::MacroDef(mac) => { 205 return item;
210 let item = render_macro(self.ctx, import_to_add, local_name, *mac); 206 }
211 return item;
212 }
213 207
214 hir::ScopeDef::ModuleDef(Module(..)) => { 208 hir::ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
215 CompletionItemKind::SymbolKind(SymbolKind::Module) 209 hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
216 } 210 hir::Adt::Struct(_) => SymbolKind::Struct,
217 hir::ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt { 211 hir::Adt::Union(_) => SymbolKind::Union,
218 hir::Adt::Struct(_) => SymbolKind::Struct, 212 hir::Adt::Enum(_) => SymbolKind::Enum,
219 hir::Adt::Union(_) => SymbolKind::Union, 213 }),
220 hir::Adt::Enum(_) => SymbolKind::Enum, 214 hir::ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
221 }), 215 hir::ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
222 hir::ScopeDef::ModuleDef(Const(..)) => { 216 hir::ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
223 CompletionItemKind::SymbolKind(SymbolKind::Const) 217 hir::ScopeDef::ModuleDef(TypeAlias(..)) => {
224 } 218 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
225 hir::ScopeDef::ModuleDef(Static(..)) => { 219 }
226 CompletionItemKind::SymbolKind(SymbolKind::Static) 220 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
227 } 221 hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
228 hir::ScopeDef::ModuleDef(Trait(..)) => { 222 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
229 CompletionItemKind::SymbolKind(SymbolKind::Trait) 223 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
230 } 224 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
231 hir::ScopeDef::ModuleDef(TypeAlias(..)) => { 225 }),
232 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias) 226 hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
233 } 227 hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
234 hir::ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, 228 hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => {
235 hir::ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param { 229 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
236 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam, 230 }
237 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam, 231 hir::ScopeDef::Unknown => {
238 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam, 232 let mut item = CompletionItem::new(
239 }), 233 CompletionKind::Reference,
240 hir::ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local), 234 ctx.source_range(),
241 hir::ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label), 235 local_name.to_string(),
242 hir::ScopeDef::AdtSelfType(..) | hir::ScopeDef::ImplSelfType(..) => { 236 );
243 CompletionItemKind::SymbolKind(SymbolKind::SelfParam) 237 item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
244 } 238 return Some(item.build());
245 hir::ScopeDef::Unknown => { 239 }
246 let mut item = CompletionItem::new( 240 };
247 CompletionKind::Reference,
248 self.ctx.source_range(),
249 local_name.to_string(),
250 );
251 item.kind(CompletionItemKind::UnresolvedReference).add_import(import_to_add);
252 return Some(item.build());
253 }
254 };
255 241
256 let local_name = local_name.to_string(); 242 let local_name = local_name.to_string();
257 let mut item = 243 let mut item = CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
258 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); 244 if let hir::ScopeDef::Local(local) = resolution {
259 if let hir::ScopeDef::Local(local) = resolution { 245 let ty = local.ty(ctx.db());
260 let ty = local.ty(self.ctx.db()); 246 if !ty.is_unknown() {
261 if !ty.is_unknown() { 247 item.detail(ty.display(ctx.db()).to_string());
262 item.detail(ty.display(self.ctx.db()).to_string()); 248 }
263 }
264 249
265 item.set_relevance(CompletionRelevance { 250 item.set_relevance(CompletionRelevance {
266 type_match: compute_type_match(self.ctx.completion, &ty), 251 type_match: compute_type_match(ctx.completion, &ty),
267 exact_name_match: compute_exact_name_match(self.ctx.completion, &local_name), 252 exact_name_match: compute_exact_name_match(ctx.completion, &local_name),
268 is_local: true, 253 is_local: true,
269 ..CompletionRelevance::default() 254 ..CompletionRelevance::default()
270 }); 255 });
271 256
272 if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) { 257 if let Some(ref_match) = compute_ref_match(ctx.completion, &ty) {
273 item.ref_match(ref_match); 258 item.ref_match(ref_match);
274 } 259 }
275 }; 260 };
276 261
277 // Add `<>` for generic types 262 // Add `<>` for generic types
278 if self.ctx.completion.is_path_type 263 if matches!(
279 && !self.ctx.completion.has_type_args 264 ctx.completion.path_context,
280 && self.ctx.completion.config.add_call_parenthesis 265 Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
281 { 266 ) && ctx.completion.config.add_call_parenthesis
282 if let Some(cap) = self.ctx.snippet_cap() { 267 {
283 let has_non_default_type_params = match resolution { 268 if let Some(cap) = ctx.snippet_cap() {
284 hir::ScopeDef::ModuleDef(Adt(it)) => { 269 let has_non_default_type_params = match resolution {
285 it.has_non_default_type_params(self.ctx.db()) 270 hir::ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db()),
286 } 271 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db()),
287 hir::ScopeDef::ModuleDef(TypeAlias(it)) => { 272 _ => false,
288 it.has_non_default_type_params(self.ctx.db()) 273 };
289 } 274 if has_non_default_type_params {
290 _ => false, 275 cov_mark::hit!(inserts_angle_brackets_for_generics);
291 }; 276 item.lookup_by(local_name.clone())
292 if has_non_default_type_params { 277 .label(format!("{}<…>", local_name))
293 cov_mark::hit!(inserts_angle_brackets_for_generics); 278 .insert_snippet(cap, format!("{}<$0>", local_name));
294 item.lookup_by(local_name.clone())
295 .label(format!("{}<…>", local_name))
296 .insert_snippet(cap, format!("{}<$0>", local_name));
297 }
298 } 279 }
299 } 280 }
300 item.kind(kind)
301 .add_import(import_to_add)
302 .set_documentation(self.docs(resolution))
303 .set_deprecated(self.is_deprecated(resolution));
304 Some(item.build())
305 } 281 }
282 item.kind(kind)
283 .add_import(import_to_add)
284 .set_documentation(scope_def_docs(ctx.db(), resolution))
285 .set_deprecated(scope_def_is_deprecated(&ctx, resolution));
286 Some(item.build())
287}
306 288
307 fn docs(&self, resolution: &hir::ScopeDef) -> Option<hir::Documentation> { 289fn scope_def_docs(db: &RootDatabase, resolution: &hir::ScopeDef) -> Option<hir::Documentation> {
308 use hir::ModuleDef::*; 290 use hir::ModuleDef::*;
309 match resolution { 291 match resolution {
310 hir::ScopeDef::ModuleDef(Module(it)) => it.docs(self.ctx.db()), 292 hir::ScopeDef::ModuleDef(Module(it)) => it.docs(db),
311 hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(self.ctx.db()), 293 hir::ScopeDef::ModuleDef(Adt(it)) => it.docs(db),
312 hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(self.ctx.db()), 294 hir::ScopeDef::ModuleDef(Variant(it)) => it.docs(db),
313 hir::ScopeDef::ModuleDef(Const(it)) => it.docs(self.ctx.db()), 295 hir::ScopeDef::ModuleDef(Const(it)) => it.docs(db),
314 hir::ScopeDef::ModuleDef(Static(it)) => it.docs(self.ctx.db()), 296 hir::ScopeDef::ModuleDef(Static(it)) => it.docs(db),
315 hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(self.ctx.db()), 297 hir::ScopeDef::ModuleDef(Trait(it)) => it.docs(db),
316 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(self.ctx.db()), 298 hir::ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(db),
317 _ => None, 299 _ => None,
318 }
319 } 300 }
301}
320 302
321 fn is_deprecated(&self, resolution: &hir::ScopeDef) -> bool { 303fn scope_def_is_deprecated(ctx: &RenderContext<'_>, resolution: &hir::ScopeDef) -> bool {
322 match resolution { 304 match resolution {
323 hir::ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it), 305 hir::ScopeDef::ModuleDef(it) => ctx.is_deprecated_assoc_item(*it),
324 hir::ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it), 306 hir::ScopeDef::MacroDef(it) => ctx.is_deprecated(*it),
325 hir::ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it), 307 hir::ScopeDef::GenericParam(it) => ctx.is_deprecated(*it),
326 hir::ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it), 308 hir::ScopeDef::AdtSelfType(it) => ctx.is_deprecated(*it),
327 _ => false, 309 _ => false,
328 }
329 } 310 }
330} 311}
331 312
@@ -1026,6 +1007,7 @@ fn go(world: &WorldSnapshot) { go(w$0) }
1026 1007
1027 #[test] 1008 #[test]
1028 fn too_many_arguments() { 1009 fn too_many_arguments() {
1010 cov_mark::check!(too_many_arguments);
1029 check_relevance( 1011 check_relevance(
1030 r#" 1012 r#"
1031struct Foo; 1013struct Foo;
diff --git a/crates/ide_completion/src/render/builder_ext.rs b/crates/ide_completion/src/render/builder_ext.rs
index 6d062b3b9..c54752d30 100644
--- a/crates/ide_completion/src/render/builder_ext.rs
+++ b/crates/ide_completion/src/render/builder_ext.rs
@@ -2,7 +2,7 @@
2 2
3use itertools::Itertools; 3use itertools::Itertools;
4 4
5use crate::{item::Builder, CompletionContext}; 5use crate::{context::CallKind, item::Builder, patterns::ImmediateLocation, CompletionContext};
6 6
7#[derive(Debug)] 7#[derive(Debug)]
8pub(super) enum Params { 8pub(super) enum Params {
@@ -32,10 +32,12 @@ impl Builder {
32 cov_mark::hit!(no_parens_in_use_item); 32 cov_mark::hit!(no_parens_in_use_item);
33 return false; 33 return false;
34 } 34 }
35 if ctx.is_pattern_call { 35 if matches!(ctx.path_call_kind(), Some(CallKind::Expr) | Some(CallKind::Pat))
36 return false; 36 | matches!(
37 } 37 ctx.completion_location,
38 if ctx.is_call { 38 Some(ImmediateLocation::MethodCall { has_parens: true, .. })
39 )
40 {
39 return false; 41 return false;
40 } 42 }
41 43
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 1abeed96d..1357b9f4a 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -58,29 +58,29 @@ impl<'a> FunctionRender<'a> {
58 Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method }) 58 Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method })
59 } 59 }
60 60
61 fn render(mut self, import_to_add: Option<ImportEdit>) -> CompletionItem { 61 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
62 let params = self.params(); 62 let params = self.params();
63 if let Some(receiver) = &self.receiver { 63 let call = if let Some(receiver) = &self.receiver {
64 self.name = format!("{}.{}", receiver, &self.name) 64 format!("{}.{}", receiver, &self.name)
65 } 65 } else {
66 let mut item = CompletionItem::new( 66 self.name.clone()
67 CompletionKind::Reference, 67 };
68 self.ctx.source_range(), 68 let mut item =
69 self.name.clone(), 69 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), call.clone());
70 );
71 item.kind(self.kind()) 70 item.kind(self.kind())
72 .set_documentation(self.ctx.docs(self.func)) 71 .set_documentation(self.ctx.docs(self.func))
73 .set_deprecated( 72 .set_deprecated(
74 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), 73 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
75 ) 74 )
76 .detail(self.detail()) 75 .detail(self.detail())
77 .add_call_parens(self.ctx.completion, self.name.clone(), params) 76 .add_call_parens(self.ctx.completion, call.clone(), params)
78 .add_import(import_to_add); 77 .add_import(import_to_add)
78 .lookup_by(self.name);
79 79
80 let ret_type = self.func.ret_type(self.ctx.db()); 80 let ret_type = self.func.ret_type(self.ctx.db());
81 item.set_relevance(CompletionRelevance { 81 item.set_relevance(CompletionRelevance {
82 type_match: compute_type_match(self.ctx.completion, &ret_type), 82 type_match: compute_type_match(self.ctx.completion, &ret_type),
83 exact_name_match: compute_exact_name_match(self.ctx.completion, &self.name), 83 exact_name_match: compute_exact_name_match(self.ctx.completion, &call),
84 ..CompletionRelevance::default() 84 ..CompletionRelevance::default()
85 }); 85 });
86 86
@@ -263,7 +263,7 @@ fn bar(s: &S) {
263 ); 263 );
264 264
265 check_edit( 265 check_edit(
266 "self.foo", 266 "foo",
267 r#" 267 r#"
268struct S {} 268struct S {}
269impl S { 269impl S {
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs
index 0dfba8acc..429d937c8 100644
--- a/crates/ide_completion/src/render/macro_.rs
+++ b/crates/ide_completion/src/render/macro_.rs
@@ -5,6 +5,7 @@ use ide_db::SymbolKind;
5use syntax::display::macro_label; 5use syntax::display::macro_label;
6 6
7use crate::{ 7use crate::{
8 context::CallKind,
8 item::{CompletionItem, CompletionKind, ImportEdit}, 9 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::RenderContext, 10 render::RenderContext,
10}; 11};
@@ -68,7 +69,8 @@ impl<'a> MacroRender<'a> {
68 } 69 }
69 70
70 fn needs_bang(&self) -> bool { 71 fn needs_bang(&self) -> bool {
71 self.ctx.completion.use_item_syntax.is_none() && !self.ctx.completion.is_macro_call 72 self.ctx.completion.use_item_syntax.is_none()
73 && !matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac))
72 } 74 }
73 75
74 fn label(&self) -> String { 76 fn label(&self) -> String {
diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs
index b4e80f424..3717a0409 100644
--- a/crates/ide_completion/src/render/pattern.rs
+++ b/crates/ide_completion/src/render/pattern.rs
@@ -75,10 +75,10 @@ fn render_pat(
75) -> Option<String> { 75) -> Option<String> {
76 let mut pat = match kind { 76 let mut pat = match kind {
77 StructKind::Tuple if ctx.snippet_cap().is_some() => { 77 StructKind::Tuple if ctx.snippet_cap().is_some() => {
78 render_tuple_as_pat(&fields, &name, fields_omitted) 78 render_tuple_as_pat(fields, name, fields_omitted)
79 } 79 }
80 StructKind::Record => { 80 StructKind::Record => {
81 render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted) 81 render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
82 } 82 }
83 _ => return None, 83 _ => return None,
84 }; 84 };
@@ -86,7 +86,7 @@ fn render_pat(
86 if ctx.completion.is_param { 86 if ctx.completion.is_param {
87 pat.push(':'); 87 pat.push(':');
88 pat.push(' '); 88 pat.push(' ');
89 pat.push_str(&name); 89 pat.push_str(name);
90 } 90 }
91 if ctx.snippet_cap().is_some() { 91 if ctx.snippet_cap().is_some() {
92 pat.push_str("$0"); 92 pat.push_str("$0");
diff --git a/crates/ide_completion/src/render/type_alias.rs b/crates/ide_completion/src/render/type_alias.rs
index e47b4c745..e0234171a 100644
--- a/crates/ide_completion/src/render/type_alias.rs
+++ b/crates/ide_completion/src/render/type_alias.rs
@@ -16,7 +16,14 @@ pub(crate) fn render_type_alias<'a>(
16 ctx: RenderContext<'a>, 16 ctx: RenderContext<'a>,
17 type_alias: hir::TypeAlias, 17 type_alias: hir::TypeAlias,
18) -> Option<CompletionItem> { 18) -> Option<CompletionItem> {
19 TypeAliasRender::new(ctx, type_alias)?.render() 19 TypeAliasRender::new(ctx, type_alias)?.render(false)
20}
21
22pub(crate) fn render_type_alias_with_eq<'a>(
23 ctx: RenderContext<'a>,
24 type_alias: hir::TypeAlias,
25) -> Option<CompletionItem> {
26 TypeAliasRender::new(ctx, type_alias)?.render(true)
20} 27}
21 28
22#[derive(Debug)] 29#[derive(Debug)]
@@ -32,8 +39,14 @@ impl<'a> TypeAliasRender<'a> {
32 Some(TypeAliasRender { ctx, type_alias, ast_node }) 39 Some(TypeAliasRender { ctx, type_alias, ast_node })
33 } 40 }
34 41
35 fn render(self) -> Option<CompletionItem> { 42 fn render(self, with_eq: bool) -> Option<CompletionItem> {
36 let name = self.name()?; 43 let name = self.ast_node.name().map(|name| {
44 if with_eq {
45 format!("{} = ", name.text())
46 } else {
47 name.text().to_string()
48 }
49 })?;
37 let detail = self.detail(); 50 let detail = self.detail();
38 51
39 let mut item = 52 let mut item =
@@ -49,10 +62,6 @@ impl<'a> TypeAliasRender<'a> {
49 Some(item.build()) 62 Some(item.build())
50 } 63 }
51 64
52 fn name(&self) -> Option<String> {
53 self.ast_node.name().map(|name| name.text().to_string())
54 }
55
56 fn detail(&self) -> String { 65 fn detail(&self) -> String {
57 type_label(&self.ast_node) 66 type_label(&self.ast_node)
58 } 67 }