diff options
23 files changed, 303 insertions, 264 deletions
diff --git a/Cargo.toml b/Cargo.toml index 612e6809f..218581d9d 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -2,37 +2,34 @@ | |||
2 | members = [ "crates/*", "xtask/" ] | 2 | members = [ "crates/*", "xtask/" ] |
3 | 3 | ||
4 | [profile.dev] | 4 | [profile.dev] |
5 | # disabling debug info speeds up builds a bunch, | 5 | # Disabling debug info speeds up builds a bunch, |
6 | # and we don't rely on it for debugging that much. | 6 | # and we don't rely on it for debugging that much. |
7 | debug = 0 | 7 | debug = 0 |
8 | 8 | ||
9 | [profile.dev.package] | ||
10 | # These speed up local tests. | ||
11 | rowan.opt-level = 3 | ||
12 | rustc-hash.opt-level = 3 | ||
13 | smol_str.opt-level = 3 | ||
14 | text-size.opt-level = 3 | ||
15 | # This speeds up `cargo xtask dist`. | ||
16 | miniz_oxide.opt-level = 3 | ||
17 | |||
9 | [profile.release] | 18 | [profile.release] |
10 | incremental = true | 19 | incremental = true |
11 | debug = 0 # set this to 1 or 2 to get more useful backtraces in debugger | 20 | debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger. |
12 | |||
13 | # ideally, we would use `build-override` here, but some crates are also | ||
14 | # needed at run-time and we end up compiling them twice | ||
15 | [profile.release.package.proc-macro2] | ||
16 | opt-level = 0 | ||
17 | [profile.release.package.quote] | ||
18 | opt-level = 0 | ||
19 | [profile.release.package.syn] | ||
20 | opt-level = 0 | ||
21 | [profile.release.package.serde_derive] | ||
22 | opt-level = 0 | ||
23 | [profile.release.package.chalk-derive] | ||
24 | opt-level = 0 | ||
25 | [profile.release.package.salsa-macros] | ||
26 | opt-level = 0 | ||
27 | [profile.release.package.tracing-attributes] | ||
28 | opt-level = 0 | ||
29 | [profile.release.package.xtask] | ||
30 | opt-level = 0 | ||
31 | 21 | ||
32 | # Gzipping the artifacts is up to 10 times faster with optimizations (`cargo xtask dist`). | 22 | # Ideally, we would use `build-override` here, but some crates are also |
33 | # `miniz_oxide` is the direct dependency of `flate2` which does all the heavy lifting | 23 | # needed at run-time and we end up compiling them twice. |
34 | [profile.dev.package.miniz_oxide] | 24 | [profile.release.package] |
35 | opt-level = 3 | 25 | chalk-derive.opt-level = 0 |
26 | proc-macro2.opt-level = 0 | ||
27 | quote.opt-level = 0 | ||
28 | salsa-macros.opt-level = 0 | ||
29 | serde_derive.opt-level = 0 | ||
30 | syn.opt-level = 0 | ||
31 | tracing-attributes.opt-level = 0 | ||
32 | xtask.opt-level = 0 | ||
36 | 33 | ||
37 | [patch.'crates-io'] | 34 | [patch.'crates-io'] |
38 | # rowan = { path = "../rowan" } | 35 | # rowan = { path = "../rowan" } |
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs index 79574b9ac..11c171fc2 100644 --- a/crates/assists/src/assist_context.rs +++ b/crates/assists/src/assist_context.rs | |||
@@ -6,6 +6,7 @@ use algo::find_covering_element; | |||
6 | use base_db::{FileId, FileRange}; | 6 | use base_db::{FileId, FileRange}; |
7 | use hir::Semantics; | 7 | use hir::Semantics; |
8 | use ide_db::{ | 8 | use ide_db::{ |
9 | label::Label, | ||
9 | source_change::{SourceChange, SourceFileEdit}, | 10 | source_change::{SourceChange, SourceFileEdit}, |
10 | RootDatabase, | 11 | RootDatabase, |
11 | }; | 12 | }; |
@@ -157,8 +158,9 @@ impl Assists { | |||
157 | if !self.is_allowed(&id) { | 158 | if !self.is_allowed(&id) { |
158 | return None; | 159 | return None; |
159 | } | 160 | } |
160 | let label = Assist::new(id, label.into(), None, target); | 161 | let label = Label::new(label.into()); |
161 | self.add_impl(label, f) | 162 | let assist = Assist { id, label, group: None, target }; |
163 | self.add_impl(assist, f) | ||
162 | } | 164 | } |
163 | 165 | ||
164 | pub(crate) fn add_group( | 166 | pub(crate) fn add_group( |
@@ -172,12 +174,12 @@ impl Assists { | |||
172 | if !self.is_allowed(&id) { | 174 | if !self.is_allowed(&id) { |
173 | return None; | 175 | return None; |
174 | } | 176 | } |
175 | 177 | let label = Label::new(label.into()); | |
176 | let label = Assist::new(id, label.into(), Some(group.clone()), target); | 178 | let assist = Assist { id, label, group: Some(group.clone()), target }; |
177 | self.add_impl(label, f) | 179 | self.add_impl(assist, f) |
178 | } | 180 | } |
179 | 181 | ||
180 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { | 182 | fn add_impl(&mut self, assist: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { |
181 | let source_change = if self.resolve { | 183 | let source_change = if self.resolve { |
182 | let mut builder = AssistBuilder::new(self.file); | 184 | let mut builder = AssistBuilder::new(self.file); |
183 | f(&mut builder); | 185 | f(&mut builder); |
@@ -186,7 +188,7 @@ impl Assists { | |||
186 | None | 188 | None |
187 | }; | 189 | }; |
188 | 190 | ||
189 | self.buf.push((label, source_change)); | 191 | self.buf.push((assist, source_change)); |
190 | Some(()) | 192 | Some(()) |
191 | } | 193 | } |
192 | 194 | ||
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index c589b08dc..14834480a 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -19,7 +19,7 @@ pub mod ast_transform; | |||
19 | 19 | ||
20 | use base_db::FileRange; | 20 | use base_db::FileRange; |
21 | use hir::Semantics; | 21 | use hir::Semantics; |
22 | use ide_db::{source_change::SourceChange, RootDatabase}; | 22 | use ide_db::{label::Label, source_change::SourceChange, RootDatabase}; |
23 | use syntax::TextRange; | 23 | use syntax::TextRange; |
24 | 24 | ||
25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
@@ -68,7 +68,7 @@ pub struct GroupLabel(pub String); | |||
68 | pub struct Assist { | 68 | pub struct Assist { |
69 | pub id: AssistId, | 69 | pub id: AssistId, |
70 | /// Short description of the assist, as shown in the UI. | 70 | /// Short description of the assist, as shown in the UI. |
71 | label: String, | 71 | pub label: Label, |
72 | pub group: Option<GroupLabel>, | 72 | pub group: Option<GroupLabel>, |
73 | /// Target ranges are used to sort assists: the smaller the target range, | 73 | /// Target ranges are used to sort assists: the smaller the target range, |
74 | /// the more specific assist is, and so it should be sorted first. | 74 | /// the more specific assist is, and so it should be sorted first. |
@@ -82,11 +82,6 @@ pub struct ResolvedAssist { | |||
82 | } | 82 | } |
83 | 83 | ||
84 | impl Assist { | 84 | impl Assist { |
85 | fn new(id: AssistId, label: String, group: Option<GroupLabel>, target: TextRange) -> Assist { | ||
86 | assert!(label.starts_with(char::is_uppercase)); | ||
87 | Assist { id, label, group, target } | ||
88 | } | ||
89 | |||
90 | /// Return all the assists applicable at the given position. | 85 | /// Return all the assists applicable at the given position. |
91 | /// | 86 | /// |
92 | /// Assists are returned in the "unresolved" state, that is only labels are | 87 | /// Assists are returned in the "unresolved" state, that is only labels are |
@@ -118,10 +113,6 @@ impl Assist { | |||
118 | }); | 113 | }); |
119 | acc.finish_resolved() | 114 | acc.finish_resolved() |
120 | } | 115 | } |
121 | |||
122 | pub fn label(&self) -> &str { | ||
123 | self.label.as_str() | ||
124 | } | ||
125 | } | 116 | } |
126 | 117 | ||
127 | mod handlers { | 118 | mod handlers { |
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index c7723de00..3e19d9117 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::any::Any; | 3 | use std::any::Any; |
4 | 4 | ||
5 | use hir_expand::diagnostics::Diagnostic; | 5 | use hir_expand::diagnostics::{Diagnostic, DiagnosticCode}; |
6 | use syntax::{ast, AstPtr, SyntaxNodePtr}; | 6 | use syntax::{ast, AstPtr, SyntaxNodePtr}; |
7 | 7 | ||
8 | use hir_expand::{HirFileId, InFile}; | 8 | use hir_expand::{HirFileId, InFile}; |
@@ -15,8 +15,8 @@ pub struct UnresolvedModule { | |||
15 | } | 15 | } |
16 | 16 | ||
17 | impl Diagnostic for UnresolvedModule { | 17 | impl Diagnostic for UnresolvedModule { |
18 | fn name(&self) -> &'static str { | 18 | fn code(&self) -> DiagnosticCode { |
19 | "unresolved-module" | 19 | DiagnosticCode("unresolved-module") |
20 | } | 20 | } |
21 | fn message(&self) -> String { | 21 | fn message(&self) -> String { |
22 | "unresolved module".to_string() | 22 | "unresolved module".to_string() |
diff --git a/crates/hir_expand/src/diagnostics.rs b/crates/hir_expand/src/diagnostics.rs index 6c81b2501..78ccc212c 100644 --- a/crates/hir_expand/src/diagnostics.rs +++ b/crates/hir_expand/src/diagnostics.rs | |||
@@ -20,8 +20,17 @@ use syntax::SyntaxNodePtr; | |||
20 | 20 | ||
21 | use crate::InFile; | 21 | use crate::InFile; |
22 | 22 | ||
23 | #[derive(Copy, Clone, PartialEq)] | ||
24 | pub struct DiagnosticCode(pub &'static str); | ||
25 | |||
26 | impl DiagnosticCode { | ||
27 | pub fn as_str(&self) -> &str { | ||
28 | self.0 | ||
29 | } | ||
30 | } | ||
31 | |||
23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | 32 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { |
24 | fn name(&self) -> &'static str; | 33 | fn code(&self) -> DiagnosticCode; |
25 | fn message(&self) -> String; | 34 | fn message(&self) -> String; |
26 | /// Used in highlighting and related purposes | 35 | /// Used in highlighting and related purposes |
27 | fn display_source(&self) -> InFile<SyntaxNodePtr>; | 36 | fn display_source(&self) -> InFile<SyntaxNodePtr>; |
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs index 38fa24ee0..9ba005fab 100644 --- a/crates/hir_ty/src/diagnostics.rs +++ b/crates/hir_ty/src/diagnostics.rs | |||
@@ -6,7 +6,7 @@ mod unsafe_check; | |||
6 | use std::any::Any; | 6 | use std::any::Any; |
7 | 7 | ||
8 | use hir_def::DefWithBodyId; | 8 | use hir_def::DefWithBodyId; |
9 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSink}; | 9 | use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; |
10 | use hir_expand::{name::Name, HirFileId, InFile}; | 10 | use hir_expand::{name::Name, HirFileId, InFile}; |
11 | use stdx::format_to; | 11 | use stdx::format_to; |
12 | use syntax::{ast, AstPtr, SyntaxNodePtr}; | 12 | use syntax::{ast, AstPtr, SyntaxNodePtr}; |
@@ -32,8 +32,8 @@ pub struct NoSuchField { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | impl Diagnostic for NoSuchField { | 34 | impl Diagnostic for NoSuchField { |
35 | fn name(&self) -> &'static str { | 35 | fn code(&self) -> DiagnosticCode { |
36 | "no-such-field" | 36 | DiagnosticCode("no-such-field") |
37 | } | 37 | } |
38 | 38 | ||
39 | fn message(&self) -> String { | 39 | fn message(&self) -> String { |
@@ -58,8 +58,8 @@ pub struct MissingFields { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | impl Diagnostic for MissingFields { | 60 | impl Diagnostic for MissingFields { |
61 | fn name(&self) -> &'static str { | 61 | fn code(&self) -> DiagnosticCode { |
62 | "missing-structure-fields" | 62 | DiagnosticCode("missing-structure-fields") |
63 | } | 63 | } |
64 | fn message(&self) -> String { | 64 | fn message(&self) -> String { |
65 | let mut buf = String::from("Missing structure fields:\n"); | 65 | let mut buf = String::from("Missing structure fields:\n"); |
@@ -94,8 +94,8 @@ pub struct MissingPatFields { | |||
94 | } | 94 | } |
95 | 95 | ||
96 | impl Diagnostic for MissingPatFields { | 96 | impl Diagnostic for MissingPatFields { |
97 | fn name(&self) -> &'static str { | 97 | fn code(&self) -> DiagnosticCode { |
98 | "missing-pat-fields" | 98 | DiagnosticCode("missing-pat-fields") |
99 | } | 99 | } |
100 | fn message(&self) -> String { | 100 | fn message(&self) -> String { |
101 | let mut buf = String::from("Missing structure fields:\n"); | 101 | let mut buf = String::from("Missing structure fields:\n"); |
@@ -127,8 +127,8 @@ pub struct MissingMatchArms { | |||
127 | } | 127 | } |
128 | 128 | ||
129 | impl Diagnostic for MissingMatchArms { | 129 | impl Diagnostic for MissingMatchArms { |
130 | fn name(&self) -> &'static str { | 130 | fn code(&self) -> DiagnosticCode { |
131 | "missing-match-arm" | 131 | DiagnosticCode("missing-match-arm") |
132 | } | 132 | } |
133 | fn message(&self) -> String { | 133 | fn message(&self) -> String { |
134 | String::from("Missing match arm") | 134 | String::from("Missing match arm") |
@@ -148,8 +148,8 @@ pub struct MissingOkInTailExpr { | |||
148 | } | 148 | } |
149 | 149 | ||
150 | impl Diagnostic for MissingOkInTailExpr { | 150 | impl Diagnostic for MissingOkInTailExpr { |
151 | fn name(&self) -> &'static str { | 151 | fn code(&self) -> DiagnosticCode { |
152 | "missing-ok-in-tail-expr" | 152 | DiagnosticCode("missing-ok-in-tail-expr") |
153 | } | 153 | } |
154 | fn message(&self) -> String { | 154 | fn message(&self) -> String { |
155 | "wrap return expression in Ok".to_string() | 155 | "wrap return expression in Ok".to_string() |
@@ -169,8 +169,8 @@ pub struct BreakOutsideOfLoop { | |||
169 | } | 169 | } |
170 | 170 | ||
171 | impl Diagnostic for BreakOutsideOfLoop { | 171 | impl Diagnostic for BreakOutsideOfLoop { |
172 | fn name(&self) -> &'static str { | 172 | fn code(&self) -> DiagnosticCode { |
173 | "break-outside-of-loop" | 173 | DiagnosticCode("break-outside-of-loop") |
174 | } | 174 | } |
175 | fn message(&self) -> String { | 175 | fn message(&self) -> String { |
176 | "break outside of loop".to_string() | 176 | "break outside of loop".to_string() |
@@ -190,8 +190,8 @@ pub struct MissingUnsafe { | |||
190 | } | 190 | } |
191 | 191 | ||
192 | impl Diagnostic for MissingUnsafe { | 192 | impl Diagnostic for MissingUnsafe { |
193 | fn name(&self) -> &'static str { | 193 | fn code(&self) -> DiagnosticCode { |
194 | "missing-unsafe" | 194 | DiagnosticCode("missing-unsafe") |
195 | } | 195 | } |
196 | fn message(&self) -> String { | 196 | fn message(&self) -> String { |
197 | format!("This operation is unsafe and requires an unsafe function or block") | 197 | format!("This operation is unsafe and requires an unsafe function or block") |
@@ -213,8 +213,8 @@ pub struct MismatchedArgCount { | |||
213 | } | 213 | } |
214 | 214 | ||
215 | impl Diagnostic for MismatchedArgCount { | 215 | impl Diagnostic for MismatchedArgCount { |
216 | fn name(&self) -> &'static str { | 216 | fn code(&self) -> DiagnosticCode { |
217 | "mismatched-arg-count" | 217 | DiagnosticCode("mismatched-arg-count") |
218 | } | 218 | } |
219 | fn message(&self) -> String { | 219 | fn message(&self) -> String { |
220 | let s = if self.expected == 1 { "" } else { "s" }; | 220 | let s = if self.expected == 1 { "" } else { "s" }; |
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs index c953925ec..91c9d38c5 100644 --- a/crates/hir_ty/src/tests.rs +++ b/crates/hir_ty/src/tests.rs | |||
@@ -8,7 +8,7 @@ mod method_resolution; | |||
8 | mod macros; | 8 | mod macros; |
9 | mod display_source_code; | 9 | mod display_source_code; |
10 | 10 | ||
11 | use std::sync::Arc; | 11 | use std::{env, sync::Arc}; |
12 | 12 | ||
13 | use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; | 13 | use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; |
14 | use expect::Expect; | 14 | use expect::Expect; |
@@ -22,12 +22,14 @@ use hir_def::{ | |||
22 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, | 22 | AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, |
23 | }; | 23 | }; |
24 | use hir_expand::{db::AstDatabase, InFile}; | 24 | use hir_expand::{db::AstDatabase, InFile}; |
25 | use stdx::format_to; | 25 | use stdx::{format_to, RacyFlag}; |
26 | use syntax::{ | 26 | use syntax::{ |
27 | algo, | 27 | algo, |
28 | ast::{self, AstNode}, | 28 | ast::{self, AstNode}, |
29 | SyntaxNode, | 29 | SyntaxNode, |
30 | }; | 30 | }; |
31 | use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; | ||
32 | use tracing_tree::HierarchicalLayer; | ||
31 | 33 | ||
32 | use crate::{ | 34 | use crate::{ |
33 | db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, | 35 | db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty, |
@@ -37,9 +39,12 @@ use crate::{ | |||
37 | // against snapshots of the expected results using expect. Use | 39 | // against snapshots of the expected results using expect. Use |
38 | // `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots. | 40 | // `env UPDATE_EXPECT=1 cargo test -p hir_ty` to update the snapshots. |
39 | 41 | ||
40 | fn setup_tracing() -> tracing::subscriber::DefaultGuard { | 42 | fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { |
41 | use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; | 43 | static ENABLE: RacyFlag = RacyFlag::new(); |
42 | use tracing_tree::HierarchicalLayer; | 44 | if !ENABLE.get(|| env::var("CHALK_DEBUG").is_ok()) { |
45 | return None; | ||
46 | } | ||
47 | |||
43 | let filter = EnvFilter::from_env("CHALK_DEBUG"); | 48 | let filter = EnvFilter::from_env("CHALK_DEBUG"); |
44 | let layer = HierarchicalLayer::default() | 49 | let layer = HierarchicalLayer::default() |
45 | .with_indent_lines(true) | 50 | .with_indent_lines(true) |
@@ -47,7 +52,7 @@ fn setup_tracing() -> tracing::subscriber::DefaultGuard { | |||
47 | .with_indent_amount(2) | 52 | .with_indent_amount(2) |
48 | .with_writer(std::io::stderr); | 53 | .with_writer(std::io::stderr); |
49 | let subscriber = Registry::default().with(filter).with(layer); | 54 | let subscriber = Registry::default().with(filter).with(layer); |
50 | tracing::subscriber::set_default(subscriber) | 55 | Some(tracing::subscriber::set_default(subscriber)) |
51 | } | 56 | } |
52 | 57 | ||
53 | fn check_types(ra_fixture: &str) { | 58 | fn check_types(ra_fixture: &str) { |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 606a6064b..92b5adaa2 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -4,22 +4,48 @@ | |||
4 | //! macro-expanded files, but we need to present them to the users in terms of | 4 | //! macro-expanded files, but we need to present them to the users in terms of |
5 | //! original files. So we need to map the ranges. | 5 | //! original files. So we need to map the ranges. |
6 | 6 | ||
7 | use std::{cell::RefCell, collections::HashSet}; | 7 | mod fixes; |
8 | |||
9 | use std::cell::RefCell; | ||
8 | 10 | ||
9 | use base_db::SourceDatabase; | 11 | use base_db::SourceDatabase; |
10 | use hir::{diagnostics::DiagnosticSinkBuilder, Semantics}; | 12 | use hir::{diagnostics::DiagnosticSinkBuilder, Semantics}; |
11 | use ide_db::RootDatabase; | 13 | use ide_db::RootDatabase; |
12 | use itertools::Itertools; | 14 | use itertools::Itertools; |
15 | use rustc_hash::FxHashSet; | ||
13 | use syntax::{ | 16 | use syntax::{ |
14 | ast::{self, AstNode}, | 17 | ast::{self, AstNode}, |
15 | SyntaxNode, TextRange, T, | 18 | SyntaxNode, TextRange, T, |
16 | }; | 19 | }; |
17 | use text_edit::TextEdit; | 20 | use text_edit::TextEdit; |
18 | 21 | ||
19 | use crate::{Diagnostic, FileId, Fix, SourceFileEdit}; | 22 | use crate::{FileId, Label, SourceChange, SourceFileEdit}; |
23 | |||
24 | use self::fixes::DiagnosticWithFix; | ||
25 | |||
26 | #[derive(Debug)] | ||
27 | pub struct Diagnostic { | ||
28 | // pub name: Option<String>, | ||
29 | pub message: String, | ||
30 | pub range: TextRange, | ||
31 | pub severity: Severity, | ||
32 | pub fix: Option<Fix>, | ||
33 | } | ||
20 | 34 | ||
21 | mod diagnostics_with_fix; | 35 | #[derive(Debug)] |
22 | use diagnostics_with_fix::DiagnosticWithFix; | 36 | pub struct Fix { |
37 | pub label: Label, | ||
38 | pub source_change: SourceChange, | ||
39 | /// Allows to trigger the fix only when the caret is in the range given | ||
40 | pub fix_trigger_range: TextRange, | ||
41 | } | ||
42 | |||
43 | impl Fix { | ||
44 | fn new(label: &str, source_change: SourceChange, fix_trigger_range: TextRange) -> Self { | ||
45 | let label = Label::new(label); | ||
46 | Self { label, source_change, fix_trigger_range } | ||
47 | } | ||
48 | } | ||
23 | 49 | ||
24 | #[derive(Debug, Copy, Clone)] | 50 | #[derive(Debug, Copy, Clone)] |
25 | pub enum Severity { | 51 | pub enum Severity { |
@@ -27,11 +53,16 @@ pub enum Severity { | |||
27 | WeakWarning, | 53 | WeakWarning, |
28 | } | 54 | } |
29 | 55 | ||
56 | #[derive(Default, Debug, Clone)] | ||
57 | pub struct DiagnosticsConfig { | ||
58 | pub disable_experimental: bool, | ||
59 | pub disabled: FxHashSet<String>, | ||
60 | } | ||
61 | |||
30 | pub(crate) fn diagnostics( | 62 | pub(crate) fn diagnostics( |
31 | db: &RootDatabase, | 63 | db: &RootDatabase, |
64 | config: &DiagnosticsConfig, | ||
32 | file_id: FileId, | 65 | file_id: FileId, |
33 | enable_experimental: bool, | ||
34 | disabled_diagnostics: Option<HashSet<String>>, | ||
35 | ) -> Vec<Diagnostic> { | 66 | ) -> Vec<Diagnostic> { |
36 | let _p = profile::span("diagnostics"); | 67 | let _p = profile::span("diagnostics"); |
37 | let sema = Semantics::new(db); | 68 | let sema = Semantics::new(db); |
@@ -40,7 +71,7 @@ pub(crate) fn diagnostics( | |||
40 | 71 | ||
41 | // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. | 72 | // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily. |
42 | res.extend(parse.errors().iter().take(128).map(|err| Diagnostic { | 73 | res.extend(parse.errors().iter().take(128).map(|err| Diagnostic { |
43 | name: None, | 74 | // name: None, |
44 | range: err.range(), | 75 | range: err.range(), |
45 | message: format!("Syntax Error: {}", err), | 76 | message: format!("Syntax Error: {}", err), |
46 | severity: Severity::Error, | 77 | severity: Severity::Error, |
@@ -52,7 +83,7 @@ pub(crate) fn diagnostics( | |||
52 | check_struct_shorthand_initialization(&mut res, file_id, &node); | 83 | check_struct_shorthand_initialization(&mut res, file_id, &node); |
53 | } | 84 | } |
54 | let res = RefCell::new(res); | 85 | let res = RefCell::new(res); |
55 | let mut sink_builder = DiagnosticSinkBuilder::new() | 86 | let sink_builder = DiagnosticSinkBuilder::new() |
56 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { | 87 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { |
57 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 88 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
58 | }) | 89 | }) |
@@ -66,19 +97,15 @@ pub(crate) fn diagnostics( | |||
66 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); | 97 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
67 | }) | 98 | }) |
68 | // Only collect experimental diagnostics when they're enabled. | 99 | // Only collect experimental diagnostics when they're enabled. |
69 | .filter(|diag| !diag.is_experimental() || enable_experimental); | 100 | .filter(|diag| !(diag.is_experimental() && config.disable_experimental)) |
70 | 101 | .filter(|diag| !config.disabled.contains(diag.code().as_str())); | |
71 | if let Some(disabled_diagnostics) = disabled_diagnostics { | ||
72 | // Do not collect disabled diagnostics. | ||
73 | sink_builder = sink_builder.filter(move |diag| !disabled_diagnostics.contains(diag.name())); | ||
74 | } | ||
75 | 102 | ||
76 | // Finalize the `DiagnosticSink` building process. | 103 | // Finalize the `DiagnosticSink` building process. |
77 | let mut sink = sink_builder | 104 | let mut sink = sink_builder |
78 | // Diagnostics not handled above get no fix and default treatment. | 105 | // Diagnostics not handled above get no fix and default treatment. |
79 | .build(|d| { | 106 | .build(|d| { |
80 | res.borrow_mut().push(Diagnostic { | 107 | res.borrow_mut().push(Diagnostic { |
81 | name: Some(d.name().into()), | 108 | // name: Some(d.name().into()), |
82 | message: d.message(), | 109 | message: d.message(), |
83 | range: sema.diagnostics_display_range(d).range, | 110 | range: sema.diagnostics_display_range(d).range, |
84 | severity: Severity::Error, | 111 | severity: Severity::Error, |
@@ -95,7 +122,7 @@ pub(crate) fn diagnostics( | |||
95 | 122 | ||
96 | fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { | 123 | fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { |
97 | Diagnostic { | 124 | Diagnostic { |
98 | name: Some(d.name().into()), | 125 | // name: Some(d.name().into()), |
99 | range: sema.diagnostics_display_range(d).range, | 126 | range: sema.diagnostics_display_range(d).range, |
100 | message: d.message(), | 127 | message: d.message(), |
101 | severity: Severity::Error, | 128 | severity: Severity::Error, |
@@ -122,7 +149,7 @@ fn check_unnecessary_braces_in_use_statement( | |||
122 | }); | 149 | }); |
123 | 150 | ||
124 | acc.push(Diagnostic { | 151 | acc.push(Diagnostic { |
125 | name: None, | 152 | // name: None, |
126 | range: use_range, | 153 | range: use_range, |
127 | message: "Unnecessary braces in use statement".to_string(), | 154 | message: "Unnecessary braces in use statement".to_string(), |
128 | severity: Severity::WeakWarning, | 155 | severity: Severity::WeakWarning, |
@@ -169,7 +196,7 @@ fn check_struct_shorthand_initialization( | |||
169 | 196 | ||
170 | let field_range = record_field.syntax().text_range(); | 197 | let field_range = record_field.syntax().text_range(); |
171 | acc.push(Diagnostic { | 198 | acc.push(Diagnostic { |
172 | name: None, | 199 | // name: None, |
173 | range: field_range, | 200 | range: field_range, |
174 | message: "Shorthand struct initialization".to_string(), | 201 | message: "Shorthand struct initialization".to_string(), |
175 | severity: Severity::WeakWarning, | 202 | severity: Severity::WeakWarning, |
@@ -187,12 +214,14 @@ fn check_struct_shorthand_initialization( | |||
187 | 214 | ||
188 | #[cfg(test)] | 215 | #[cfg(test)] |
189 | mod tests { | 216 | mod tests { |
190 | use std::collections::HashSet; | 217 | use expect::{expect, Expect}; |
191 | use stdx::trim_indent; | 218 | use stdx::trim_indent; |
192 | use test_utils::assert_eq_text; | 219 | use test_utils::assert_eq_text; |
193 | 220 | ||
194 | use crate::mock_analysis::{analysis_and_position, single_file, MockAnalysis}; | 221 | use crate::{ |
195 | use expect::{expect, Expect}; | 222 | mock_analysis::{analysis_and_position, single_file, MockAnalysis}, |
223 | DiagnosticsConfig, | ||
224 | }; | ||
196 | 225 | ||
197 | /// Takes a multi-file input fixture with annotated cursor positions, | 226 | /// Takes a multi-file input fixture with annotated cursor positions, |
198 | /// and checks that: | 227 | /// and checks that: |
@@ -203,8 +232,11 @@ mod tests { | |||
203 | let after = trim_indent(ra_fixture_after); | 232 | let after = trim_indent(ra_fixture_after); |
204 | 233 | ||
205 | let (analysis, file_position) = analysis_and_position(ra_fixture_before); | 234 | let (analysis, file_position) = analysis_and_position(ra_fixture_before); |
206 | let diagnostic = | 235 | let diagnostic = analysis |
207 | analysis.diagnostics(file_position.file_id, true, None).unwrap().pop().unwrap(); | 236 | .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) |
237 | .unwrap() | ||
238 | .pop() | ||
239 | .unwrap(); | ||
208 | let mut fix = diagnostic.fix.unwrap(); | 240 | let mut fix = diagnostic.fix.unwrap(); |
209 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; | 241 | let edit = fix.source_change.source_file_edits.pop().unwrap().edit; |
210 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); | 242 | let target_file_contents = analysis.file_text(file_position.file_id).unwrap(); |
@@ -230,7 +262,11 @@ mod tests { | |||
230 | let ra_fixture_after = &trim_indent(ra_fixture_after); | 262 | let ra_fixture_after = &trim_indent(ra_fixture_after); |
231 | let (analysis, file_pos) = analysis_and_position(ra_fixture_before); | 263 | let (analysis, file_pos) = analysis_and_position(ra_fixture_before); |
232 | let current_file_id = file_pos.file_id; | 264 | let current_file_id = file_pos.file_id; |
233 | let diagnostic = analysis.diagnostics(current_file_id, true, None).unwrap().pop().unwrap(); | 265 | let diagnostic = analysis |
266 | .diagnostics(&DiagnosticsConfig::default(), current_file_id) | ||
267 | .unwrap() | ||
268 | .pop() | ||
269 | .unwrap(); | ||
234 | let mut fix = diagnostic.fix.unwrap(); | 270 | let mut fix = diagnostic.fix.unwrap(); |
235 | let edit = fix.source_change.source_file_edits.pop().unwrap(); | 271 | let edit = fix.source_change.source_file_edits.pop().unwrap(); |
236 | let changed_file_id = edit.file_id; | 272 | let changed_file_id = edit.file_id; |
@@ -251,58 +287,16 @@ mod tests { | |||
251 | let analysis = mock.analysis(); | 287 | let analysis = mock.analysis(); |
252 | let diagnostics = files | 288 | let diagnostics = files |
253 | .into_iter() | 289 | .into_iter() |
254 | .flat_map(|file_id| analysis.diagnostics(file_id, true, None).unwrap()) | ||
255 | .collect::<Vec<_>>(); | ||
256 | assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); | ||
257 | } | ||
258 | |||
259 | /// Takes a multi-file input fixture with annotated cursor position and the list of disabled diagnostics, | ||
260 | /// and checks that provided diagnostics aren't spawned during analysis. | ||
261 | fn check_disabled_diagnostics(ra_fixture: &str, disabled_diagnostics: &[&'static str]) { | ||
262 | let disabled_diagnostics: HashSet<_> = | ||
263 | disabled_diagnostics.into_iter().map(|diag| diag.to_string()).collect(); | ||
264 | |||
265 | let mock = MockAnalysis::with_files(ra_fixture); | ||
266 | let files = mock.files().map(|(it, _)| it).collect::<Vec<_>>(); | ||
267 | let analysis = mock.analysis(); | ||
268 | |||
269 | let diagnostics = files | ||
270 | .clone() | ||
271 | .into_iter() | ||
272 | .flat_map(|file_id| { | 290 | .flat_map(|file_id| { |
273 | analysis.diagnostics(file_id, true, Some(disabled_diagnostics.clone())).unwrap() | 291 | analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() |
274 | }) | 292 | }) |
275 | .collect::<Vec<_>>(); | 293 | .collect::<Vec<_>>(); |
276 | 294 | assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); | |
277 | // First, we have to check that diagnostic is not emitted when it's added to the disabled diagnostics list. | ||
278 | for diagnostic in diagnostics { | ||
279 | if let Some(name) = diagnostic.name { | ||
280 | assert!(!disabled_diagnostics.contains(&name), "Diagnostic {} is disabled", name); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | // Then, we must reset the config and repeat the check, so that we'll be sure that without | ||
285 | // config these diagnostics are emitted. | ||
286 | // This is required for tests to not become outdated if e.g. diagnostics name changes: | ||
287 | // without this additional run the test will pass simply because a diagnostic with an old name | ||
288 | // will no longer exist. | ||
289 | let diagnostics = files | ||
290 | .into_iter() | ||
291 | .flat_map(|file_id| analysis.diagnostics(file_id, true, None).unwrap()) | ||
292 | .collect::<Vec<_>>(); | ||
293 | |||
294 | assert!( | ||
295 | diagnostics | ||
296 | .into_iter() | ||
297 | .filter_map(|diag| diag.name) | ||
298 | .any(|name| disabled_diagnostics.contains(&name)), | ||
299 | "At least one of the diagnostics was not emitted even without config; are the diagnostics names correct?" | ||
300 | ); | ||
301 | } | 295 | } |
302 | 296 | ||
303 | fn check_expect(ra_fixture: &str, expect: Expect) { | 297 | fn check_expect(ra_fixture: &str, expect: Expect) { |
304 | let (analysis, file_id) = single_file(ra_fixture); | 298 | let (analysis, file_id) = single_file(ra_fixture); |
305 | let diagnostics = analysis.diagnostics(file_id, true, None).unwrap(); | 299 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); |
306 | expect.assert_debug_eq(&diagnostics) | 300 | expect.assert_debug_eq(&diagnostics) |
307 | } | 301 | } |
308 | 302 | ||
@@ -562,9 +556,6 @@ fn test_fn() { | |||
562 | expect![[r#" | 556 | expect![[r#" |
563 | [ | 557 | [ |
564 | Diagnostic { | 558 | Diagnostic { |
565 | name: Some( | ||
566 | "unresolved-module", | ||
567 | ), | ||
568 | message: "unresolved module", | 559 | message: "unresolved module", |
569 | range: 0..8, | 560 | range: 0..8, |
570 | severity: Error, | 561 | severity: Error, |
@@ -741,6 +732,15 @@ struct Foo { | |||
741 | 732 | ||
742 | #[test] | 733 | #[test] |
743 | fn test_disabled_diagnostics() { | 734 | fn test_disabled_diagnostics() { |
744 | check_disabled_diagnostics(r#"mod foo;"#, &["unresolved-module"]); | 735 | let mut config = DiagnosticsConfig::default(); |
736 | config.disabled.insert("unresolved-module".into()); | ||
737 | |||
738 | let (analysis, file_id) = single_file(r#"mod foo;"#); | ||
739 | |||
740 | let diagnostics = analysis.diagnostics(&config, file_id).unwrap(); | ||
741 | assert!(diagnostics.is_empty()); | ||
742 | |||
743 | let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); | ||
744 | assert!(!diagnostics.is_empty()); | ||
745 | } | 745 | } |
746 | } | 746 | } |
diff --git a/crates/ide/src/diagnostics/diagnostics_with_fix.rs b/crates/ide/src/diagnostics/fixes.rs index 85b46c995..68ae1c239 100644 --- a/crates/ide/src/diagnostics/diagnostics_with_fix.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -1,7 +1,5 @@ | |||
1 | //! Provides a way to attach fixes to the diagnostics. | 1 | //! Provides a way to attach fixes to the diagnostics. |
2 | //! The same module also has all curret custom fixes for the diagnostics implemented. | 2 | //! The same module also has all curret custom fixes for the diagnostics implemented. |
3 | use crate::Fix; | ||
4 | use ast::{edit::IndentLevel, make}; | ||
5 | use base_db::FileId; | 3 | use base_db::FileId; |
6 | use hir::{ | 4 | use hir::{ |
7 | db::AstDatabase, | 5 | db::AstDatabase, |
@@ -12,9 +10,15 @@ use ide_db::{ | |||
12 | source_change::{FileSystemEdit, SourceFileEdit}, | 10 | source_change::{FileSystemEdit, SourceFileEdit}, |
13 | RootDatabase, | 11 | RootDatabase, |
14 | }; | 12 | }; |
15 | use syntax::{algo, ast, AstNode}; | 13 | use syntax::{ |
14 | algo, | ||
15 | ast::{self, edit::IndentLevel, make}, | ||
16 | AstNode, | ||
17 | }; | ||
16 | use text_edit::TextEdit; | 18 | use text_edit::TextEdit; |
17 | 19 | ||
20 | use crate::diagnostics::Fix; | ||
21 | |||
18 | /// A [Diagnostic] that potentially has a fix available. | 22 | /// A [Diagnostic] that potentially has a fix available. |
19 | /// | 23 | /// |
20 | /// [Diagnostic]: hir::diagnostics::Diagnostic | 24 | /// [Diagnostic]: hir::diagnostics::Diagnostic |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 4b797f374..e3af6d5bc 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -44,7 +44,7 @@ mod syntax_highlighting; | |||
44 | mod syntax_tree; | 44 | mod syntax_tree; |
45 | mod typing; | 45 | mod typing; |
46 | 46 | ||
47 | use std::{collections::HashSet, sync::Arc}; | 47 | use std::sync::Arc; |
48 | 48 | ||
49 | use base_db::{ | 49 | use base_db::{ |
50 | salsa::{self, ParallelDatabase}, | 50 | salsa::{self, ParallelDatabase}, |
@@ -65,7 +65,7 @@ pub use crate::{ | |||
65 | completion::{ | 65 | completion::{ |
66 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, | 66 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, |
67 | }, | 67 | }, |
68 | diagnostics::Severity, | 68 | diagnostics::{Diagnostic, DiagnosticsConfig, Fix, Severity}, |
69 | display::NavigationTarget, | 69 | display::NavigationTarget, |
70 | expand_macro::ExpandedMacro, | 70 | expand_macro::ExpandedMacro, |
71 | file_structure::StructureNode, | 71 | file_structure::StructureNode, |
@@ -88,6 +88,7 @@ pub use base_db::{ | |||
88 | pub use hir::{Documentation, Semantics}; | 88 | pub use hir::{Documentation, Semantics}; |
89 | pub use ide_db::{ | 89 | pub use ide_db::{ |
90 | change::AnalysisChange, | 90 | change::AnalysisChange, |
91 | label::Label, | ||
91 | line_index::{LineCol, LineIndex}, | 92 | line_index::{LineCol, LineIndex}, |
92 | search::SearchScope, | 93 | search::SearchScope, |
93 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, | 94 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
@@ -99,35 +100,6 @@ pub use text_edit::{Indel, TextEdit}; | |||
99 | 100 | ||
100 | pub type Cancelable<T> = Result<T, Canceled>; | 101 | pub type Cancelable<T> = Result<T, Canceled>; |
101 | 102 | ||
102 | #[derive(Debug)] | ||
103 | pub struct Diagnostic { | ||
104 | pub name: Option<String>, | ||
105 | pub message: String, | ||
106 | pub range: TextRange, | ||
107 | pub severity: Severity, | ||
108 | pub fix: Option<Fix>, | ||
109 | } | ||
110 | |||
111 | #[derive(Debug)] | ||
112 | pub struct Fix { | ||
113 | pub label: String, | ||
114 | pub source_change: SourceChange, | ||
115 | /// Allows to trigger the fix only when the caret is in the range given | ||
116 | pub fix_trigger_range: TextRange, | ||
117 | } | ||
118 | |||
119 | impl Fix { | ||
120 | pub fn new( | ||
121 | label: impl Into<String>, | ||
122 | source_change: SourceChange, | ||
123 | fix_trigger_range: TextRange, | ||
124 | ) -> Self { | ||
125 | let label = label.into(); | ||
126 | assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.')); | ||
127 | Self { label, source_change, fix_trigger_range } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | /// Info associated with a text range. | 103 | /// Info associated with a text range. |
132 | #[derive(Debug)] | 104 | #[derive(Debug)] |
133 | pub struct RangeInfo<T> { | 105 | pub struct RangeInfo<T> { |
@@ -148,7 +120,7 @@ pub struct AnalysisHost { | |||
148 | } | 120 | } |
149 | 121 | ||
150 | impl AnalysisHost { | 122 | impl AnalysisHost { |
151 | pub fn new(lru_capacity: Option<usize>) -> Self { | 123 | pub fn new(lru_capacity: Option<usize>) -> AnalysisHost { |
152 | AnalysisHost { db: RootDatabase::new(lru_capacity) } | 124 | AnalysisHost { db: RootDatabase::new(lru_capacity) } |
153 | } | 125 | } |
154 | 126 | ||
@@ -495,13 +467,10 @@ impl Analysis { | |||
495 | /// Computes the set of diagnostics for the given file. | 467 | /// Computes the set of diagnostics for the given file. |
496 | pub fn diagnostics( | 468 | pub fn diagnostics( |
497 | &self, | 469 | &self, |
470 | config: &DiagnosticsConfig, | ||
498 | file_id: FileId, | 471 | file_id: FileId, |
499 | enable_experimental: bool, | ||
500 | disabled_diagnostics: Option<HashSet<String>>, | ||
501 | ) -> Cancelable<Vec<Diagnostic>> { | 472 | ) -> Cancelable<Vec<Diagnostic>> { |
502 | self.with_db(|db| { | 473 | self.with_db(|db| diagnostics::diagnostics(db, config, file_id)) |
503 | diagnostics::diagnostics(db, file_id, enable_experimental, disabled_diagnostics) | ||
504 | }) | ||
505 | } | 474 | } |
506 | 475 | ||
507 | /// Returns the edit required to rename reference at the position to the new | 476 | /// Returns the edit required to rename reference at the position to the new |
diff --git a/crates/ide_db/src/label.rs b/crates/ide_db/src/label.rs new file mode 100644 index 000000000..c0e89e72f --- /dev/null +++ b/crates/ide_db/src/label.rs | |||
@@ -0,0 +1,49 @@ | |||
1 | //! See `Label` | ||
2 | use std::fmt; | ||
3 | |||
4 | /// A type to specify UI label, like an entry in the list of assists. Enforces | ||
5 | /// proper casing: | ||
6 | /// | ||
7 | /// Frobnicate bar | ||
8 | /// | ||
9 | /// Note the upper-case first letter and the absence of `.` at the end. | ||
10 | #[derive(Clone)] | ||
11 | pub struct Label(String); | ||
12 | |||
13 | impl PartialEq<str> for Label { | ||
14 | fn eq(&self, other: &str) -> bool { | ||
15 | self.0 == other | ||
16 | } | ||
17 | } | ||
18 | |||
19 | impl PartialEq<&'_ str> for Label { | ||
20 | fn eq(&self, other: &&str) -> bool { | ||
21 | self == *other | ||
22 | } | ||
23 | } | ||
24 | |||
25 | impl From<Label> for String { | ||
26 | fn from(label: Label) -> String { | ||
27 | label.0 | ||
28 | } | ||
29 | } | ||
30 | |||
31 | impl Label { | ||
32 | pub fn new(label: impl Into<String>) -> Label { | ||
33 | let label = label.into(); | ||
34 | assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.')); | ||
35 | Label(label) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | impl fmt::Display for Label { | ||
40 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
41 | fmt::Display::fmt(&self.0, f) | ||
42 | } | ||
43 | } | ||
44 | |||
45 | impl fmt::Debug for Label { | ||
46 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
47 | fmt::Debug::fmt(&self.0, f) | ||
48 | } | ||
49 | } | ||
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index fd474cd0f..70ada02f3 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | //! | 2 | //! |
3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. | 3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. |
4 | 4 | ||
5 | pub mod label; | ||
5 | pub mod line_index; | 6 | pub mod line_index; |
6 | pub mod symbol_index; | 7 | pub mod symbol_index; |
7 | pub mod change; | 8 | pub mod change; |
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index 43f0196af..c312e0a2e 100644 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ b/crates/rust-analyzer/src/cli/analysis_bench.rs | |||
@@ -7,7 +7,10 @@ use base_db::{ | |||
7 | salsa::{Database, Durability}, | 7 | salsa::{Database, Durability}, |
8 | FileId, | 8 | FileId, |
9 | }; | 9 | }; |
10 | use ide::{Analysis, AnalysisChange, AnalysisHost, CompletionConfig, FilePosition, LineCol}; | 10 | use ide::{ |
11 | Analysis, AnalysisChange, AnalysisHost, CompletionConfig, DiagnosticsConfig, FilePosition, | ||
12 | LineCol, | ||
13 | }; | ||
11 | use vfs::AbsPathBuf; | 14 | use vfs::AbsPathBuf; |
12 | 15 | ||
13 | use crate::{ | 16 | use crate::{ |
@@ -71,7 +74,7 @@ impl BenchCmd { | |||
71 | match &self.what { | 74 | match &self.what { |
72 | BenchWhat::Highlight { .. } => { | 75 | BenchWhat::Highlight { .. } => { |
73 | let res = do_work(&mut host, file_id, |analysis| { | 76 | let res = do_work(&mut host, file_id, |analysis| { |
74 | analysis.diagnostics(file_id, true, None).unwrap(); | 77 | analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); |
75 | analysis.highlight_as_html(file_id, false).unwrap() | 78 | analysis.highlight_as_html(file_id, false).unwrap() |
76 | }); | 79 | }); |
77 | if verbosity.is_verbose() { | 80 | if verbosity.is_verbose() { |
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 31eb7ff3f..c424aa6e2 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs | |||
@@ -8,7 +8,7 @@ use rustc_hash::FxHashSet; | |||
8 | 8 | ||
9 | use base_db::SourceDatabaseExt; | 9 | use base_db::SourceDatabaseExt; |
10 | use hir::Crate; | 10 | use hir::Crate; |
11 | use ide::Severity; | 11 | use ide::{DiagnosticsConfig, Severity}; |
12 | 12 | ||
13 | use crate::cli::{load_cargo::load_cargo, Result}; | 13 | use crate::cli::{load_cargo::load_cargo, Result}; |
14 | 14 | ||
@@ -47,7 +47,8 @@ pub fn diagnostics( | |||
47 | String::from("unknown") | 47 | String::from("unknown") |
48 | }; | 48 | }; |
49 | println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); | 49 | println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); |
50 | for diagnostic in analysis.diagnostics(file_id, true, None).unwrap() { | 50 | for diagnostic in analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() |
51 | { | ||
51 | if matches!(diagnostic.severity, Severity::Error) { | 52 | if matches!(diagnostic.severity, Severity::Error) { |
52 | found_error = true; | 53 | found_error = true; |
53 | } | 54 | } |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 44fd7c286..99f7751ac 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -7,24 +7,25 @@ | |||
7 | //! configure the server itself, feature flags are passed into analysis, and | 7 | //! configure the server itself, feature flags are passed into analysis, and |
8 | //! tweak things like automatic insertion of `()` in completions. | 8 | //! tweak things like automatic insertion of `()` in completions. |
9 | 9 | ||
10 | use std::{collections::HashSet, ffi::OsString, path::PathBuf}; | 10 | use std::{ffi::OsString, path::PathBuf}; |
11 | 11 | ||
12 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
13 | use ide::{AssistConfig, CompletionConfig, HoverConfig, InlayHintsConfig}; | 13 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; |
14 | use lsp_types::ClientCapabilities; | 14 | use lsp_types::ClientCapabilities; |
15 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 15 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
16 | use rustc_hash::FxHashSet; | ||
16 | use serde::Deserialize; | 17 | use serde::Deserialize; |
17 | use vfs::AbsPathBuf; | 18 | use vfs::AbsPathBuf; |
18 | 19 | ||
19 | use crate::diagnostics::DiagnosticsConfig; | 20 | use crate::diagnostics::DiagnosticsMapConfig; |
20 | 21 | ||
21 | #[derive(Debug, Clone)] | 22 | #[derive(Debug, Clone)] |
22 | pub struct Config { | 23 | pub struct Config { |
23 | pub client_caps: ClientCapsConfig, | 24 | pub client_caps: ClientCapsConfig, |
24 | 25 | ||
25 | pub publish_diagnostics: bool, | 26 | pub publish_diagnostics: bool, |
26 | pub experimental_diagnostics: bool, | ||
27 | pub diagnostics: DiagnosticsConfig, | 27 | pub diagnostics: DiagnosticsConfig, |
28 | pub diagnostics_map: DiagnosticsMapConfig, | ||
28 | pub lru_capacity: Option<usize>, | 29 | pub lru_capacity: Option<usize>, |
29 | pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, | 30 | pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, |
30 | pub files: FilesConfig, | 31 | pub files: FilesConfig, |
@@ -45,14 +46,6 @@ pub struct Config { | |||
45 | pub with_sysroot: bool, | 46 | pub with_sysroot: bool, |
46 | pub linked_projects: Vec<LinkedProject>, | 47 | pub linked_projects: Vec<LinkedProject>, |
47 | pub root_path: AbsPathBuf, | 48 | pub root_path: AbsPathBuf, |
48 | |||
49 | pub analysis: AnalysisConfig, | ||
50 | } | ||
51 | |||
52 | /// Configuration parameters for the analysis run. | ||
53 | #[derive(Debug, Default, Clone)] | ||
54 | pub struct AnalysisConfig { | ||
55 | pub disabled_diagnostics: HashSet<String>, | ||
56 | } | 49 | } |
57 | 50 | ||
58 | #[derive(Debug, Clone, Eq, PartialEq)] | 51 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -146,8 +139,8 @@ impl Config { | |||
146 | 139 | ||
147 | with_sysroot: true, | 140 | with_sysroot: true, |
148 | publish_diagnostics: true, | 141 | publish_diagnostics: true, |
149 | experimental_diagnostics: true, | ||
150 | diagnostics: DiagnosticsConfig::default(), | 142 | diagnostics: DiagnosticsConfig::default(), |
143 | diagnostics_map: DiagnosticsMapConfig::default(), | ||
151 | lru_capacity: None, | 144 | lru_capacity: None, |
152 | proc_macro_srv: None, | 145 | proc_macro_srv: None, |
153 | files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, | 146 | files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, |
@@ -184,8 +177,6 @@ impl Config { | |||
184 | hover: HoverConfig::default(), | 177 | hover: HoverConfig::default(), |
185 | linked_projects: Vec::new(), | 178 | linked_projects: Vec::new(), |
186 | root_path, | 179 | root_path, |
187 | |||
188 | analysis: AnalysisConfig::default(), | ||
189 | } | 180 | } |
190 | } | 181 | } |
191 | 182 | ||
@@ -200,8 +191,11 @@ impl Config { | |||
200 | 191 | ||
201 | self.with_sysroot = data.withSysroot; | 192 | self.with_sysroot = data.withSysroot; |
202 | self.publish_diagnostics = data.diagnostics_enable; | 193 | self.publish_diagnostics = data.diagnostics_enable; |
203 | self.experimental_diagnostics = data.diagnostics_enableExperimental; | ||
204 | self.diagnostics = DiagnosticsConfig { | 194 | self.diagnostics = DiagnosticsConfig { |
195 | disable_experimental: !data.diagnostics_enableExperimental, | ||
196 | disabled: data.diagnostics_disabled, | ||
197 | }; | ||
198 | self.diagnostics_map = DiagnosticsMapConfig { | ||
205 | warnings_as_info: data.diagnostics_warningsAsInfo, | 199 | warnings_as_info: data.diagnostics_warningsAsInfo, |
206 | warnings_as_hint: data.diagnostics_warningsAsHint, | 200 | warnings_as_hint: data.diagnostics_warningsAsHint, |
207 | }; | 201 | }; |
@@ -303,8 +297,6 @@ impl Config { | |||
303 | goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef, | 297 | goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef, |
304 | }; | 298 | }; |
305 | 299 | ||
306 | self.analysis = AnalysisConfig { disabled_diagnostics: data.analysis_disabledDiagnostics }; | ||
307 | |||
308 | log::info!("Config::update() = {:#?}", self); | 300 | log::info!("Config::update() = {:#?}", self); |
309 | } | 301 | } |
310 | 302 | ||
@@ -369,14 +361,6 @@ impl Config { | |||
369 | self.client_caps.status_notification = get_bool("statusNotification"); | 361 | self.client_caps.status_notification = get_bool("statusNotification"); |
370 | } | 362 | } |
371 | } | 363 | } |
372 | |||
373 | pub fn disabled_diagnostics(&self) -> Option<HashSet<String>> { | ||
374 | if self.analysis.disabled_diagnostics.is_empty() { | ||
375 | None | ||
376 | } else { | ||
377 | Some(self.analysis.disabled_diagnostics.clone()) | ||
378 | } | ||
379 | } | ||
380 | } | 364 | } |
381 | 365 | ||
382 | #[derive(Deserialize)] | 366 | #[derive(Deserialize)] |
@@ -434,6 +418,7 @@ config_data! { | |||
434 | 418 | ||
435 | diagnostics_enable: bool = true, | 419 | diagnostics_enable: bool = true, |
436 | diagnostics_enableExperimental: bool = true, | 420 | diagnostics_enableExperimental: bool = true, |
421 | diagnostics_disabled: FxHashSet<String> = FxHashSet::default(), | ||
437 | diagnostics_warningsAsHint: Vec<String> = Vec::new(), | 422 | diagnostics_warningsAsHint: Vec<String> = Vec::new(), |
438 | diagnostics_warningsAsInfo: Vec<String> = Vec::new(), | 423 | diagnostics_warningsAsInfo: Vec<String> = Vec::new(), |
439 | 424 | ||
@@ -464,7 +449,5 @@ config_data! { | |||
464 | rustfmt_overrideCommand: Option<Vec<String>> = None, | 449 | rustfmt_overrideCommand: Option<Vec<String>> = None, |
465 | 450 | ||
466 | withSysroot: bool = true, | 451 | withSysroot: bool = true, |
467 | |||
468 | analysis_disabledDiagnostics: HashSet<String> = HashSet::new(), | ||
469 | } | 452 | } |
470 | } | 453 | } |
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs index 108df3eb0..ee6f2a867 100644 --- a/crates/rust-analyzer/src/diagnostics.rs +++ b/crates/rust-analyzer/src/diagnostics.rs | |||
@@ -11,7 +11,7 @@ use crate::lsp_ext; | |||
11 | pub(crate) type CheckFixes = Arc<FxHashMap<FileId, Vec<Fix>>>; | 11 | pub(crate) type CheckFixes = Arc<FxHashMap<FileId, Vec<Fix>>>; |
12 | 12 | ||
13 | #[derive(Debug, Default, Clone)] | 13 | #[derive(Debug, Default, Clone)] |
14 | pub struct DiagnosticsConfig { | 14 | pub struct DiagnosticsMapConfig { |
15 | pub warnings_as_info: Vec<String>, | 15 | pub warnings_as_info: Vec<String>, |
16 | pub warnings_as_hint: Vec<String>, | 16 | pub warnings_as_hint: Vec<String>, |
17 | } | 17 | } |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index 6d5408156..df5583897 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -7,11 +7,11 @@ use stdx::format_to; | |||
7 | 7 | ||
8 | use crate::{lsp_ext, to_proto::url_from_abs_path}; | 8 | use crate::{lsp_ext, to_proto::url_from_abs_path}; |
9 | 9 | ||
10 | use super::DiagnosticsConfig; | 10 | use super::DiagnosticsMapConfig; |
11 | 11 | ||
12 | /// Determines the LSP severity from a diagnostic | 12 | /// Determines the LSP severity from a diagnostic |
13 | fn diagnostic_severity( | 13 | fn diagnostic_severity( |
14 | config: &DiagnosticsConfig, | 14 | config: &DiagnosticsMapConfig, |
15 | level: flycheck::DiagnosticLevel, | 15 | level: flycheck::DiagnosticLevel, |
16 | code: Option<flycheck::DiagnosticCode>, | 16 | code: Option<flycheck::DiagnosticCode>, |
17 | ) -> Option<lsp_types::DiagnosticSeverity> { | 17 | ) -> Option<lsp_types::DiagnosticSeverity> { |
@@ -141,7 +141,7 @@ pub(crate) struct MappedRustDiagnostic { | |||
141 | /// | 141 | /// |
142 | /// If the diagnostic has no primary span this will return `None` | 142 | /// If the diagnostic has no primary span this will return `None` |
143 | pub(crate) fn map_rust_diagnostic_to_lsp( | 143 | pub(crate) fn map_rust_diagnostic_to_lsp( |
144 | config: &DiagnosticsConfig, | 144 | config: &DiagnosticsMapConfig, |
145 | rd: &flycheck::Diagnostic, | 145 | rd: &flycheck::Diagnostic, |
146 | workspace_root: &Path, | 146 | workspace_root: &Path, |
147 | ) -> Vec<MappedRustDiagnostic> { | 147 | ) -> Vec<MappedRustDiagnostic> { |
@@ -259,10 +259,10 @@ mod tests { | |||
259 | use expect::{expect_file, ExpectFile}; | 259 | use expect::{expect_file, ExpectFile}; |
260 | 260 | ||
261 | fn check(diagnostics_json: &str, expect: ExpectFile) { | 261 | fn check(diagnostics_json: &str, expect: ExpectFile) { |
262 | check_with_config(DiagnosticsConfig::default(), diagnostics_json, expect) | 262 | check_with_config(DiagnosticsMapConfig::default(), diagnostics_json, expect) |
263 | } | 263 | } |
264 | 264 | ||
265 | fn check_with_config(config: DiagnosticsConfig, diagnostics_json: &str, expect: ExpectFile) { | 265 | fn check_with_config(config: DiagnosticsMapConfig, diagnostics_json: &str, expect: ExpectFile) { |
266 | let diagnostic: flycheck::Diagnostic = serde_json::from_str(diagnostics_json).unwrap(); | 266 | let diagnostic: flycheck::Diagnostic = serde_json::from_str(diagnostics_json).unwrap(); |
267 | let workspace_root = Path::new("/test/"); | 267 | let workspace_root = Path::new("/test/"); |
268 | let actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root); | 268 | let actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root); |
@@ -402,9 +402,9 @@ mod tests { | |||
402 | #[cfg(not(windows))] | 402 | #[cfg(not(windows))] |
403 | fn rustc_unused_variable_as_info() { | 403 | fn rustc_unused_variable_as_info() { |
404 | check_with_config( | 404 | check_with_config( |
405 | DiagnosticsConfig { | 405 | DiagnosticsMapConfig { |
406 | warnings_as_info: vec!["unused_variables".to_string()], | 406 | warnings_as_info: vec!["unused_variables".to_string()], |
407 | ..DiagnosticsConfig::default() | 407 | ..DiagnosticsMapConfig::default() |
408 | }, | 408 | }, |
409 | r##"{ | 409 | r##"{ |
410 | "message": "unused variable: `foo`", | 410 | "message": "unused variable: `foo`", |
@@ -486,9 +486,9 @@ mod tests { | |||
486 | #[cfg(not(windows))] | 486 | #[cfg(not(windows))] |
487 | fn rustc_unused_variable_as_hint() { | 487 | fn rustc_unused_variable_as_hint() { |
488 | check_with_config( | 488 | check_with_config( |
489 | DiagnosticsConfig { | 489 | DiagnosticsMapConfig { |
490 | warnings_as_hint: vec!["unused_variables".to_string()], | 490 | warnings_as_hint: vec!["unused_variables".to_string()], |
491 | ..DiagnosticsConfig::default() | 491 | ..DiagnosticsMapConfig::default() |
492 | }, | 492 | }, |
493 | r##"{ | 493 | r##"{ |
494 | "message": "unused variable: `foo`", | 494 | "message": "unused variable: `foo`", |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 4f77b1b4d..33e60b500 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -271,24 +271,24 @@ pub(crate) fn handle_document_symbol( | |||
271 | }; | 271 | }; |
272 | parents.push((doc_symbol, symbol.parent)); | 272 | parents.push((doc_symbol, symbol.parent)); |
273 | } | 273 | } |
274 | let mut document_symbols = Vec::new(); | ||
275 | // Constructs `document_symbols` from `parents`, in order from the end. | ||
276 | while let Some((node, parent)) = parents.pop() { | ||
277 | match parent { | ||
278 | None => document_symbols.push(node), | ||
279 | Some(i) => { | ||
280 | parents[i].0.children.get_or_insert_with(Vec::new).push(node); | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | 274 | ||
285 | fn reverse(symbols: &mut Vec<DocumentSymbol>) { | 275 | // Builds hierarchy from a flat list, in reverse order (so that indices |
286 | for sym in symbols.iter_mut() { | 276 | // makes sense) |
287 | sym.children.as_mut().map(|c| reverse(c)); | 277 | let document_symbols = { |
278 | let mut acc = Vec::new(); | ||
279 | while let Some((mut node, parent_idx)) = parents.pop() { | ||
280 | if let Some(children) = &mut node.children { | ||
281 | children.reverse(); | ||
282 | } | ||
283 | let parent = match parent_idx { | ||
284 | None => &mut acc, | ||
285 | Some(i) => parents[i].0.children.get_or_insert_with(Vec::new), | ||
286 | }; | ||
287 | parent.push(node); | ||
288 | } | 288 | } |
289 | symbols.reverse(); | 289 | acc.reverse(); |
290 | } | 290 | acc |
291 | reverse(&mut document_symbols); | 291 | }; |
292 | 292 | ||
293 | let res = if snap.config.client_caps.hierarchical_symbols { | 293 | let res = if snap.config.client_caps.hierarchical_symbols { |
294 | document_symbols.into() | 294 | document_symbols.into() |
@@ -775,21 +775,16 @@ fn handle_fixes( | |||
775 | None => {} | 775 | None => {} |
776 | }; | 776 | }; |
777 | 777 | ||
778 | let diagnostics = snap.analysis.diagnostics( | 778 | let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, file_id)?; |
779 | file_id, | ||
780 | snap.config.experimental_diagnostics, | ||
781 | snap.config.disabled_diagnostics(), | ||
782 | )?; | ||
783 | 779 | ||
784 | for fix in diagnostics | 780 | for fix in diagnostics |
785 | .into_iter() | 781 | .into_iter() |
786 | .filter_map(|d| d.fix) | 782 | .filter_map(|d| d.fix) |
787 | .filter(|fix| fix.fix_trigger_range.intersect(range).is_some()) | 783 | .filter(|fix| fix.fix_trigger_range.intersect(range).is_some()) |
788 | { | 784 | { |
789 | let title = fix.label; | ||
790 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; | 785 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; |
791 | let action = lsp_ext::CodeAction { | 786 | let action = lsp_ext::CodeAction { |
792 | title, | 787 | title: fix.label.to_string(), |
793 | id: None, | 788 | id: None, |
794 | group: None, | 789 | group: None, |
795 | kind: Some(CodeActionKind::QUICKFIX), | 790 | kind: Some(CodeActionKind::QUICKFIX), |
@@ -1051,13 +1046,10 @@ pub(crate) fn publish_diagnostics( | |||
1051 | ) -> Result<Vec<Diagnostic>> { | 1046 | ) -> Result<Vec<Diagnostic>> { |
1052 | let _p = profile::span("publish_diagnostics"); | 1047 | let _p = profile::span("publish_diagnostics"); |
1053 | let line_index = snap.analysis.file_line_index(file_id)?; | 1048 | let line_index = snap.analysis.file_line_index(file_id)?; |
1049 | |||
1054 | let diagnostics: Vec<Diagnostic> = snap | 1050 | let diagnostics: Vec<Diagnostic> = snap |
1055 | .analysis | 1051 | .analysis |
1056 | .diagnostics( | 1052 | .diagnostics(&snap.config.diagnostics, file_id)? |
1057 | file_id, | ||
1058 | snap.config.experimental_diagnostics, | ||
1059 | snap.config.disabled_diagnostics(), | ||
1060 | )? | ||
1061 | .into_iter() | 1053 | .into_iter() |
1062 | .map(|d| Diagnostic { | 1054 | .map(|d| Diagnostic { |
1063 | range: to_proto::range(&line_index, d.range), | 1055 | range: to_proto::range(&line_index, d.range), |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 66e04653a..f039cdc31 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -248,7 +248,7 @@ impl GlobalState { | |||
248 | Event::Flycheck(task) => match task { | 248 | Event::Flycheck(task) => match task { |
249 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { | 249 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { |
250 | let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( | 250 | let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( |
251 | &self.config.diagnostics, | 251 | &self.config.diagnostics_map, |
252 | &diagnostic, | 252 | &diagnostic, |
253 | &workspace_root, | 253 | &workspace_root, |
254 | ); | 254 | ); |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 535de2f71..643dcb4fc 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -704,7 +704,7 @@ pub(crate) fn unresolved_code_action( | |||
704 | index: usize, | 704 | index: usize, |
705 | ) -> Result<lsp_ext::CodeAction> { | 705 | ) -> Result<lsp_ext::CodeAction> { |
706 | let res = lsp_ext::CodeAction { | 706 | let res = lsp_ext::CodeAction { |
707 | title: assist.label().to_string(), | 707 | title: assist.label.to_string(), |
708 | id: Some(format!("{}:{}", assist.id.0, index.to_string())), | 708 | id: Some(format!("{}:{}", assist.id.0, index.to_string())), |
709 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), | 709 | group: assist.group.filter(|_| snap.config.client_caps.code_action_group).map(|gr| gr.0), |
710 | kind: Some(code_action_kind(assist.id.1)), | 710 | kind: Some(code_action_kind(assist.id.1)), |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index 265d19288..5d60f0219 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -1,5 +1,8 @@ | |||
1 | //! Missing batteries for standard libraries. | 1 | //! Missing batteries for standard libraries. |
2 | use std::time::Instant; | 2 | use std::{ |
3 | sync::atomic::{AtomicUsize, Ordering}, | ||
4 | time::Instant, | ||
5 | }; | ||
3 | 6 | ||
4 | mod macros; | 7 | mod macros; |
5 | 8 | ||
@@ -134,6 +137,31 @@ where | |||
134 | left | 137 | left |
135 | } | 138 | } |
136 | 139 | ||
140 | pub struct RacyFlag(AtomicUsize); | ||
141 | |||
142 | impl RacyFlag { | ||
143 | pub const fn new() -> RacyFlag { | ||
144 | RacyFlag(AtomicUsize::new(0)) | ||
145 | } | ||
146 | |||
147 | pub fn get(&self, init: impl FnMut() -> bool) -> bool { | ||
148 | let mut init = Some(init); | ||
149 | self.get_impl(&mut || init.take().map_or(false, |mut f| f())) | ||
150 | } | ||
151 | |||
152 | fn get_impl(&self, init: &mut dyn FnMut() -> bool) -> bool { | ||
153 | match self.0.load(Ordering::Relaxed) { | ||
154 | 0 => false, | ||
155 | 1 => true, | ||
156 | _ => { | ||
157 | let res = init(); | ||
158 | self.0.store(if res { 1 } else { 0 }, Ordering::Relaxed); | ||
159 | res | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
137 | #[cfg(test)] | 165 | #[cfg(test)] |
138 | mod tests { | 166 | mod tests { |
139 | use super::*; | 167 | use super::*; |
diff --git a/docs/dev/style.md b/docs/dev/style.md index 8effddcda..2454087e8 100644 --- a/docs/dev/style.md +++ b/docs/dev/style.md | |||
@@ -148,8 +148,13 @@ struct Foo { | |||
148 | Use boring and long names for local variables ([yay code completion](https://github.com/rust-analyzer/rust-analyzer/pull/4162#discussion_r417130973)). | 148 | Use boring and long names for local variables ([yay code completion](https://github.com/rust-analyzer/rust-analyzer/pull/4162#discussion_r417130973)). |
149 | The default name is a lowercased name of the type: `global_state: GlobalState`. | 149 | The default name is a lowercased name of the type: `global_state: GlobalState`. |
150 | Avoid ad-hoc acronyms and contractions, but use the ones that exist consistently (`db`, `ctx`, `acc`). | 150 | Avoid ad-hoc acronyms and contractions, but use the ones that exist consistently (`db`, `ctx`, `acc`). |
151 | The default name for "result of the function" local variable is `res`. | 151 | |
152 | The default name for "I don't really care about the name" variable is `it`. | 152 | Default names: |
153 | |||
154 | * `res` -- "result of the function" local variable | ||
155 | * `it` -- I don't really care about the name | ||
156 | * `n_foo` -- number of foos | ||
157 | * `foo_idx` -- index of `foo` | ||
153 | 158 | ||
154 | # Collection types | 159 | # Collection types |
155 | 160 | ||
diff --git a/editors/code/package.json b/editors/code/package.json index 429ff5def..f079f73b8 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -592,31 +592,31 @@ | |||
592 | "default": true, | 592 | "default": true, |
593 | "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might have more false positives than usual." | 593 | "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might have more false positives than usual." |
594 | }, | 594 | }, |
595 | "rust-analyzer.diagnostics.warningsAsInfo": { | 595 | "rust-analyzer.diagnostics.disabled": { |
596 | "type": "array", | 596 | "type": "array", |
597 | "uniqueItems": true, | 597 | "uniqueItems": true, |
598 | "items": { | 598 | "items": { |
599 | "type": "string" | 599 | "type": "string" |
600 | }, | 600 | }, |
601 | "description": "List of warnings that should be displayed with info severity.\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.", | 601 | "description": "List of rust-analyzer diagnostics to disable", |
602 | "default": [] | 602 | "default": [] |
603 | }, | 603 | }, |
604 | "rust-analyzer.diagnostics.warningsAsHint": { | 604 | "rust-analyzer.diagnostics.warningsAsInfo": { |
605 | "type": "array", | 605 | "type": "array", |
606 | "uniqueItems": true, | 606 | "uniqueItems": true, |
607 | "items": { | 607 | "items": { |
608 | "type": "string" | 608 | "type": "string" |
609 | }, | 609 | }, |
610 | "description": "List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", | 610 | "description": "List of warnings that should be displayed with info severity.\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.", |
611 | "default": [] | 611 | "default": [] |
612 | }, | 612 | }, |
613 | "rust-analyzer.analysis.disabledDiagnostics": { | 613 | "rust-analyzer.diagnostics.warningsAsHint": { |
614 | "type": "array", | 614 | "type": "array", |
615 | "uniqueItems": true, | 615 | "uniqueItems": true, |
616 | "items": { | 616 | "items": { |
617 | "type": "string" | 617 | "type": "string" |
618 | }, | 618 | }, |
619 | "description": "List of rust-analyzer diagnostics to disable", | 619 | "description": "List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", |
620 | "default": [] | 620 | "default": [] |
621 | } | 621 | } |
622 | } | 622 | } |