diff options
134 files changed, 1907 insertions, 1282 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2acd44012..f46fb8fec 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml | |||
@@ -16,20 +16,6 @@ env: | |||
16 | RUSTUP_MAX_RETRIES: 10 | 16 | RUSTUP_MAX_RETRIES: 10 |
17 | 17 | ||
18 | jobs: | 18 | jobs: |
19 | # rust-audit: | ||
20 | # name: Audit Rust vulnerabilities | ||
21 | # runs-on: ubuntu-latest | ||
22 | # steps: | ||
23 | # - name: Checkout repository | ||
24 | # uses: actions/checkout@v2 | ||
25 | |||
26 | # - uses: actions-rs/[email protected] | ||
27 | # with: | ||
28 | # crate: cargo-audit | ||
29 | # use-tool-cache: true | ||
30 | |||
31 | # - run: cargo audit | ||
32 | |||
33 | rust: | 19 | rust: |
34 | name: Rust | 20 | name: Rust |
35 | runs-on: ${{ matrix.os }} | 21 | runs-on: ${{ matrix.os }} |
@@ -88,11 +74,14 @@ jobs: | |||
88 | if: matrix.os == 'windows-latest' | 74 | if: matrix.os == 'windows-latest' |
89 | run: Remove-Item ./target/debug/xtask.exe, ./target/debug/deps/xtask.exe | 75 | run: Remove-Item ./target/debug/xtask.exe, ./target/debug/deps/xtask.exe |
90 | 76 | ||
91 | # Weird target to catch non-portable code | 77 | # Weird targets to catch non-portable code |
92 | rust-power: | 78 | rust-cross: |
93 | name: Rust Power | 79 | name: Rust Cross |
94 | runs-on: ubuntu-latest | 80 | runs-on: ubuntu-latest |
95 | 81 | ||
82 | env: | ||
83 | targets: "powerpc-unknown-linux-gnu x86_64-unknown-linux-musl" | ||
84 | |||
96 | steps: | 85 | steps: |
97 | - name: Checkout repository | 86 | - name: Checkout repository |
98 | uses: actions/checkout@v2 | 87 | uses: actions/checkout@v2 |
@@ -103,7 +92,9 @@ jobs: | |||
103 | toolchain: stable | 92 | toolchain: stable |
104 | profile: minimal | 93 | profile: minimal |
105 | override: true | 94 | override: true |
106 | target: 'powerpc-unknown-linux-gnu' | 95 | |
96 | - name: Install Rust targets | ||
97 | run: rustup target add ${{ env.targets }} | ||
107 | 98 | ||
108 | - name: Cache cargo directories | 99 | - name: Cache cargo directories |
109 | uses: actions/cache@v2 | 100 | uses: actions/cache@v2 |
@@ -114,7 +105,10 @@ jobs: | |||
114 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | 105 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} |
115 | 106 | ||
116 | - name: Check | 107 | - name: Check |
117 | run: cargo check --target=powerpc-unknown-linux-gnu --all-targets | 108 | run: | |
109 | for target in ${{ env.targets }}; do | ||
110 | cargo check --target=$target --all-targets | ||
111 | done | ||
118 | 112 | ||
119 | typescript: | 113 | typescript: |
120 | name: TypeScript | 114 | name: TypeScript |
diff --git a/Cargo.lock b/Cargo.lock index 451928c27..265889162 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -125,9 +125,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" | |||
125 | 125 | ||
126 | [[package]] | 126 | [[package]] |
127 | name = "chalk-derive" | 127 | name = "chalk-derive" |
128 | version = "0.19.0" | 128 | version = "0.21.0" |
129 | source = "registry+https://github.com/rust-lang/crates.io-index" | 129 | source = "registry+https://github.com/rust-lang/crates.io-index" |
130 | checksum = "654c611946ba2629c5028cb7708687af975faf2c29d731824cb294c873df4697" | 130 | checksum = "c1df0dbb57d74b4acd20f20fa66ab2acd09776b79eaeb9d8f947b2f3e01c40bf" |
131 | dependencies = [ | 131 | dependencies = [ |
132 | "proc-macro2", | 132 | "proc-macro2", |
133 | "quote", | 133 | "quote", |
@@ -137,9 +137,9 @@ dependencies = [ | |||
137 | 137 | ||
138 | [[package]] | 138 | [[package]] |
139 | name = "chalk-ir" | 139 | name = "chalk-ir" |
140 | version = "0.19.0" | 140 | version = "0.21.0" |
141 | source = "registry+https://github.com/rust-lang/crates.io-index" | 141 | source = "registry+https://github.com/rust-lang/crates.io-index" |
142 | checksum = "0a5341fbc654ca886b73b804a36aebf0e621057ccc1a68e9815b5b39b3ac9ae8" | 142 | checksum = "44361a25dbdb1dc428f56ad7a3c21ba9ca12f3225c26a47919ff6fcb10a583d4" |
143 | dependencies = [ | 143 | dependencies = [ |
144 | "chalk-derive", | 144 | "chalk-derive", |
145 | "lazy_static", | 145 | "lazy_static", |
@@ -147,9 +147,9 @@ dependencies = [ | |||
147 | 147 | ||
148 | [[package]] | 148 | [[package]] |
149 | name = "chalk-recursive" | 149 | name = "chalk-recursive" |
150 | version = "0.19.0" | 150 | version = "0.21.0" |
151 | source = "registry+https://github.com/rust-lang/crates.io-index" | 151 | source = "registry+https://github.com/rust-lang/crates.io-index" |
152 | checksum = "4484807b155b5a411e6135d330295f9ba5042e2920b8712c6574ca6ea91e9ee5" | 152 | checksum = "dd89556b98de156d5eaf21077d297cd2198628f10f2df140798ea3a5dd84bc86" |
153 | dependencies = [ | 153 | dependencies = [ |
154 | "chalk-derive", | 154 | "chalk-derive", |
155 | "chalk-ir", | 155 | "chalk-ir", |
@@ -160,9 +160,9 @@ dependencies = [ | |||
160 | 160 | ||
161 | [[package]] | 161 | [[package]] |
162 | name = "chalk-solve" | 162 | name = "chalk-solve" |
163 | version = "0.19.0" | 163 | version = "0.21.0" |
164 | source = "registry+https://github.com/rust-lang/crates.io-index" | 164 | source = "registry+https://github.com/rust-lang/crates.io-index" |
165 | checksum = "281f82facd2538997fbe52132b1941ed213d266748215c31d15f62a8664429ad" | 165 | checksum = "a886da37a0dc457057d86f78f026f7a09c6d8088aa13f4f4127fdb8dc80119a3" |
166 | dependencies = [ | 166 | dependencies = [ |
167 | "chalk-derive", | 167 | "chalk-derive", |
168 | "chalk-ir", | 168 | "chalk-ir", |
@@ -418,9 +418,9 @@ dependencies = [ | |||
418 | 418 | ||
419 | [[package]] | 419 | [[package]] |
420 | name = "hashbrown" | 420 | name = "hashbrown" |
421 | version = "0.8.1" | 421 | version = "0.8.2" |
422 | source = "registry+https://github.com/rust-lang/crates.io-index" | 422 | source = "registry+https://github.com/rust-lang/crates.io-index" |
423 | checksum = "34f595585f103464d8d2f6e9864682d74c1601fed5e07d62b1c9058dba8246fb" | 423 | checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" |
424 | dependencies = [ | 424 | dependencies = [ |
425 | "autocfg", | 425 | "autocfg", |
426 | ] | 426 | ] |
@@ -465,9 +465,9 @@ dependencies = [ | |||
465 | 465 | ||
466 | [[package]] | 466 | [[package]] |
467 | name = "indexmap" | 467 | name = "indexmap" |
468 | version = "1.5.0" | 468 | version = "1.5.1" |
469 | source = "registry+https://github.com/rust-lang/crates.io-index" | 469 | source = "registry+https://github.com/rust-lang/crates.io-index" |
470 | checksum = "5b88cd59ee5f71fea89a62248fc8f387d44400cefe05ef548466d61ced9029a7" | 470 | checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" |
471 | dependencies = [ | 471 | dependencies = [ |
472 | "autocfg", | 472 | "autocfg", |
473 | "hashbrown", | 473 | "hashbrown", |
@@ -852,9 +852,9 @@ dependencies = [ | |||
852 | 852 | ||
853 | [[package]] | 853 | [[package]] |
854 | name = "perf-event-open-sys" | 854 | name = "perf-event-open-sys" |
855 | version = "0.3.1" | 855 | version = "0.3.2" |
856 | source = "registry+https://github.com/rust-lang/crates.io-index" | 856 | source = "registry+https://github.com/rust-lang/crates.io-index" |
857 | checksum = "95db63e37862bc1b842135d2234ef9418f222cc660c6752f45e7cf9ddfb97f96" | 857 | checksum = "83e7183862f36d10263d0a1ccaef50fef734ade948bf026afd1bd97355c78273" |
858 | dependencies = [ | 858 | dependencies = [ |
859 | "libc", | 859 | "libc", |
860 | ] | 860 | ] |
@@ -871,9 +871,9 @@ dependencies = [ | |||
871 | 871 | ||
872 | [[package]] | 872 | [[package]] |
873 | name = "pico-args" | 873 | name = "pico-args" |
874 | version = "0.3.3" | 874 | version = "0.3.4" |
875 | source = "registry+https://github.com/rust-lang/crates.io-index" | 875 | source = "registry+https://github.com/rust-lang/crates.io-index" |
876 | checksum = "1b1eee8b1f4966c8343d7ca0f5a8452cd35d5610a2e0efbe2a68cae44bef2046" | 876 | checksum = "28b9b4df73455c861d7cbf8be42f01d3b373ed7f02e378d55fa84eafc6f638b1" |
877 | 877 | ||
878 | [[package]] | 878 | [[package]] |
879 | name = "plain" | 879 | name = "plain" |
@@ -1694,9 +1694,9 @@ dependencies = [ | |||
1694 | 1694 | ||
1695 | [[package]] | 1695 | [[package]] |
1696 | name = "tracing-tree" | 1696 | name = "tracing-tree" |
1697 | version = "0.1.4" | 1697 | version = "0.1.5" |
1698 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1698 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1699 | checksum = "37ee7f0f53ed2093971a698db799ef56a2dfd89b32e3aeb5165f0e637a02be04" | 1699 | checksum = "e1a3dc4774db3a6b2d66a4f8d8de670e874ec3ed55615860c994927419b32c5f" |
1700 | dependencies = [ | 1700 | dependencies = [ |
1701 | "ansi_term", | 1701 | "ansi_term", |
1702 | "atty", | 1702 | "atty", |
diff --git a/crates/expect/src/lib.rs b/crates/expect/src/lib.rs index 21a458d47..bd83895f7 100644 --- a/crates/expect/src/lib.rs +++ b/crates/expect/src/lib.rs | |||
@@ -74,7 +74,7 @@ impl fmt::Display for Position { | |||
74 | impl Expect { | 74 | impl Expect { |
75 | pub fn assert_eq(&self, actual: &str) { | 75 | pub fn assert_eq(&self, actual: &str) { |
76 | let trimmed = self.trimmed(); | 76 | let trimmed = self.trimmed(); |
77 | if &trimmed == actual { | 77 | if trimmed == actual { |
78 | return; | 78 | return; |
79 | } | 79 | } |
80 | Runtime::fail_expect(self, &trimmed, actual); | 80 | Runtime::fail_expect(self, &trimmed, actual); |
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs index 7c38f5ef9..31e14246d 100644 --- a/crates/flycheck/src/lib.rs +++ b/crates/flycheck/src/lib.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | //! cargo_check provides the functionality needed to run `cargo check` or | 1 | //! Flycheck provides the functionality needed to run `cargo check` or |
2 | //! another compatible command (f.x. clippy) in a background thread and provide | 2 | //! another compatible command (f.x. clippy) in a background thread and provide |
3 | //! LSP diagnostics based on the output of the command. | 3 | //! LSP diagnostics based on the output of the command. |
4 | 4 | ||
@@ -147,6 +147,12 @@ impl FlycheckActor { | |||
147 | // avoid busy-waiting. | 147 | // avoid busy-waiting. |
148 | let cargo_handle = self.cargo_handle.take().unwrap(); | 148 | let cargo_handle = self.cargo_handle.take().unwrap(); |
149 | let res = cargo_handle.join(); | 149 | let res = cargo_handle.join(); |
150 | if res.is_err() { | ||
151 | log::error!( | ||
152 | "Flycheck failed to run the following command: {:?}", | ||
153 | self.check_command() | ||
154 | ) | ||
155 | } | ||
150 | self.send(Message::Progress(Progress::DidFinish(res))); | 156 | self.send(Message::Progress(Progress::DidFinish(res))); |
151 | } | 157 | } |
152 | Event::CheckEvent(Some(message)) => match message { | 158 | Event::CheckEvent(Some(message)) => match message { |
@@ -253,7 +259,7 @@ impl CargoHandle { | |||
253 | return Err(io::Error::new( | 259 | return Err(io::Error::new( |
254 | io::ErrorKind::Other, | 260 | io::ErrorKind::Other, |
255 | format!( | 261 | format!( |
256 | "Cargo watcher failed,the command produced no valid metadata (exit code: {:?})", | 262 | "Cargo watcher failed, the command produced no valid metadata (exit code: {:?})", |
257 | exit_status | 263 | exit_status |
258 | ), | 264 | ), |
259 | )); | 265 | )); |
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 15ec75c95..07c978378 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -51,7 +51,7 @@ impl<'a> SubstituteTypeParams<'a> { | |||
51 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky | 51 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky |
52 | .skip(1) | 52 | .skip(1) |
53 | // The actual list of trait type parameters may be longer than the one | 53 | // The actual list of trait type parameters may be longer than the one |
54 | // used in the `impl` block due to trailing default type parametrs. | 54 | // used in the `impl` block due to trailing default type parameters. |
55 | // For that case we extend the `substs` with an empty iterator so we | 55 | // For that case we extend the `substs` with an empty iterator so we |
56 | // can still hit those trailing values and check if they actually have | 56 | // can still hit those trailing values and check if they actually have |
57 | // a default type. If they do, go for that type from `hir` to `ast` so | 57 | // a default type. If they do, go for that type from `hir` to `ast` so |
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index b67438b6b..ebdf00e67 100644 --- a/crates/ra_assists/src/handlers/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs | |||
@@ -1,10 +1,10 @@ | |||
1 | use itertools::Itertools; | ||
1 | use ra_syntax::{ | 2 | use ra_syntax::{ |
2 | ast::{self, AstNode}, | 3 | ast::{self, AstNode}, |
3 | Direction, SmolStr, | 4 | Direction, SmolStr, |
4 | SyntaxKind::{IDENT, WHITESPACE}, | 5 | SyntaxKind::{IDENT, WHITESPACE}, |
5 | TextRange, TextSize, | 6 | TextRange, TextSize, |
6 | }; | 7 | }; |
7 | use stdx::SepBy; | ||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | assist_context::{AssistContext, Assists}, | 10 | assist_context::{AssistContext, Assists}, |
@@ -61,9 +61,9 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
61 | .filter(|t| t != trait_token.text()) | 61 | .filter(|t| t != trait_token.text()) |
62 | .collect::<Vec<SmolStr>>(); | 62 | .collect::<Vec<SmolStr>>(); |
63 | let has_more_derives = !new_attr_input.is_empty(); | 63 | let has_more_derives = !new_attr_input.is_empty(); |
64 | let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string(); | ||
65 | 64 | ||
66 | if has_more_derives { | 65 | if has_more_derives { |
66 | let new_attr_input = format!("({})", new_attr_input.iter().format(", ")); | ||
67 | builder.replace(input.syntax().text_range(), new_attr_input); | 67 | builder.replace(input.syntax().text_range(), new_attr_input); |
68 | } else { | 68 | } else { |
69 | let attr_range = attr.syntax().text_range(); | 69 | let attr_range = attr.syntax().text_range(); |
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs index 0c565e89a..537322a72 100644 --- a/crates/ra_assists/src/handlers/add_turbo_fish.rs +++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs | |||
@@ -41,7 +41,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
41 | let name_ref = ast::NameRef::cast(ident.parent())?; | 41 | let name_ref = ast::NameRef::cast(ident.parent())?; |
42 | let def = match classify_name_ref(&ctx.sema, &name_ref)? { | 42 | let def = match classify_name_ref(&ctx.sema, &name_ref)? { |
43 | NameRefClass::Definition(def) => def, | 43 | NameRefClass::Definition(def) => def, |
44 | NameRefClass::FieldShorthand { .. } => return None, | 44 | NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None, |
45 | }; | 45 | }; |
46 | let fun = match def { | 46 | let fun = match def { |
47 | Definition::ModuleDef(hir::ModuleDef::Function(it)) => it, | 47 | Definition::ModuleDef(hir::ModuleDef::Function(it)) => it, |
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs index de701f8b8..3ac4aed7d 100644 --- a/crates/ra_assists/src/handlers/apply_demorgan.rs +++ b/crates/ra_assists/src/handlers/apply_demorgan.rs | |||
@@ -4,7 +4,7 @@ use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKin | |||
4 | 4 | ||
5 | // Assist: apply_demorgan | 5 | // Assist: apply_demorgan |
6 | // | 6 | // |
7 | // Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). | 7 | // Apply https://en.wikipedia.org/wiki/De_Morgan%27s_laws[De Morgan's law]. |
8 | // This transforms expressions of the form `!l || !r` into `!(l && r)`. | 8 | // This transforms expressions of the form `!l || !r` into `!(l && r)`. |
9 | // This also works with `&&`. This assist can only be applied with the cursor | 9 | // This also works with `&&`. This assist can only be applied with the cursor |
10 | // on either `||` or `&&`, with both operands being a negation of some kind. | 10 | // on either `||` or `&&`, with both operands being a negation of some kind. |
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs index 1aefa79cc..a19dbf33f 100644 --- a/crates/ra_assists/src/handlers/fix_visibility.rs +++ b/crates/ra_assists/src/handlers/fix_visibility.rs | |||
@@ -121,7 +121,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> | |||
121 | Some(cap) => match current_visibility { | 121 | Some(cap) => match current_visibility { |
122 | Some(current_visibility) => builder.replace_snippet( | 122 | Some(current_visibility) => builder.replace_snippet( |
123 | cap, | 123 | cap, |
124 | dbg!(current_visibility.syntax()).text_range(), | 124 | current_visibility.syntax().text_range(), |
125 | format!("$0{}", missing_visibility), | 125 | format!("$0{}", missing_visibility), |
126 | ), | 126 | ), |
127 | None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), | 127 | None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)), |
diff --git a/crates/ra_assists/src/handlers/generate_impl.rs b/crates/ra_assists/src/handlers/generate_impl.rs index d9b87c9c0..7162dc184 100644 --- a/crates/ra_assists/src/handlers/generate_impl.rs +++ b/crates/ra_assists/src/handlers/generate_impl.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | use itertools::Itertools; | ||
1 | use ra_syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner}; | 2 | use ra_syntax::ast::{self, AstNode, GenericParamsOwner, NameOwner}; |
2 | use stdx::{format_to, SepBy}; | 3 | use stdx::format_to; |
3 | 4 | ||
4 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 5 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
5 | 6 | ||
@@ -50,7 +51,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
50 | .filter_map(|it| it.name()) | 51 | .filter_map(|it| it.name()) |
51 | .map(|it| it.text().clone()); | 52 | .map(|it| it.text().clone()); |
52 | 53 | ||
53 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); | 54 | let generic_params = lifetime_params.chain(type_params).format(", "); |
54 | format_to!(buf, "<{}>", generic_params) | 55 | format_to!(buf, "<{}>", generic_params) |
55 | } | 56 | } |
56 | match ctx.config.snippet_cap { | 57 | match ctx.config.snippet_cap { |
diff --git a/crates/ra_assists/src/handlers/generate_new.rs b/crates/ra_assists/src/handlers/generate_new.rs index b84aa24b6..32dfed274 100644 --- a/crates/ra_assists/src/handlers/generate_new.rs +++ b/crates/ra_assists/src/handlers/generate_new.rs | |||
@@ -1,9 +1,10 @@ | |||
1 | use hir::Adt; | 1 | use hir::Adt; |
2 | use itertools::Itertools; | ||
2 | use ra_syntax::{ | 3 | use ra_syntax::{ |
3 | ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, | 4 | ast::{self, AstNode, GenericParamsOwner, NameOwner, StructKind, VisibilityOwner}, |
4 | T, | 5 | T, |
5 | }; | 6 | }; |
6 | use stdx::{format_to, SepBy}; | 7 | use stdx::format_to; |
7 | 8 | ||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 9 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
9 | 10 | ||
@@ -52,8 +53,8 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
52 | let params = field_list | 53 | let params = field_list |
53 | .fields() | 54 | .fields() |
54 | .filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))) | 55 | .filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))) |
55 | .sep_by(", "); | 56 | .format(", "); |
56 | let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); | 57 | let fields = field_list.fields().filter_map(|f| f.name()).format(", "); |
57 | 58 | ||
58 | format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); | 59 | format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); |
59 | 60 | ||
@@ -102,7 +103,7 @@ fn generate_impl_text(strukt: &ast::Struct, code: &str) -> String { | |||
102 | .map(|it| it.text().clone()); | 103 | .map(|it| it.text().clone()); |
103 | let type_params = | 104 | let type_params = |
104 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 105 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); |
105 | format_to!(buf, "<{}>", lifetime_params.chain(type_params).sep_by(", ")) | 106 | format_to!(buf, "<{}>", lifetime_params.chain(type_params).format(", ")) |
106 | } | 107 | } |
107 | 108 | ||
108 | format_to!(buf, " {{\n{}\n}}\n", code); | 109 | format_to!(buf, " {{\n{}\n}}\n", code); |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 507646cc8..890996a68 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -66,13 +66,13 @@ pub struct GroupLabel(pub String); | |||
66 | 66 | ||
67 | #[derive(Debug, Clone)] | 67 | #[derive(Debug, Clone)] |
68 | pub struct Assist { | 68 | pub struct Assist { |
69 | pub id: AssistId, | 69 | 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 | pub label: String, | 71 | label: String, |
72 | pub group: Option<GroupLabel>, | 72 | 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. |
75 | pub target: TextRange, | 75 | target: TextRange, |
76 | } | 76 | } |
77 | 77 | ||
78 | #[derive(Debug, Clone)] | 78 | #[derive(Debug, Clone)] |
@@ -120,10 +120,25 @@ impl Assist { | |||
120 | group: Option<GroupLabel>, | 120 | group: Option<GroupLabel>, |
121 | target: TextRange, | 121 | target: TextRange, |
122 | ) -> Assist { | 122 | ) -> Assist { |
123 | // FIXME: make fields private, so that this invariant can't be broken | ||
124 | assert!(label.starts_with(|c: char| c.is_uppercase())); | 123 | assert!(label.starts_with(|c: char| c.is_uppercase())); |
125 | Assist { id, label, group, target } | 124 | Assist { id, label, group, target } |
126 | } | 125 | } |
126 | |||
127 | pub fn id(&self) -> AssistId { | ||
128 | self.id | ||
129 | } | ||
130 | |||
131 | pub fn label(&self) -> String { | ||
132 | self.label.clone() | ||
133 | } | ||
134 | |||
135 | pub fn group(&self) -> Option<GroupLabel> { | ||
136 | self.group.clone() | ||
137 | } | ||
138 | |||
139 | pub fn target(&self) -> TextRange { | ||
140 | self.target | ||
141 | } | ||
127 | } | 142 | } |
128 | 143 | ||
129 | mod handlers { | 144 | mod handlers { |
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 18fcb9049..e73836422 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs | |||
@@ -20,7 +20,7 @@ pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_ | |||
20 | 20 | ||
21 | // FIXME: instead of having a separate function here, maybe use | 21 | // FIXME: instead of having a separate function here, maybe use |
22 | // `extract_ranges` and mark the target as `<target> </target>` in the | 22 | // `extract_ranges` and mark the target as `<target> </target>` in the |
23 | // fixuture? | 23 | // fixture? |
24 | pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) { | 24 | pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) { |
25 | check(assist, ra_fixture, ExpectedResult::Target(target)); | 25 | check(assist, ra_fixture, ExpectedResult::Target(target)); |
26 | } | 26 | } |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 54d5678d1..0de6fdf3f 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -257,7 +257,7 @@ pub use prelude::*; | |||
257 | .find(|dep| &dep.name.to_string() == std_crate)? | 257 | .find(|dep| &dep.name.to_string() == std_crate)? |
258 | .krate; | 258 | .krate; |
259 | 259 | ||
260 | let mut module = std_crate.root_module(db)?; | 260 | let mut module = std_crate.root_module(db); |
261 | for segment in path { | 261 | for segment in path { |
262 | module = module.children(db).find_map(|child| { | 262 | module = module.children(db).find_map(|child| { |
263 | let name = child.name(db)?; | 263 | let name = child.name(db)?; |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 27cdabea0..0007d7fa8 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -4,6 +4,7 @@ use std::{iter, sync::Arc}; | |||
4 | use arrayvec::ArrayVec; | 4 | use arrayvec::ArrayVec; |
5 | use either::Either; | 5 | use either::Either; |
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | adt::ReprKind, | ||
7 | adt::StructKind, | 8 | adt::StructKind, |
8 | adt::VariantData, | 9 | adt::VariantData, |
9 | builtin_type::BuiltinType, | 10 | builtin_type::BuiltinType, |
@@ -83,9 +84,9 @@ impl Crate { | |||
83 | .collect() | 84 | .collect() |
84 | } | 85 | } |
85 | 86 | ||
86 | pub fn root_module(self, db: &dyn HirDatabase) -> Option<Module> { | 87 | pub fn root_module(self, db: &dyn HirDatabase) -> Module { |
87 | let module_id = db.crate_def_map(self.id).root; | 88 | let module_id = db.crate_def_map(self.id).root; |
88 | Some(Module::new(self, module_id)) | 89 | Module::new(self, module_id) |
89 | } | 90 | } |
90 | 91 | ||
91 | pub fn root_file(self, db: &dyn HirDatabase) -> FileId { | 92 | pub fn root_file(self, db: &dyn HirDatabase) -> FileId { |
@@ -431,6 +432,10 @@ impl Struct { | |||
431 | Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) | 432 | Type::from_def(db, self.id.lookup(db.upcast()).container.module(db.upcast()).krate, self.id) |
432 | } | 433 | } |
433 | 434 | ||
435 | pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprKind> { | ||
436 | db.struct_data(self.id).repr.clone() | ||
437 | } | ||
438 | |||
434 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | 439 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { |
435 | db.struct_data(self.id).variant_data.clone() | 440 | db.struct_data(self.id).variant_data.clone() |
436 | } | 441 | } |
@@ -1253,6 +1258,19 @@ impl Type { | |||
1253 | ) | 1258 | ) |
1254 | } | 1259 | } |
1255 | 1260 | ||
1261 | pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { | ||
1262 | let adt_id = match self.ty.value { | ||
1263 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_id), .. }) => adt_id, | ||
1264 | _ => return false, | ||
1265 | }; | ||
1266 | |||
1267 | let adt = adt_id.into(); | ||
1268 | match adt { | ||
1269 | Adt::Struct(s) => matches!(s.repr(db), Some(ReprKind::Packed)), | ||
1270 | _ => false, | ||
1271 | } | ||
1272 | } | ||
1273 | |||
1256 | pub fn is_raw_ptr(&self) -> bool { | 1274 | pub fn is_raw_ptr(&self) -> bool { |
1257 | matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) | 1275 | matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) |
1258 | } | 1276 | } |
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 266b513dc..363164b9b 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | pub use hir_def::diagnostics::UnresolvedModule; | 2 | pub use hir_def::diagnostics::UnresolvedModule; |
3 | pub use hir_expand::diagnostics::{ | 3 | pub use hir_expand::diagnostics::{Diagnostic, DiagnosticSink, DiagnosticSinkBuilder}; |
4 | AstDiagnostic, Diagnostic, DiagnosticSink, DiagnosticSinkBuilder, | ||
5 | }; | ||
6 | pub use hir_ty::diagnostics::{ | 4 | pub use hir_ty::diagnostics::{ |
7 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, | 5 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, NoSuchField, |
8 | }; | 6 | }; |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 31f3241c9..34b02c536 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -49,7 +49,7 @@ pub use hir_def::{ | |||
49 | docs::Documentation, | 49 | docs::Documentation, |
50 | nameres::ModuleSource, | 50 | nameres::ModuleSource, |
51 | path::{ModPath, Path, PathKind}, | 51 | path::{ModPath, Path, PathKind}, |
52 | type_ref::Mutability, | 52 | type_ref::{Mutability, TypeRef}, |
53 | }; | 53 | }; |
54 | pub use hir_expand::{ | 54 | pub use hir_expand::{ |
55 | hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, | 55 | hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 307b336f2..36b688ccb 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -8,7 +8,7 @@ use hir_def::{ | |||
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | AsMacroCall, FunctionId, TraitId, VariantId, | 9 | AsMacroCall, FunctionId, TraitId, VariantId, |
10 | }; | 10 | }; |
11 | use hir_expand::{diagnostics::AstDiagnostic, hygiene::Hygiene, ExpansionInfo}; | 11 | use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | 12 | use hir_ty::associated_type_shorthand_candidates; |
13 | use itertools::Itertools; | 13 | use itertools::Itertools; |
14 | use ra_db::{FileId, FileRange}; | 14 | use ra_db::{FileId, FileRange}; |
@@ -24,8 +24,9 @@ use crate::{ | |||
24 | diagnostics::Diagnostic, | 24 | diagnostics::Diagnostic, |
25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, | 26 | source_analyzer::{resolve_hir_path, resolve_hir_path_qualifier, SourceAnalyzer}, |
27 | AssocItem, Callable, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, | 27 | AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, |
28 | ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, | 28 | Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, TypeRef, |
29 | VariantDef, | ||
29 | }; | 30 | }; |
30 | use resolver::TypeNs; | 31 | use resolver::TypeNs; |
31 | 32 | ||
@@ -109,13 +110,6 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
109 | self.imp.parse(file_id) | 110 | self.imp.parse(file_id) |
110 | } | 111 | } |
111 | 112 | ||
112 | pub fn ast<T: AstDiagnostic + Diagnostic>(&self, d: &T) -> <T as AstDiagnostic>::AST { | ||
113 | let file_id = d.source().file_id; | ||
114 | let root = self.db.parse_or_expand(file_id).unwrap(); | ||
115 | self.imp.cache(root, file_id); | ||
116 | d.ast(self.db.upcast()) | ||
117 | } | ||
118 | |||
119 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 113 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
120 | self.imp.expand(macro_call) | 114 | self.imp.expand(macro_call) |
121 | } | 115 | } |
@@ -145,8 +139,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
145 | self.imp.original_range(node) | 139 | self.imp.original_range(node) |
146 | } | 140 | } |
147 | 141 | ||
148 | pub fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | 142 | pub fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { |
149 | self.imp.diagnostics_range(diagnostics) | 143 | self.imp.diagnostics_display_range(diagnostics) |
150 | } | 144 | } |
151 | 145 | ||
152 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | 146 | pub fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { |
@@ -228,6 +222,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
228 | self.imp.resolve_path(path) | 222 | self.imp.resolve_path(path) |
229 | } | 223 | } |
230 | 224 | ||
225 | pub fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> { | ||
226 | self.imp.resolve_extern_crate(extern_crate) | ||
227 | } | ||
228 | |||
231 | pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> { | 229 | pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> { |
232 | self.imp.resolve_variant(record_lit).map(VariantDef::from) | 230 | self.imp.resolve_variant(record_lit).map(VariantDef::from) |
233 | } | 231 | } |
@@ -275,6 +273,18 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
275 | pub fn assert_contains_node(&self, node: &SyntaxNode) { | 273 | pub fn assert_contains_node(&self, node: &SyntaxNode) { |
276 | self.imp.assert_contains_node(node) | 274 | self.imp.assert_contains_node(node) |
277 | } | 275 | } |
276 | |||
277 | pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool { | ||
278 | self.imp.is_unsafe_method_call(method_call_expr) | ||
279 | } | ||
280 | |||
281 | pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool { | ||
282 | self.imp.is_unsafe_ref_expr(ref_expr) | ||
283 | } | ||
284 | |||
285 | pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool { | ||
286 | self.imp.is_unsafe_ident_pat(ident_pat) | ||
287 | } | ||
278 | } | 288 | } |
279 | 289 | ||
280 | impl<'db> SemanticsImpl<'db> { | 290 | impl<'db> SemanticsImpl<'db> { |
@@ -372,10 +382,11 @@ impl<'db> SemanticsImpl<'db> { | |||
372 | original_range(self.db, node.as_ref()) | 382 | original_range(self.db, node.as_ref()) |
373 | } | 383 | } |
374 | 384 | ||
375 | fn diagnostics_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | 385 | fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { |
376 | let src = diagnostics.source(); | 386 | let src = diagnostics.display_source(); |
377 | let root = self.db.parse_or_expand(src.file_id).unwrap(); | 387 | let root = self.db.parse_or_expand(src.file_id).unwrap(); |
378 | let node = src.value.to_node(&root); | 388 | let node = src.value.to_node(&root); |
389 | self.cache(root, src.file_id); | ||
379 | original_range(self.db, src.with_value(&node)) | 390 | original_range(self.db, src.with_value(&node)) |
380 | } | 391 | } |
381 | 392 | ||
@@ -443,6 +454,17 @@ impl<'db> SemanticsImpl<'db> { | |||
443 | self.analyze(path.syntax()).resolve_path(self.db, path) | 454 | self.analyze(path.syntax()).resolve_path(self.db, path) |
444 | } | 455 | } |
445 | 456 | ||
457 | fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> { | ||
458 | let krate = self.scope(extern_crate.syntax()).krate()?; | ||
459 | krate.dependencies(self.db).into_iter().find_map(|dep| { | ||
460 | if dep.name == extern_crate.name_ref()?.as_name() { | ||
461 | Some(dep.krate) | ||
462 | } else { | ||
463 | None | ||
464 | } | ||
465 | }) | ||
466 | } | ||
467 | |||
446 | fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { | 468 | fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> { |
447 | self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) | 469 | self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit) |
448 | } | 470 | } |
@@ -559,6 +581,90 @@ impl<'db> SemanticsImpl<'db> { | |||
559 | }); | 581 | }); |
560 | InFile::new(file_id, node) | 582 | InFile::new(file_id, node) |
561 | } | 583 | } |
584 | |||
585 | pub fn is_unsafe_method_call(&self, method_call_expr: ast::MethodCallExpr) -> bool { | ||
586 | method_call_expr | ||
587 | .expr() | ||
588 | .and_then(|expr| { | ||
589 | let field_expr = if let ast::Expr::FieldExpr(field_expr) = expr { | ||
590 | field_expr | ||
591 | } else { | ||
592 | return None; | ||
593 | }; | ||
594 | let ty = self.type_of_expr(&field_expr.expr()?)?; | ||
595 | if !ty.is_packed(self.db) { | ||
596 | return None; | ||
597 | } | ||
598 | |||
599 | let func = self.resolve_method_call(&method_call_expr).map(Function::from)?; | ||
600 | let is_unsafe = func.has_self_param(self.db) | ||
601 | && matches!(func.params(self.db).first(), Some(TypeRef::Reference(..))); | ||
602 | Some(is_unsafe) | ||
603 | }) | ||
604 | .unwrap_or(false) | ||
605 | } | ||
606 | |||
607 | pub fn is_unsafe_ref_expr(&self, ref_expr: &ast::RefExpr) -> bool { | ||
608 | ref_expr | ||
609 | .expr() | ||
610 | .and_then(|expr| { | ||
611 | let field_expr = match expr { | ||
612 | ast::Expr::FieldExpr(field_expr) => field_expr, | ||
613 | _ => return None, | ||
614 | }; | ||
615 | let expr = field_expr.expr()?; | ||
616 | self.type_of_expr(&expr) | ||
617 | }) | ||
618 | // Binding a reference to a packed type is possibly unsafe. | ||
619 | .map(|ty| ty.is_packed(self.db)) | ||
620 | .unwrap_or(false) | ||
621 | |||
622 | // FIXME This needs layout computation to be correct. It will highlight | ||
623 | // more than it should with the current implementation. | ||
624 | } | ||
625 | |||
626 | pub fn is_unsafe_ident_pat(&self, ident_pat: &ast::IdentPat) -> bool { | ||
627 | if !ident_pat.ref_token().is_some() { | ||
628 | return false; | ||
629 | } | ||
630 | |||
631 | ident_pat | ||
632 | .syntax() | ||
633 | .parent() | ||
634 | .and_then(|parent| { | ||
635 | // `IdentPat` can live under `RecordPat` directly under `RecordPatField` or | ||
636 | // `RecordPatFieldList`. `RecordPatField` also lives under `RecordPatFieldList`, | ||
637 | // so this tries to lookup the `IdentPat` anywhere along that structure to the | ||
638 | // `RecordPat` so we can get the containing type. | ||
639 | let record_pat = ast::RecordPatField::cast(parent.clone()) | ||
640 | .and_then(|record_pat| record_pat.syntax().parent()) | ||
641 | .or_else(|| Some(parent.clone())) | ||
642 | .and_then(|parent| { | ||
643 | ast::RecordPatFieldList::cast(parent)? | ||
644 | .syntax() | ||
645 | .parent() | ||
646 | .and_then(ast::RecordPat::cast) | ||
647 | }); | ||
648 | |||
649 | // If this doesn't match a `RecordPat`, fallback to a `LetStmt` to see if | ||
650 | // this is initialized from a `FieldExpr`. | ||
651 | if let Some(record_pat) = record_pat { | ||
652 | self.type_of_pat(&ast::Pat::RecordPat(record_pat)) | ||
653 | } else if let Some(let_stmt) = ast::LetStmt::cast(parent) { | ||
654 | let field_expr = match let_stmt.initializer()? { | ||
655 | ast::Expr::FieldExpr(field_expr) => field_expr, | ||
656 | _ => return None, | ||
657 | }; | ||
658 | |||
659 | self.type_of_expr(&field_expr.expr()?) | ||
660 | } else { | ||
661 | None | ||
662 | } | ||
663 | }) | ||
664 | // Binding a reference to a packed type is possibly unsafe. | ||
665 | .map(|ty| ty.is_packed(self.db)) | ||
666 | .unwrap_or(false) | ||
667 | } | ||
562 | } | 668 | } |
563 | 669 | ||
564 | pub trait ToDef: AstNode + Clone { | 670 | pub trait ToDef: AstNode + Clone { |
@@ -612,6 +718,10 @@ impl<'a> SemanticsScope<'a> { | |||
612 | Some(Module { id: self.resolver.module()? }) | 718 | Some(Module { id: self.resolver.module()? }) |
613 | } | 719 | } |
614 | 720 | ||
721 | pub fn krate(&self) -> Option<Crate> { | ||
722 | Some(Crate { id: self.resolver.krate()? }) | ||
723 | } | ||
724 | |||
615 | /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type | 725 | /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type |
616 | // FIXME: rename to visible_traits to not repeat scope? | 726 | // FIXME: rename to visible_traits to not repeat scope? |
617 | pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { | 727 | pub fn traits_in_scope(&self) -> FxHashSet<TraitId> { |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index d0cb62ef0..d3d62debf 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -265,8 +265,7 @@ impl SourceAnalyzer { | |||
265 | } | 265 | } |
266 | 266 | ||
267 | // This must be a normal source file rather than macro file. | 267 | // This must be a normal source file rather than macro file. |
268 | let hir_path = | 268 | let hir_path = Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; |
269 | crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; | ||
270 | 269 | ||
271 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we | 270 | // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we |
272 | // trying to resolve foo::bar. | 271 | // trying to resolve foo::bar. |
@@ -451,7 +450,7 @@ fn adjust( | |||
451 | pub(crate) fn resolve_hir_path( | 450 | pub(crate) fn resolve_hir_path( |
452 | db: &dyn HirDatabase, | 451 | db: &dyn HirDatabase, |
453 | resolver: &Resolver, | 452 | resolver: &Resolver, |
454 | path: &crate::Path, | 453 | path: &Path, |
455 | ) -> Option<PathResolution> { | 454 | ) -> Option<PathResolution> { |
456 | let types = | 455 | let types = |
457 | resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { | 456 | resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { |
@@ -512,7 +511,7 @@ pub(crate) fn resolve_hir_path( | |||
512 | pub(crate) fn resolve_hir_path_qualifier( | 511 | pub(crate) fn resolve_hir_path_qualifier( |
513 | db: &dyn HirDatabase, | 512 | db: &dyn HirDatabase, |
514 | resolver: &Resolver, | 513 | resolver: &Resolver, |
515 | path: &crate::Path, | 514 | path: &Path, |
516 | ) -> Option<PathResolution> { | 515 | ) -> Option<PathResolution> { |
517 | let items = resolver | 516 | let items = resolver |
518 | .resolve_module_path_in_items(db.upcast(), path.mod_path()) | 517 | .resolve_module_path_in_items(db.upcast(), path.mod_path()) |
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 6cb56a1cd..35c3a9140 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -9,11 +9,12 @@ use hir_expand::{ | |||
9 | }; | 9 | }; |
10 | use ra_arena::{map::ArenaMap, Arena}; | 10 | use ra_arena::{map::ArenaMap, Arena}; |
11 | use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; | 11 | use ra_syntax::ast::{self, NameOwner, VisibilityOwner}; |
12 | use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree}; | ||
12 | 13 | ||
13 | use crate::{ | 14 | use crate::{ |
14 | body::{CfgExpander, LowerCtx}, | 15 | body::{CfgExpander, LowerCtx}, |
15 | db::DefDatabase, | 16 | db::DefDatabase, |
16 | item_tree::{Field, Fields, ItemTree}, | 17 | item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem}, |
17 | src::HasChildSource, | 18 | src::HasChildSource, |
18 | src::HasSource, | 19 | src::HasSource, |
19 | trace::Trace, | 20 | trace::Trace, |
@@ -29,6 +30,7 @@ use ra_cfg::CfgOptions; | |||
29 | pub struct StructData { | 30 | pub struct StructData { |
30 | pub name: Name, | 31 | pub name: Name, |
31 | pub variant_data: Arc<VariantData>, | 32 | pub variant_data: Arc<VariantData>, |
33 | pub repr: Option<ReprKind>, | ||
32 | } | 34 | } |
33 | 35 | ||
34 | #[derive(Debug, Clone, PartialEq, Eq)] | 36 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -58,26 +60,58 @@ pub struct FieldData { | |||
58 | pub visibility: RawVisibility, | 60 | pub visibility: RawVisibility, |
59 | } | 61 | } |
60 | 62 | ||
63 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
64 | pub enum ReprKind { | ||
65 | Packed, | ||
66 | Other, | ||
67 | } | ||
68 | |||
69 | fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option<ReprKind> { | ||
70 | item_tree.attrs(of).by_key("repr").tt_values().find_map(parse_repr_tt) | ||
71 | } | ||
72 | |||
73 | fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> { | ||
74 | match tt.delimiter { | ||
75 | Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {} | ||
76 | _ => return None, | ||
77 | } | ||
78 | |||
79 | let mut it = tt.token_trees.iter(); | ||
80 | match it.next()? { | ||
81 | TokenTree::Leaf(Leaf::Ident(ident)) if ident.text == "packed" => Some(ReprKind::Packed), | ||
82 | _ => Some(ReprKind::Other), | ||
83 | } | ||
84 | } | ||
85 | |||
61 | impl StructData { | 86 | impl StructData { |
62 | pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { | 87 | pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { |
63 | let loc = id.lookup(db); | 88 | let loc = id.lookup(db); |
64 | let item_tree = db.item_tree(loc.id.file_id); | 89 | let item_tree = db.item_tree(loc.id.file_id); |
90 | let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into()); | ||
65 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | 91 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); |
66 | 92 | ||
67 | let strukt = &item_tree[loc.id.value]; | 93 | let strukt = &item_tree[loc.id.value]; |
68 | let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); | 94 | let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields); |
69 | 95 | Arc::new(StructData { | |
70 | Arc::new(StructData { name: strukt.name.clone(), variant_data: Arc::new(variant_data) }) | 96 | name: strukt.name.clone(), |
97 | variant_data: Arc::new(variant_data), | ||
98 | repr, | ||
99 | }) | ||
71 | } | 100 | } |
72 | pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { | 101 | pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { |
73 | let loc = id.lookup(db); | 102 | let loc = id.lookup(db); |
74 | let item_tree = db.item_tree(loc.id.file_id); | 103 | let item_tree = db.item_tree(loc.id.file_id); |
104 | let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into()); | ||
75 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); | 105 | let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); |
76 | 106 | ||
77 | let union = &item_tree[loc.id.value]; | 107 | let union = &item_tree[loc.id.value]; |
78 | let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); | 108 | let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields); |
79 | 109 | ||
80 | Arc::new(StructData { name: union.name.clone(), variant_data: Arc::new(variant_data) }) | 110 | Arc::new(StructData { |
111 | name: union.name.clone(), | ||
112 | variant_data: Arc::new(variant_data), | ||
113 | repr, | ||
114 | }) | ||
81 | } | 115 | } |
82 | } | 116 | } |
83 | 117 | ||
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index 481b13a87..5b7f05bf4 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ impl Diagnostic for UnresolvedModule { | |||
21 | fn message(&self) -> String { | 21 | fn message(&self) -> String { |
22 | "unresolved module".to_string() | 22 | "unresolved module".to_string() |
23 | } | 23 | } |
24 | fn source(&self) -> InFile<SyntaxNodePtr> { | 24 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
25 | InFile::new(self.file, self.decl.clone().into()) | 25 | InFile::new(self.file, self.decl.clone().into()) |
26 | } | 26 | } |
27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs index 507132a13..a618934c9 100644 --- a/crates/ra_hir_expand/src/diagnostics.rs +++ b/crates/ra_hir_expand/src/diagnostics.rs | |||
@@ -16,36 +16,21 @@ | |||
16 | 16 | ||
17 | use std::{any::Any, fmt}; | 17 | use std::{any::Any, fmt}; |
18 | 18 | ||
19 | use ra_syntax::{SyntaxNode, SyntaxNodePtr}; | 19 | use ra_syntax::SyntaxNodePtr; |
20 | 20 | ||
21 | use crate::{db::AstDatabase, InFile}; | 21 | use crate::InFile; |
22 | 22 | ||
23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | 23 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { |
24 | fn name(&self) -> &'static str; | 24 | fn name(&self) -> &'static str; |
25 | fn message(&self) -> String; | 25 | fn message(&self) -> String; |
26 | fn source(&self) -> InFile<SyntaxNodePtr>; | 26 | /// Used in highlighting and related purposes |
27 | fn display_source(&self) -> InFile<SyntaxNodePtr>; | ||
27 | fn as_any(&self) -> &(dyn Any + Send + 'static); | 28 | fn as_any(&self) -> &(dyn Any + Send + 'static); |
28 | fn is_experimental(&self) -> bool { | 29 | fn is_experimental(&self) -> bool { |
29 | false | 30 | false |
30 | } | 31 | } |
31 | } | 32 | } |
32 | 33 | ||
33 | pub trait AstDiagnostic { | ||
34 | type AST; | ||
35 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST; | ||
36 | } | ||
37 | |||
38 | impl dyn Diagnostic { | ||
39 | pub fn syntax_node(&self, db: &impl AstDatabase) -> SyntaxNode { | ||
40 | let node = db.parse_or_expand(self.source().file_id).unwrap(); | ||
41 | self.source().value.to_node(&node) | ||
42 | } | ||
43 | |||
44 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { | ||
45 | self.as_any().downcast_ref() | ||
46 | } | ||
47 | } | ||
48 | |||
49 | pub struct DiagnosticSink<'a> { | 34 | pub struct DiagnosticSink<'a> { |
50 | callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, | 35 | callbacks: Vec<Box<dyn FnMut(&dyn Diagnostic) -> Result<(), ()> + 'a>>, |
51 | filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>, | 36 | filters: Vec<Box<dyn FnMut(&dyn Diagnostic) -> bool + 'a>>, |
@@ -90,7 +75,7 @@ impl<'a> DiagnosticSinkBuilder<'a> { | |||
90 | } | 75 | } |
91 | 76 | ||
92 | pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self { | 77 | pub fn on<D: Diagnostic, F: FnMut(&D) + 'a>(mut self, mut cb: F) -> Self { |
93 | let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::<D>() { | 78 | let cb = move |diag: &dyn Diagnostic| match diag.as_any().downcast_ref::<D>() { |
94 | Some(d) => { | 79 | Some(d) => { |
95 | cb(d); | 80 | cb(d); |
96 | Ok(()) | 81 | Ok(()) |
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs index 6b482a60c..aefe47bd3 100644 --- a/crates/ra_hir_expand/src/hygiene.rs +++ b/crates/ra_hir_expand/src/hygiene.rs | |||
@@ -17,7 +17,7 @@ pub struct Hygiene { | |||
17 | // This is what `$crate` expands to | 17 | // This is what `$crate` expands to |
18 | def_crate: Option<CrateId>, | 18 | def_crate: Option<CrateId>, |
19 | 19 | ||
20 | // Indiciate this is a local inner macro | 20 | // Indicate this is a local inner macro |
21 | local_inner: bool, | 21 | local_inner: bool, |
22 | } | 22 | } |
23 | 23 | ||
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 2e8d63691..8bb735fc6 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -44,7 +44,8 @@ mod test_db; | |||
44 | /// containing the call plus the offset of the macro call in the file. Note that | 44 | /// containing the call plus the offset of the macro call in the file. Note that |
45 | /// this is a recursive definition! However, the size_of of `HirFileId` is | 45 | /// this is a recursive definition! However, the size_of of `HirFileId` is |
46 | /// finite (because everything bottoms out at the real `FileId`) and small | 46 | /// finite (because everything bottoms out at the real `FileId`) and small |
47 | /// (`MacroCallId` uses the location interner). | 47 | /// (`MacroCallId` uses the location interning. You can check details here: |
48 | /// https://en.wikipedia.org/wiki/String_interning). | ||
48 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 49 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
49 | pub struct HirFileId(HirFileIdRepr); | 50 | pub struct HirFileId(HirFileIdRepr); |
50 | 51 | ||
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 623ce261a..83397d579 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml | |||
@@ -28,9 +28,9 @@ test_utils = { path = "../test_utils" } | |||
28 | 28 | ||
29 | scoped-tls = "1" | 29 | scoped-tls = "1" |
30 | 30 | ||
31 | chalk-solve = { version = "0.19.0" } | 31 | chalk-solve = { version = "0.21.0" } |
32 | chalk-ir = { version = "0.19.0" } | 32 | chalk-ir = { version = "0.21.0" } |
33 | chalk-recursive = { version = "0.19.0" } | 33 | chalk-recursive = { version = "0.21.0" } |
34 | 34 | ||
35 | [dev-dependencies] | 35 | [dev-dependencies] |
36 | expect = { path = "../expect" } | 36 | expect = { path = "../expect" } |
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 56acd3bbf..45e31033e 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -6,10 +6,10 @@ 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::{AstDiagnostic, Diagnostic, DiagnosticSink}; | 9 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSink}; |
10 | use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; | 10 | use hir_expand::{name::Name, HirFileId, InFile}; |
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; | 12 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; |
13 | use stdx::format_to; | 13 | use stdx::format_to; |
14 | 14 | ||
15 | use crate::db::HirDatabase; | 15 | use crate::db::HirDatabase; |
@@ -41,7 +41,7 @@ impl Diagnostic for NoSuchField { | |||
41 | "no such field".to_string() | 41 | "no such field".to_string() |
42 | } | 42 | } |
43 | 43 | ||
44 | fn source(&self) -> InFile<SyntaxNodePtr> { | 44 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
45 | InFile::new(self.file, self.field.clone().into()) | 45 | InFile::new(self.file, self.field.clone().into()) |
46 | } | 46 | } |
47 | 47 | ||
@@ -50,20 +50,11 @@ impl Diagnostic for NoSuchField { | |||
50 | } | 50 | } |
51 | } | 51 | } |
52 | 52 | ||
53 | impl AstDiagnostic for NoSuchField { | ||
54 | type AST = ast::RecordExprField; | ||
55 | |||
56 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
57 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
58 | let node = self.source().value.to_node(&root); | ||
59 | ast::RecordExprField::cast(node).unwrap() | ||
60 | } | ||
61 | } | ||
62 | |||
63 | #[derive(Debug)] | 53 | #[derive(Debug)] |
64 | pub struct MissingFields { | 54 | pub struct MissingFields { |
65 | pub file: HirFileId, | 55 | pub file: HirFileId, |
66 | pub field_list: AstPtr<ast::RecordExprFieldList>, | 56 | pub field_list_parent: AstPtr<ast::RecordExpr>, |
57 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
67 | pub missed_fields: Vec<Name>, | 58 | pub missed_fields: Vec<Name>, |
68 | } | 59 | } |
69 | 60 | ||
@@ -78,28 +69,28 @@ impl Diagnostic for MissingFields { | |||
78 | } | 69 | } |
79 | buf | 70 | buf |
80 | } | 71 | } |
81 | fn source(&self) -> InFile<SyntaxNodePtr> { | 72 | |
82 | InFile { file_id: self.file, value: self.field_list.clone().into() } | 73 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
74 | InFile { | ||
75 | file_id: self.file, | ||
76 | value: self | ||
77 | .field_list_parent_path | ||
78 | .clone() | ||
79 | .map(SyntaxNodePtr::from) | ||
80 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
81 | } | ||
83 | } | 82 | } |
83 | |||
84 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 84 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
85 | self | 85 | self |
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | impl AstDiagnostic for MissingFields { | ||
90 | type AST = ast::RecordExprFieldList; | ||
91 | |||
92 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
93 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
94 | let node = self.source().value.to_node(&root); | ||
95 | ast::RecordExprFieldList::cast(node).unwrap() | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #[derive(Debug)] | 89 | #[derive(Debug)] |
100 | pub struct MissingPatFields { | 90 | pub struct MissingPatFields { |
101 | pub file: HirFileId, | 91 | pub file: HirFileId, |
102 | pub field_list: AstPtr<ast::RecordPatFieldList>, | 92 | pub field_list_parent: AstPtr<ast::RecordPat>, |
93 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
103 | pub missed_fields: Vec<Name>, | 94 | pub missed_fields: Vec<Name>, |
104 | } | 95 | } |
105 | 96 | ||
@@ -114,8 +105,15 @@ impl Diagnostic for MissingPatFields { | |||
114 | } | 105 | } |
115 | buf | 106 | buf |
116 | } | 107 | } |
117 | fn source(&self) -> InFile<SyntaxNodePtr> { | 108 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
118 | InFile { file_id: self.file, value: self.field_list.clone().into() } | 109 | InFile { |
110 | file_id: self.file, | ||
111 | value: self | ||
112 | .field_list_parent_path | ||
113 | .clone() | ||
114 | .map(SyntaxNodePtr::from) | ||
115 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
116 | } | ||
119 | } | 117 | } |
120 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 118 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
121 | self | 119 | self |
@@ -136,7 +134,7 @@ impl Diagnostic for MissingMatchArms { | |||
136 | fn message(&self) -> String { | 134 | fn message(&self) -> String { |
137 | String::from("Missing match arm") | 135 | String::from("Missing match arm") |
138 | } | 136 | } |
139 | fn source(&self) -> InFile<SyntaxNodePtr> { | 137 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
140 | InFile { file_id: self.file, value: self.match_expr.clone().into() } | 138 | InFile { file_id: self.file, value: self.match_expr.clone().into() } |
141 | } | 139 | } |
142 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 140 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -157,7 +155,7 @@ impl Diagnostic for MissingOkInTailExpr { | |||
157 | fn message(&self) -> String { | 155 | fn message(&self) -> String { |
158 | "wrap return expression in Ok".to_string() | 156 | "wrap return expression in Ok".to_string() |
159 | } | 157 | } |
160 | fn source(&self) -> InFile<SyntaxNodePtr> { | 158 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
161 | InFile { file_id: self.file, value: self.expr.clone().into() } | 159 | InFile { file_id: self.file, value: self.expr.clone().into() } |
162 | } | 160 | } |
163 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 161 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -165,16 +163,6 @@ impl Diagnostic for MissingOkInTailExpr { | |||
165 | } | 163 | } |
166 | } | 164 | } |
167 | 165 | ||
168 | impl AstDiagnostic for MissingOkInTailExpr { | ||
169 | type AST = ast::Expr; | ||
170 | |||
171 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
172 | let root = db.parse_or_expand(self.file).unwrap(); | ||
173 | let node = self.source().value.to_node(&root); | ||
174 | ast::Expr::cast(node).unwrap() | ||
175 | } | ||
176 | } | ||
177 | |||
178 | #[derive(Debug)] | 166 | #[derive(Debug)] |
179 | pub struct BreakOutsideOfLoop { | 167 | pub struct BreakOutsideOfLoop { |
180 | pub file: HirFileId, | 168 | pub file: HirFileId, |
@@ -188,7 +176,7 @@ impl Diagnostic for BreakOutsideOfLoop { | |||
188 | fn message(&self) -> String { | 176 | fn message(&self) -> String { |
189 | "break outside of loop".to_string() | 177 | "break outside of loop".to_string() |
190 | } | 178 | } |
191 | fn source(&self) -> InFile<SyntaxNodePtr> { | 179 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
192 | InFile { file_id: self.file, value: self.expr.clone().into() } | 180 | InFile { file_id: self.file, value: self.expr.clone().into() } |
193 | } | 181 | } |
194 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 182 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -196,16 +184,6 @@ impl Diagnostic for BreakOutsideOfLoop { | |||
196 | } | 184 | } |
197 | } | 185 | } |
198 | 186 | ||
199 | impl AstDiagnostic for BreakOutsideOfLoop { | ||
200 | type AST = ast::Expr; | ||
201 | |||
202 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
203 | let root = db.parse_or_expand(self.file).unwrap(); | ||
204 | let node = self.source().value.to_node(&root); | ||
205 | ast::Expr::cast(node).unwrap() | ||
206 | } | ||
207 | } | ||
208 | |||
209 | #[derive(Debug)] | 187 | #[derive(Debug)] |
210 | pub struct MissingUnsafe { | 188 | pub struct MissingUnsafe { |
211 | pub file: HirFileId, | 189 | pub file: HirFileId, |
@@ -219,7 +197,7 @@ impl Diagnostic for MissingUnsafe { | |||
219 | fn message(&self) -> String { | 197 | fn message(&self) -> String { |
220 | format!("This operation is unsafe and requires an unsafe function or block") | 198 | format!("This operation is unsafe and requires an unsafe function or block") |
221 | } | 199 | } |
222 | fn source(&self) -> InFile<SyntaxNodePtr> { | 200 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
223 | InFile { file_id: self.file, value: self.expr.clone().into() } | 201 | InFile { file_id: self.file, value: self.expr.clone().into() } |
224 | } | 202 | } |
225 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 203 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -227,16 +205,6 @@ impl Diagnostic for MissingUnsafe { | |||
227 | } | 205 | } |
228 | } | 206 | } |
229 | 207 | ||
230 | impl AstDiagnostic for MissingUnsafe { | ||
231 | type AST = ast::Expr; | ||
232 | |||
233 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
234 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
235 | let node = self.source().value.to_node(&root); | ||
236 | ast::Expr::cast(node).unwrap() | ||
237 | } | ||
238 | } | ||
239 | |||
240 | #[derive(Debug)] | 208 | #[derive(Debug)] |
241 | pub struct MismatchedArgCount { | 209 | pub struct MismatchedArgCount { |
242 | pub file: HirFileId, | 210 | pub file: HirFileId, |
@@ -253,7 +221,7 @@ impl Diagnostic for MismatchedArgCount { | |||
253 | let s = if self.expected == 1 { "" } else { "s" }; | 221 | let s = if self.expected == 1 { "" } else { "s" }; |
254 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | 222 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) |
255 | } | 223 | } |
256 | fn source(&self) -> InFile<SyntaxNodePtr> { | 224 | fn display_source(&self) -> InFile<SyntaxNodePtr> { |
257 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | 225 | InFile { file_id: self.file, value: self.call_expr.clone().into() } |
258 | } | 226 | } |
259 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 227 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -264,19 +232,13 @@ impl Diagnostic for MismatchedArgCount { | |||
264 | } | 232 | } |
265 | } | 233 | } |
266 | 234 | ||
267 | impl AstDiagnostic for MismatchedArgCount { | ||
268 | type AST = ast::CallExpr; | ||
269 | fn ast(&self, db: &dyn AstDatabase) -> Self::AST { | ||
270 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
271 | let node = self.source().value.to_node(&root); | ||
272 | ast::CallExpr::cast(node).unwrap() | ||
273 | } | ||
274 | } | ||
275 | |||
276 | #[cfg(test)] | 235 | #[cfg(test)] |
277 | mod tests { | 236 | mod tests { |
278 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; | 237 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId}; |
279 | use hir_expand::diagnostics::{Diagnostic, DiagnosticSinkBuilder}; | 238 | use hir_expand::{ |
239 | db::AstDatabase, | ||
240 | diagnostics::{Diagnostic, DiagnosticSinkBuilder}, | ||
241 | }; | ||
280 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; | 242 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt}; |
281 | use ra_syntax::{TextRange, TextSize}; | 243 | use ra_syntax::{TextRange, TextSize}; |
282 | use rustc_hash::FxHashMap; | 244 | use rustc_hash::FxHashMap; |
@@ -321,9 +283,11 @@ mod tests { | |||
321 | 283 | ||
322 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | 284 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); |
323 | db.diagnostics(|d| { | 285 | db.diagnostics(|d| { |
324 | // FXIME: macros... | 286 | let src = d.display_source(); |
325 | let file_id = d.source().file_id.original_file(&db); | 287 | let root = db.parse_or_expand(src.file_id).unwrap(); |
326 | let range = d.syntax_node(&db).text_range(); | 288 | // FIXME: macros... |
289 | let file_id = src.file_id.original_file(&db); | ||
290 | let range = src.value.to_node(&root).text_range(); | ||
327 | let message = d.message().to_owned(); | 291 | let message = d.message().to_owned(); |
328 | actual.entry(file_id).or_default().push((range, message)); | 292 | actual.entry(file_id).or_default().push((range, message)); |
329 | }); | 293 | }); |
@@ -351,8 +315,8 @@ struct S { foo: i32, bar: () } | |||
351 | impl S { | 315 | impl S { |
352 | fn new() -> S { | 316 | fn new() -> S { |
353 | S { | 317 | S { |
354 | //^... Missing structure fields: | 318 | //^ Missing structure fields: |
355 | //| - bar | 319 | //| - bar |
356 | foo: 92, | 320 | foo: 92, |
357 | baz: 62, | 321 | baz: 62, |
358 | //^^^^^^^ no such field | 322 | //^^^^^^^ no such field |
@@ -473,8 +437,8 @@ impl Foo { | |||
473 | struct S { foo: i32, bar: () } | 437 | struct S { foo: i32, bar: () } |
474 | fn baz(s: S) { | 438 | fn baz(s: S) { |
475 | let S { foo: _ } = s; | 439 | let S { foo: _ } = s; |
476 | //^^^^^^^^^^ Missing structure fields: | 440 | //^ Missing structure fields: |
477 | // | - bar | 441 | //| - bar |
478 | } | 442 | } |
479 | "#, | 443 | "#, |
480 | ); | 444 | ); |
diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs index 95bbf2d95..51adcecaf 100644 --- a/crates/ra_hir_ty/src/diagnostics/expr.rs +++ b/crates/ra_hir_ty/src/diagnostics/expr.rs | |||
@@ -100,8 +100,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
100 | 100 | ||
101 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 101 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
102 | let root = source_ptr.file_syntax(db.upcast()); | 102 | let root = source_ptr.file_syntax(db.upcast()); |
103 | if let ast::Expr::RecordExpr(record_lit) = &source_ptr.value.to_node(&root) { | 103 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) { |
104 | if let Some(field_list) = record_lit.record_expr_field_list() { | 104 | if let Some(_) = record_expr.record_expr_field_list() { |
105 | let variant_data = variant_data(db.upcast(), variant_def); | 105 | let variant_data = variant_data(db.upcast(), variant_def); |
106 | let missed_fields = missed_fields | 106 | let missed_fields = missed_fields |
107 | .into_iter() | 107 | .into_iter() |
@@ -109,7 +109,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
109 | .collect(); | 109 | .collect(); |
110 | self.sink.push(MissingFields { | 110 | self.sink.push(MissingFields { |
111 | file: source_ptr.file_id, | 111 | file: source_ptr.file_id, |
112 | field_list: AstPtr::new(&field_list), | 112 | field_list_parent: AstPtr::new(&record_expr), |
113 | field_list_parent_path: record_expr.path().map(|path| AstPtr::new(&path)), | ||
113 | missed_fields, | 114 | missed_fields, |
114 | }) | 115 | }) |
115 | } | 116 | } |
@@ -131,7 +132,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
131 | if let Some(expr) = source_ptr.value.as_ref().left() { | 132 | if let Some(expr) = source_ptr.value.as_ref().left() { |
132 | let root = source_ptr.file_syntax(db.upcast()); | 133 | let root = source_ptr.file_syntax(db.upcast()); |
133 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | 134 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { |
134 | if let Some(field_list) = record_pat.record_pat_field_list() { | 135 | if let Some(_) = record_pat.record_pat_field_list() { |
135 | let variant_data = variant_data(db.upcast(), variant_def); | 136 | let variant_data = variant_data(db.upcast(), variant_def); |
136 | let missed_fields = missed_fields | 137 | let missed_fields = missed_fields |
137 | .into_iter() | 138 | .into_iter() |
@@ -139,7 +140,10 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
139 | .collect(); | 140 | .collect(); |
140 | self.sink.push(MissingPatFields { | 141 | self.sink.push(MissingPatFields { |
141 | file: source_ptr.file_id, | 142 | file: source_ptr.file_id, |
142 | field_list: AstPtr::new(&field_list), | 143 | field_list_parent: AstPtr::new(&record_pat), |
144 | field_list_parent_path: record_pat | ||
145 | .path() | ||
146 | .map(|path| AstPtr::new(&path)), | ||
143 | missed_fields, | 147 | missed_fields, |
144 | }) | 148 | }) |
145 | } | 149 | } |
diff --git a/crates/ra_hir_ty/src/diagnostics/match_check.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs index 507edcb7d..deca244db 100644 --- a/crates/ra_hir_ty/src/diagnostics/match_check.rs +++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs | |||
@@ -1161,15 +1161,15 @@ fn main() { | |||
1161 | //^ Missing match arm | 1161 | //^ Missing match arm |
1162 | match a { | 1162 | match a { |
1163 | Either::A { } => (), | 1163 | Either::A { } => (), |
1164 | //^^^ Missing structure fields: | 1164 | //^^^^^^^^^ Missing structure fields: |
1165 | // | - foo | 1165 | // | - foo |
1166 | Either::B => (), | 1166 | Either::B => (), |
1167 | } | 1167 | } |
1168 | match a { | 1168 | match a { |
1169 | //^ Missing match arm | 1169 | //^ Missing match arm |
1170 | Either::A { } => (), | 1170 | Either::A { } => (), |
1171 | } //^^^ Missing structure fields: | 1171 | } //^^^^^^^^^ Missing structure fields: |
1172 | // | - foo | 1172 | // | - foo |
1173 | 1173 | ||
1174 | match a { | 1174 | match a { |
1175 | Either::A { foo: true } => (), | 1175 | Either::A { foo: true } => (), |
diff --git a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs index 5cc76bdce..61ffbf5d1 100644 --- a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -6,6 +6,7 @@ use std::sync::Arc; | |||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | body::Body, | 7 | body::Body, |
8 | expr::{Expr, ExprId, UnaryOp}, | 8 | expr::{Expr, ExprId, UnaryOp}, |
9 | resolver::{resolver_for_expr, ResolveValueResult, ValueNs}, | ||
9 | DefWithBodyId, | 10 | DefWithBodyId, |
10 | }; | 11 | }; |
11 | use hir_expand::diagnostics::DiagnosticSink; | 12 | use hir_expand::diagnostics::DiagnosticSink; |
@@ -70,7 +71,7 @@ pub fn unsafe_expressions( | |||
70 | ) -> Vec<UnsafeExpr> { | 71 | ) -> Vec<UnsafeExpr> { |
71 | let mut unsafe_exprs = vec![]; | 72 | let mut unsafe_exprs = vec![]; |
72 | let body = db.body(def); | 73 | let body = db.body(def); |
73 | walk_unsafe(&mut unsafe_exprs, db, infer, &body, body.body_expr, false); | 74 | walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false); |
74 | 75 | ||
75 | unsafe_exprs | 76 | unsafe_exprs |
76 | } | 77 | } |
@@ -79,6 +80,7 @@ fn walk_unsafe( | |||
79 | unsafe_exprs: &mut Vec<UnsafeExpr>, | 80 | unsafe_exprs: &mut Vec<UnsafeExpr>, |
80 | db: &dyn HirDatabase, | 81 | db: &dyn HirDatabase, |
81 | infer: &InferenceResult, | 82 | infer: &InferenceResult, |
83 | def: DefWithBodyId, | ||
82 | body: &Body, | 84 | body: &Body, |
83 | current: ExprId, | 85 | current: ExprId, |
84 | inside_unsafe_block: bool, | 86 | inside_unsafe_block: bool, |
@@ -97,6 +99,15 @@ fn walk_unsafe( | |||
97 | } | 99 | } |
98 | } | 100 | } |
99 | } | 101 | } |
102 | Expr::Path(path) => { | ||
103 | let resolver = resolver_for_expr(db.upcast(), def, current); | ||
104 | let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path()); | ||
105 | if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial { | ||
106 | if db.static_data(id).mutable { | ||
107 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | ||
108 | } | ||
109 | } | ||
110 | } | ||
100 | Expr::MethodCall { .. } => { | 111 | Expr::MethodCall { .. } => { |
101 | if infer | 112 | if infer |
102 | .method_resolution(current) | 113 | .method_resolution(current) |
@@ -112,13 +123,13 @@ fn walk_unsafe( | |||
112 | } | 123 | } |
113 | } | 124 | } |
114 | Expr::Unsafe { body: child } => { | 125 | Expr::Unsafe { body: child } => { |
115 | return walk_unsafe(unsafe_exprs, db, infer, body, *child, true); | 126 | return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true); |
116 | } | 127 | } |
117 | _ => {} | 128 | _ => {} |
118 | } | 129 | } |
119 | 130 | ||
120 | expr.walk_child_exprs(|child| { | 131 | expr.walk_child_exprs(|child| { |
121 | walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); | 132 | walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block); |
122 | }); | 133 | }); |
123 | } | 134 | } |
124 | 135 | ||
@@ -170,4 +181,25 @@ fn main() { | |||
170 | "#, | 181 | "#, |
171 | ); | 182 | ); |
172 | } | 183 | } |
184 | |||
185 | #[test] | ||
186 | fn missing_unsafe_diagnostic_with_static_mut() { | ||
187 | check_diagnostics( | ||
188 | r#" | ||
189 | struct Ty { | ||
190 | a: u8, | ||
191 | } | ||
192 | |||
193 | static mut static_mut: Ty = Ty { a: 0 }; | ||
194 | |||
195 | fn main() { | ||
196 | let x = static_mut.a; | ||
197 | //^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block | ||
198 | unsafe { | ||
199 | let x = static_mut.a; | ||
200 | } | ||
201 | } | ||
202 | "#, | ||
203 | ); | ||
204 | } | ||
173 | } | 205 | } |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 28f32a0a4..3d12039a6 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -440,6 +440,12 @@ impl<'a> InferenceContext<'a> { | |||
440 | let ty = self.insert_type_vars(ty.subst(&substs)); | 440 | let ty = self.insert_type_vars(ty.subst(&substs)); |
441 | forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) | 441 | forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) |
442 | } | 442 | } |
443 | TypeNs::AdtId(AdtId::UnionId(u)) => { | ||
444 | let substs = Ty::substs_from_path(&ctx, path, u.into(), true); | ||
445 | let ty = self.db.ty(u.into()); | ||
446 | let ty = self.insert_type_vars(ty.subst(&substs)); | ||
447 | forbid_unresolved_segments((ty, Some(u.into())), unresolved) | ||
448 | } | ||
443 | TypeNs::EnumVariantId(var) => { | 449 | TypeNs::EnumVariantId(var) => { |
444 | let substs = Ty::substs_from_path(&ctx, path, var.into(), true); | 450 | let substs = Ty::substs_from_path(&ctx, path, var.into(), true); |
445 | let ty = self.db.ty(var.parent.into()); | 451 | let ty = self.db.ty(var.parent.into()); |
@@ -490,10 +496,7 @@ impl<'a> InferenceContext<'a> { | |||
490 | // FIXME potentially resolve assoc type | 496 | // FIXME potentially resolve assoc type |
491 | (Ty::Unknown, None) | 497 | (Ty::Unknown, None) |
492 | } | 498 | } |
493 | TypeNs::AdtId(AdtId::EnumId(_)) | 499 | TypeNs::AdtId(AdtId::EnumId(_)) | TypeNs::BuiltinType(_) | TypeNs::TraitId(_) => { |
494 | | TypeNs::AdtId(AdtId::UnionId(_)) | ||
495 | | TypeNs::BuiltinType(_) | ||
496 | | TypeNs::TraitId(_) => { | ||
497 | // FIXME diagnostic | 500 | // FIXME diagnostic |
498 | (Ty::Unknown, None) | 501 | (Ty::Unknown, None) |
499 | } | 502 | } |
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 1eacc6f95..7638f167b 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -518,6 +518,7 @@ impl Ty { | |||
518 | let (segment, generic_def) = match resolved { | 518 | let (segment, generic_def) = match resolved { |
519 | ValueTyDefId::FunctionId(it) => (last, Some(it.into())), | 519 | ValueTyDefId::FunctionId(it) => (last, Some(it.into())), |
520 | ValueTyDefId::StructId(it) => (last, Some(it.into())), | 520 | ValueTyDefId::StructId(it) => (last, Some(it.into())), |
521 | ValueTyDefId::UnionId(it) => (last, Some(it.into())), | ||
521 | ValueTyDefId::ConstId(it) => (last, Some(it.into())), | 522 | ValueTyDefId::ConstId(it) => (last, Some(it.into())), |
522 | ValueTyDefId::StaticId(_) => (last, None), | 523 | ValueTyDefId::StaticId(_) => (last, None), |
523 | ValueTyDefId::EnumVariantId(var) => { | 524 | ValueTyDefId::EnumVariantId(var) => { |
@@ -1148,11 +1149,12 @@ impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefI | |||
1148 | pub enum ValueTyDefId { | 1149 | pub enum ValueTyDefId { |
1149 | FunctionId(FunctionId), | 1150 | FunctionId(FunctionId), |
1150 | StructId(StructId), | 1151 | StructId(StructId), |
1152 | UnionId(UnionId), | ||
1151 | EnumVariantId(EnumVariantId), | 1153 | EnumVariantId(EnumVariantId), |
1152 | ConstId(ConstId), | 1154 | ConstId(ConstId), |
1153 | StaticId(StaticId), | 1155 | StaticId(StaticId), |
1154 | } | 1156 | } |
1155 | impl_from!(FunctionId, StructId, EnumVariantId, ConstId, StaticId for ValueTyDefId); | 1157 | impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId); |
1156 | 1158 | ||
1157 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 1159 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
1158 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | 1160 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and |
@@ -1179,6 +1181,7 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders | |||
1179 | match def { | 1181 | match def { |
1180 | ValueTyDefId::FunctionId(it) => type_for_fn(db, it), | 1182 | ValueTyDefId::FunctionId(it) => type_for_fn(db, it), |
1181 | ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), | 1183 | ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), |
1184 | ValueTyDefId::UnionId(it) => type_for_adt(db, it.into()), | ||
1182 | ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), | 1185 | ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), |
1183 | ValueTyDefId::ConstId(it) => type_for_const(db, it), | 1186 | ValueTyDefId::ConstId(it) => type_for_const(db, it), |
1184 | ValueTyDefId::StaticId(it) => type_for_static(db, it), | 1187 | ValueTyDefId::StaticId(it) => type_for_static(db, it), |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 3fd7d5cd4..5a7cf9455 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -334,16 +334,44 @@ fn infer_union() { | |||
334 | bar: f32, | 334 | bar: f32, |
335 | } | 335 | } |
336 | 336 | ||
337 | fn test() { | ||
338 | let u = MyUnion { foo: 0 }; | ||
339 | unsafe { baz(u); } | ||
340 | let u = MyUnion { bar: 0.0 }; | ||
341 | unsafe { baz(u); } | ||
342 | } | ||
343 | |||
337 | unsafe fn baz(u: MyUnion) { | 344 | unsafe fn baz(u: MyUnion) { |
338 | let inner = u.foo; | 345 | let inner = u.foo; |
346 | let inner = u.bar; | ||
339 | } | 347 | } |
340 | "#, | 348 | "#, |
341 | expect![[r#" | 349 | expect![[r#" |
342 | 61..62 'u': MyUnion | 350 | 57..172 '{ ...); } }': () |
343 | 73..99 '{ ...foo; }': () | 351 | 67..68 'u': MyUnion |
344 | 83..88 'inner': u32 | 352 | 71..89 'MyUnio...o: 0 }': MyUnion |
345 | 91..92 'u': MyUnion | 353 | 86..87 '0': u32 |
346 | 91..96 'u.foo': u32 | 354 | 95..113 'unsafe...(u); }': () |
355 | 102..113 '{ baz(u); }': () | ||
356 | 104..107 'baz': fn baz(MyUnion) | ||
357 | 104..110 'baz(u)': () | ||
358 | 108..109 'u': MyUnion | ||
359 | 122..123 'u': MyUnion | ||
360 | 126..146 'MyUnio... 0.0 }': MyUnion | ||
361 | 141..144 '0.0': f32 | ||
362 | 152..170 'unsafe...(u); }': () | ||
363 | 159..170 '{ baz(u); }': () | ||
364 | 161..164 'baz': fn baz(MyUnion) | ||
365 | 161..167 'baz(u)': () | ||
366 | 165..166 'u': MyUnion | ||
367 | 188..189 'u': MyUnion | ||
368 | 200..249 '{ ...bar; }': () | ||
369 | 210..215 'inner': u32 | ||
370 | 218..219 'u': MyUnion | ||
371 | 218..223 'u.foo': u32 | ||
372 | 233..238 'inner': f32 | ||
373 | 241..242 'u': MyUnion | ||
374 | 241..246 'u.bar': f32 | ||
347 | "#]], | 375 | "#]], |
348 | ); | 376 | ); |
349 | } | 377 | } |
diff --git a/crates/ra_ide/src/completion/complete_snippet.rs b/crates/ra_ide/src/completion/complete_snippet.rs index 28d8f7876..4368e4eec 100644 --- a/crates/ra_ide/src/completion/complete_snippet.rs +++ b/crates/ra_ide/src/completion/complete_snippet.rs | |||
@@ -36,7 +36,7 @@ pub(super) fn complete_item_snippet(acc: &mut Completions, ctx: &CompletionConte | |||
36 | snippet( | 36 | snippet( |
37 | ctx, | 37 | ctx, |
38 | cap, | 38 | cap, |
39 | "Test module", | 39 | "tmod (Test module)", |
40 | "\ | 40 | "\ |
41 | #[cfg(test)] | 41 | #[cfg(test)] |
42 | mod tests { | 42 | mod tests { |
@@ -54,7 +54,7 @@ mod tests { | |||
54 | snippet( | 54 | snippet( |
55 | ctx, | 55 | ctx, |
56 | cap, | 56 | cap, |
57 | "Test function", | 57 | "tfn (Test function)", |
58 | "\ | 58 | "\ |
59 | #[test] | 59 | #[test] |
60 | fn ${1:feature}() { | 60 | fn ${1:feature}() { |
@@ -106,10 +106,10 @@ mod tests { | |||
106 | } | 106 | } |
107 | "#, | 107 | "#, |
108 | expect![[r#" | 108 | expect![[r#" |
109 | sn Test function | ||
110 | sn Test module | ||
111 | sn macro_rules | 109 | sn macro_rules |
112 | sn pub(crate) | 110 | sn pub(crate) |
111 | sn tfn (Test function) | ||
112 | sn tmod (Test module) | ||
113 | "#]], | 113 | "#]], |
114 | ) | 114 | ) |
115 | } | 115 | } |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 6b03b30bb..4aa761148 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -27,7 +27,7 @@ pub(crate) struct CompletionContext<'a> { | |||
27 | pub(super) scope: SemanticsScope<'a>, | 27 | pub(super) scope: SemanticsScope<'a>, |
28 | pub(super) db: &'a RootDatabase, | 28 | pub(super) db: &'a RootDatabase, |
29 | pub(super) config: &'a CompletionConfig, | 29 | pub(super) config: &'a CompletionConfig, |
30 | pub(super) offset: TextSize, | 30 | pub(super) position: FilePosition, |
31 | /// The token before the cursor, in the original file. | 31 | /// The token before the cursor, in the original file. |
32 | pub(super) original_token: SyntaxToken, | 32 | pub(super) original_token: SyntaxToken, |
33 | /// The token before the cursor, in the macro-expanded file. | 33 | /// The token before the cursor, in the macro-expanded file. |
@@ -117,7 +117,7 @@ impl<'a> CompletionContext<'a> { | |||
117 | config, | 117 | config, |
118 | original_token, | 118 | original_token, |
119 | token, | 119 | token, |
120 | offset: position.offset, | 120 | position, |
121 | krate, | 121 | krate, |
122 | expected_type: None, | 122 | expected_type: None, |
123 | name_ref_syntax: None, | 123 | name_ref_syntax: None, |
@@ -209,7 +209,7 @@ impl<'a> CompletionContext<'a> { | |||
209 | mark::hit!(completes_if_prefix_is_keyword); | 209 | mark::hit!(completes_if_prefix_is_keyword); |
210 | self.original_token.text_range() | 210 | self.original_token.text_range() |
211 | } else { | 211 | } else { |
212 | TextRange::empty(self.offset) | 212 | TextRange::empty(self.position.offset) |
213 | } | 213 | } |
214 | } | 214 | } |
215 | 215 | ||
@@ -379,8 +379,8 @@ impl<'a> CompletionContext<'a> { | |||
379 | self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); | 379 | self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); |
380 | self.has_type_args = segment.generic_arg_list().is_some(); | 380 | self.has_type_args = segment.generic_arg_list().is_some(); |
381 | 381 | ||
382 | #[allow(deprecated)] | 382 | let hygiene = hir::Hygiene::new(self.db, self.position.file_id.into()); |
383 | if let Some(path) = hir::Path::from_ast(path.clone()) { | 383 | if let Some(path) = hir::Path::from_src(path.clone(), &hygiene) { |
384 | if let Some(path_prefix) = path.qualifier() { | 384 | if let Some(path_prefix) = path.qualifier() { |
385 | self.path_prefix = Some(path_prefix); | 385 | self.path_prefix = Some(path_prefix); |
386 | return; | 386 | return; |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 9a94ff476..59f1b1424 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -2,8 +2,8 @@ | |||
2 | //! It also handles scoring (sorting) completions. | 2 | //! It also handles scoring (sorting) completions. |
3 | 3 | ||
4 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; | 4 | use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type}; |
5 | use itertools::Itertools; | ||
5 | use ra_syntax::ast::NameOwner; | 6 | use ra_syntax::ast::NameOwner; |
6 | use stdx::SepBy; | ||
7 | use test_utils::mark; | 7 | use test_utils::mark; |
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
@@ -289,16 +289,16 @@ impl Completions { | |||
289 | .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); | 289 | .map(|field| (field.name(ctx.db), field.signature_ty(ctx.db))); |
290 | let variant_kind = variant.kind(ctx.db); | 290 | let variant_kind = variant.kind(ctx.db); |
291 | let detail = match variant_kind { | 291 | let detail = match variant_kind { |
292 | StructKind::Tuple | StructKind::Unit => detail_types | 292 | StructKind::Tuple | StructKind::Unit => format!( |
293 | .map(|(_, t)| t.display(ctx.db).to_string()) | 293 | "({})", |
294 | .sep_by(", ") | 294 | detail_types.map(|(_, t)| t.display(ctx.db).to_string()).format(", ") |
295 | .surround_with("(", ")") | 295 | ), |
296 | .to_string(), | 296 | StructKind::Record => format!( |
297 | StructKind::Record => detail_types | 297 | "{{ {} }}", |
298 | .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string())) | 298 | detail_types |
299 | .sep_by(", ") | 299 | .map(|(n, t)| format!("{}: {}", n, t.display(ctx.db).to_string())) |
300 | .surround_with("{ ", " }") | 300 | .format(", ") |
301 | .to_string(), | 301 | ), |
302 | }; | 302 | }; |
303 | let mut res = CompletionItem::new( | 303 | let mut res = CompletionItem::new( |
304 | CompletionKind::Reference, | 304 | CompletionKind::Reference, |
@@ -412,11 +412,10 @@ impl Builder { | |||
412 | self = self.trigger_call_info(); | 412 | self = self.trigger_call_info(); |
413 | let snippet = match (ctx.config.add_call_argument_snippets, params) { | 413 | let snippet = match (ctx.config.add_call_argument_snippets, params) { |
414 | (true, Params::Named(params)) => { | 414 | (true, Params::Named(params)) => { |
415 | let function_params_snippet = params | 415 | let function_params_snippet = |
416 | .iter() | 416 | params.iter().enumerate().format_with(", ", |(index, param_name), f| { |
417 | .enumerate() | 417 | f(&format_args!("${{{}:{}}}", index + 1, param_name)) |
418 | .map(|(index, param_name)| format!("${{{}:{}}}", index + 1, param_name)) | 418 | }); |
419 | .sep_by(", "); | ||
420 | format!("{}({})$0", name, function_params_snippet) | 419 | format!("{}({})$0", name, function_params_snippet) |
421 | } | 420 | } |
422 | _ => { | 421 | _ => { |
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs index 5ce900bf4..79dbb0865 100644 --- a/crates/ra_ide/src/diagnostics.rs +++ b/crates/ra_ide/src/diagnostics.rs | |||
@@ -6,22 +6,21 @@ | |||
6 | 6 | ||
7 | use std::cell::RefCell; | 7 | use std::cell::RefCell; |
8 | 8 | ||
9 | use hir::{ | 9 | use hir::{diagnostics::DiagnosticSinkBuilder, Semantics}; |
10 | diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSinkBuilder}, | ||
11 | HasSource, HirDisplay, Semantics, VariantDef, | ||
12 | }; | ||
13 | use itertools::Itertools; | 10 | use itertools::Itertools; |
14 | use ra_db::SourceDatabase; | 11 | use ra_db::SourceDatabase; |
15 | use ra_ide_db::RootDatabase; | 12 | use ra_ide_db::RootDatabase; |
16 | use ra_prof::profile; | 13 | use ra_prof::profile; |
17 | use ra_syntax::{ | 14 | use ra_syntax::{ |
18 | algo, | 15 | ast::{self, AstNode}, |
19 | ast::{self, edit::IndentLevel, make, AstNode}, | ||
20 | SyntaxNode, TextRange, T, | 16 | SyntaxNode, TextRange, T, |
21 | }; | 17 | }; |
22 | use ra_text_edit::{TextEdit, TextEditBuilder}; | 18 | use ra_text_edit::{TextEdit, TextEditBuilder}; |
23 | 19 | ||
24 | use crate::{AnalysisConfig, Diagnostic, FileId, FileSystemEdit, Fix, SourceFileEdit}; | 20 | use crate::{AnalysisConfig, Diagnostic, FileId, Fix, SourceFileEdit}; |
21 | |||
22 | mod diagnostics_with_fix; | ||
23 | use diagnostics_with_fix::DiagnosticWithFix; | ||
25 | 24 | ||
26 | #[derive(Debug, Copy, Clone)] | 25 | #[derive(Debug, Copy, Clone)] |
27 | pub enum Severity { | 26 | pub enum Severity { |
@@ -56,77 +55,16 @@ pub(crate) fn diagnostics( | |||
56 | let res = RefCell::new(res); | 55 | let res = RefCell::new(res); |
57 | let mut sink_builder = DiagnosticSinkBuilder::new() | 56 | let mut sink_builder = DiagnosticSinkBuilder::new() |
58 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { | 57 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { |
59 | let original_file = d.source().file_id.original_file(db); | 58 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
60 | let fix = Fix::new( | ||
61 | "Create module", | ||
62 | FileSystemEdit::CreateFile { anchor: original_file, dst: d.candidate.clone() } | ||
63 | .into(), | ||
64 | ); | ||
65 | res.borrow_mut().push(Diagnostic { | ||
66 | name: Some(d.name().into()), | ||
67 | range: sema.diagnostics_range(d).range, | ||
68 | message: d.message(), | ||
69 | severity: Severity::Error, | ||
70 | fix: Some(fix), | ||
71 | }) | ||
72 | }) | 59 | }) |
73 | .on::<hir::diagnostics::MissingFields, _>(|d| { | 60 | .on::<hir::diagnostics::MissingFields, _>(|d| { |
74 | // Note that although we could add a diagnostics to | 61 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
75 | // fill the missing tuple field, e.g : | ||
76 | // `struct A(usize);` | ||
77 | // `let a = A { 0: () }` | ||
78 | // but it is uncommon usage and it should not be encouraged. | ||
79 | let fix = if d.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { | ||
80 | None | ||
81 | } else { | ||
82 | let mut field_list = d.ast(db); | ||
83 | for f in d.missed_fields.iter() { | ||
84 | let field = make::record_expr_field( | ||
85 | make::name_ref(&f.to_string()), | ||
86 | Some(make::expr_unit()), | ||
87 | ); | ||
88 | field_list = field_list.append_field(&field); | ||
89 | } | ||
90 | |||
91 | let edit = { | ||
92 | let mut builder = TextEditBuilder::default(); | ||
93 | algo::diff(&d.ast(db).syntax(), &field_list.syntax()) | ||
94 | .into_text_edit(&mut builder); | ||
95 | builder.finish() | ||
96 | }; | ||
97 | Some(Fix::new("Fill struct fields", SourceFileEdit { file_id, edit }.into())) | ||
98 | }; | ||
99 | |||
100 | res.borrow_mut().push(Diagnostic { | ||
101 | name: Some(d.name().into()), | ||
102 | range: sema.diagnostics_range(d).range, | ||
103 | message: d.message(), | ||
104 | severity: Severity::Error, | ||
105 | fix, | ||
106 | }) | ||
107 | }) | 62 | }) |
108 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { | 63 | .on::<hir::diagnostics::MissingOkInTailExpr, _>(|d| { |
109 | let node = d.ast(db); | 64 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
110 | let replacement = format!("Ok({})", node.syntax()); | ||
111 | let edit = TextEdit::replace(node.syntax().text_range(), replacement); | ||
112 | let source_change = SourceFileEdit { file_id, edit }.into(); | ||
113 | let fix = Fix::new("Wrap with ok", source_change); | ||
114 | res.borrow_mut().push(Diagnostic { | ||
115 | name: Some(d.name().into()), | ||
116 | range: sema.diagnostics_range(d).range, | ||
117 | message: d.message(), | ||
118 | severity: Severity::Error, | ||
119 | fix: Some(fix), | ||
120 | }) | ||
121 | }) | 65 | }) |
122 | .on::<hir::diagnostics::NoSuchField, _>(|d| { | 66 | .on::<hir::diagnostics::NoSuchField, _>(|d| { |
123 | res.borrow_mut().push(Diagnostic { | 67 | res.borrow_mut().push(diagnostic_with_fix(d, &sema)); |
124 | name: Some(d.name().into()), | ||
125 | range: sema.diagnostics_range(d).range, | ||
126 | message: d.message(), | ||
127 | severity: Severity::Error, | ||
128 | fix: missing_struct_field_fix(&sema, file_id, d), | ||
129 | }) | ||
130 | }) | 68 | }) |
131 | // Only collect experimental diagnostics when they're enabled. | 69 | // Only collect experimental diagnostics when they're enabled. |
132 | .filter(|diag| !diag.is_experimental() || enable_experimental); | 70 | .filter(|diag| !diag.is_experimental() || enable_experimental); |
@@ -144,7 +82,7 @@ pub(crate) fn diagnostics( | |||
144 | res.borrow_mut().push(Diagnostic { | 82 | res.borrow_mut().push(Diagnostic { |
145 | name: Some(d.name().into()), | 83 | name: Some(d.name().into()), |
146 | message: d.message(), | 84 | message: d.message(), |
147 | range: sema.diagnostics_range(d).range, | 85 | range: sema.diagnostics_display_range(d).range, |
148 | severity: Severity::Error, | 86 | severity: Severity::Error, |
149 | fix: None, | 87 | fix: None, |
150 | }) | 88 | }) |
@@ -157,77 +95,13 @@ pub(crate) fn diagnostics( | |||
157 | res.into_inner() | 95 | res.into_inner() |
158 | } | 96 | } |
159 | 97 | ||
160 | fn missing_struct_field_fix( | 98 | fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { |
161 | sema: &Semantics<RootDatabase>, | 99 | Diagnostic { |
162 | usage_file_id: FileId, | 100 | name: Some(d.name().into()), |
163 | d: &hir::diagnostics::NoSuchField, | 101 | range: sema.diagnostics_display_range(d).range, |
164 | ) -> Option<Fix> { | 102 | message: d.message(), |
165 | let record_expr = sema.ast(d); | 103 | severity: Severity::Error, |
166 | 104 | fix: d.fix(&sema), | |
167 | let record_lit = ast::RecordExpr::cast(record_expr.syntax().parent()?.parent()?)?; | ||
168 | let def_id = sema.resolve_variant(record_lit)?; | ||
169 | let module; | ||
170 | let def_file_id; | ||
171 | let record_fields = match VariantDef::from(def_id) { | ||
172 | VariantDef::Struct(s) => { | ||
173 | module = s.module(sema.db); | ||
174 | let source = s.source(sema.db); | ||
175 | def_file_id = source.file_id; | ||
176 | let fields = source.value.field_list()?; | ||
177 | record_field_list(fields)? | ||
178 | } | ||
179 | VariantDef::Union(u) => { | ||
180 | module = u.module(sema.db); | ||
181 | let source = u.source(sema.db); | ||
182 | def_file_id = source.file_id; | ||
183 | source.value.record_field_list()? | ||
184 | } | ||
185 | VariantDef::EnumVariant(e) => { | ||
186 | module = e.module(sema.db); | ||
187 | let source = e.source(sema.db); | ||
188 | def_file_id = source.file_id; | ||
189 | let fields = source.value.field_list()?; | ||
190 | record_field_list(fields)? | ||
191 | } | ||
192 | }; | ||
193 | let def_file_id = def_file_id.original_file(sema.db); | ||
194 | |||
195 | let new_field_type = sema.type_of_expr(&record_expr.expr()?)?; | ||
196 | if new_field_type.is_unknown() { | ||
197 | return None; | ||
198 | } | ||
199 | let new_field = make::record_field( | ||
200 | record_expr.field_name()?, | ||
201 | make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), | ||
202 | ); | ||
203 | |||
204 | let last_field = record_fields.fields().last()?; | ||
205 | let last_field_syntax = last_field.syntax(); | ||
206 | let indent = IndentLevel::from_node(last_field_syntax); | ||
207 | |||
208 | let mut new_field = new_field.to_string(); | ||
209 | if usage_file_id != def_file_id { | ||
210 | new_field = format!("pub(crate) {}", new_field); | ||
211 | } | ||
212 | new_field = format!("\n{}{}", indent, new_field); | ||
213 | |||
214 | let needs_comma = !last_field_syntax.to_string().ends_with(','); | ||
215 | if needs_comma { | ||
216 | new_field = format!(",{}", new_field); | ||
217 | } | ||
218 | |||
219 | let source_change = SourceFileEdit { | ||
220 | file_id: def_file_id, | ||
221 | edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field), | ||
222 | }; | ||
223 | let fix = Fix::new("Create field", source_change.into()); | ||
224 | return Some(fix); | ||
225 | |||
226 | fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { | ||
227 | match field_def_list { | ||
228 | ast::FieldList::RecordFieldList(it) => Some(it), | ||
229 | ast::FieldList::TupleFieldList(_) => None, | ||
230 | } | ||
231 | } | 105 | } |
232 | } | 106 | } |
233 | 107 | ||
@@ -238,25 +112,26 @@ fn check_unnecessary_braces_in_use_statement( | |||
238 | ) -> Option<()> { | 112 | ) -> Option<()> { |
239 | let use_tree_list = ast::UseTreeList::cast(node.clone())?; | 113 | let use_tree_list = ast::UseTreeList::cast(node.clone())?; |
240 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { | 114 | if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() { |
241 | let range = use_tree_list.syntax().text_range(); | 115 | let use_range = use_tree_list.syntax().text_range(); |
242 | let edit = | 116 | let edit = |
243 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree) | 117 | text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree) |
244 | .unwrap_or_else(|| { | 118 | .unwrap_or_else(|| { |
245 | let to_replace = single_use_tree.syntax().text().to_string(); | 119 | let to_replace = single_use_tree.syntax().text().to_string(); |
246 | let mut edit_builder = TextEditBuilder::default(); | 120 | let mut edit_builder = TextEditBuilder::default(); |
247 | edit_builder.delete(range); | 121 | edit_builder.delete(use_range); |
248 | edit_builder.insert(range.start(), to_replace); | 122 | edit_builder.insert(use_range.start(), to_replace); |
249 | edit_builder.finish() | 123 | edit_builder.finish() |
250 | }); | 124 | }); |
251 | 125 | ||
252 | acc.push(Diagnostic { | 126 | acc.push(Diagnostic { |
253 | name: None, | 127 | name: None, |
254 | range, | 128 | range: use_range, |
255 | message: "Unnecessary braces in use statement".to_string(), | 129 | message: "Unnecessary braces in use statement".to_string(), |
256 | severity: Severity::WeakWarning, | 130 | severity: Severity::WeakWarning, |
257 | fix: Some(Fix::new( | 131 | fix: Some(Fix::new( |
258 | "Remove unnecessary braces", | 132 | "Remove unnecessary braces", |
259 | SourceFileEdit { file_id, edit }.into(), | 133 | SourceFileEdit { file_id, edit }.into(), |
134 | use_range, | ||
260 | )), | 135 | )), |
261 | }); | 136 | }); |
262 | } | 137 | } |
@@ -271,8 +146,7 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement( | |||
271 | if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] { | 146 | if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind() == T![self] { |
272 | let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); | 147 | let start = use_tree_list_node.prev_sibling_or_token()?.text_range().start(); |
273 | let end = use_tree_list_node.text_range().end(); | 148 | let end = use_tree_list_node.text_range().end(); |
274 | let range = TextRange::new(start, end); | 149 | return Some(TextEdit::delete(TextRange::new(start, end))); |
275 | return Some(TextEdit::delete(range)); | ||
276 | } | 150 | } |
277 | None | 151 | None |
278 | } | 152 | } |
@@ -295,14 +169,16 @@ fn check_struct_shorthand_initialization( | |||
295 | edit_builder.insert(record_field.syntax().text_range().start(), field_name); | 169 | edit_builder.insert(record_field.syntax().text_range().start(), field_name); |
296 | let edit = edit_builder.finish(); | 170 | let edit = edit_builder.finish(); |
297 | 171 | ||
172 | let field_range = record_field.syntax().text_range(); | ||
298 | acc.push(Diagnostic { | 173 | acc.push(Diagnostic { |
299 | name: None, | 174 | name: None, |
300 | range: record_field.syntax().text_range(), | 175 | range: field_range, |
301 | message: "Shorthand struct initialization".to_string(), | 176 | message: "Shorthand struct initialization".to_string(), |
302 | severity: Severity::WeakWarning, | 177 | severity: Severity::WeakWarning, |
303 | fix: Some(Fix::new( | 178 | fix: Some(Fix::new( |
304 | "Use struct shorthand initialization", | 179 | "Use struct shorthand initialization", |
305 | SourceFileEdit { file_id, edit }.into(), | 180 | SourceFileEdit { file_id, edit }.into(), |
181 | field_range, | ||
306 | )), | 182 | )), |
307 | }); | 183 | }); |
308 | } | 184 | } |
@@ -326,7 +202,7 @@ mod tests { | |||
326 | /// Takes a multi-file input fixture with annotated cursor positions, | 202 | /// Takes a multi-file input fixture with annotated cursor positions, |
327 | /// and checks that: | 203 | /// and checks that: |
328 | /// * a diagnostic is produced | 204 | /// * a diagnostic is produced |
329 | /// * this diagnostic touches the input cursor position | 205 | /// * this diagnostic fix trigger range touches the input cursor position |
330 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied | 206 | /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied |
331 | fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { | 207 | fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { |
332 | let after = trim_indent(ra_fixture_after); | 208 | let after = trim_indent(ra_fixture_after); |
@@ -344,10 +220,10 @@ mod tests { | |||
344 | 220 | ||
345 | assert_eq_text!(&after, &actual); | 221 | assert_eq_text!(&after, &actual); |
346 | assert!( | 222 | assert!( |
347 | diagnostic.range.start() <= file_position.offset | 223 | fix.fix_trigger_range.start() <= file_position.offset |
348 | && diagnostic.range.end() >= file_position.offset, | 224 | && fix.fix_trigger_range.end() >= file_position.offset, |
349 | "diagnostic range {:?} does not touch cursor position {:?}", | 225 | "diagnostic fix range {:?} does not touch cursor position {:?}", |
350 | diagnostic.range, | 226 | fix.fix_trigger_range, |
351 | file_position.offset | 227 | file_position.offset |
352 | ); | 228 | ); |
353 | } | 229 | } |
@@ -712,6 +588,7 @@ fn test_fn() { | |||
712 | ], | 588 | ], |
713 | is_snippet: false, | 589 | is_snippet: false, |
714 | }, | 590 | }, |
591 | fix_trigger_range: 0..8, | ||
715 | }, | 592 | }, |
716 | ), | 593 | ), |
717 | }, | 594 | }, |
diff --git a/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs b/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs new file mode 100644 index 000000000..f7c73773f --- /dev/null +++ b/crates/ra_ide/src/diagnostics/diagnostics_with_fix.rs | |||
@@ -0,0 +1,171 @@ | |||
1 | //! Provides a way to attach fixes to the diagnostics. | ||
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 hir::{ | ||
6 | db::AstDatabase, | ||
7 | diagnostics::{Diagnostic, MissingFields, MissingOkInTailExpr, NoSuchField, UnresolvedModule}, | ||
8 | HasSource, HirDisplay, Semantics, VariantDef, | ||
9 | }; | ||
10 | use ra_db::FileId; | ||
11 | use ra_ide_db::{ | ||
12 | source_change::{FileSystemEdit, SourceFileEdit}, | ||
13 | RootDatabase, | ||
14 | }; | ||
15 | use ra_syntax::{algo, ast, AstNode}; | ||
16 | use ra_text_edit::{TextEdit, TextEditBuilder}; | ||
17 | |||
18 | /// A [Diagnostic] that potentially has a fix available. | ||
19 | /// | ||
20 | /// [Diagnostic]: hir::diagnostics::Diagnostic | ||
21 | pub trait DiagnosticWithFix: Diagnostic { | ||
22 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>; | ||
23 | } | ||
24 | |||
25 | impl DiagnosticWithFix for UnresolvedModule { | ||
26 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | ||
27 | let root = sema.db.parse_or_expand(self.file)?; | ||
28 | let unresolved_module = self.decl.to_node(&root); | ||
29 | Some(Fix::new( | ||
30 | "Create module", | ||
31 | FileSystemEdit::CreateFile { | ||
32 | anchor: self.file.original_file(sema.db), | ||
33 | dst: self.candidate.clone(), | ||
34 | } | ||
35 | .into(), | ||
36 | unresolved_module.syntax().text_range(), | ||
37 | )) | ||
38 | } | ||
39 | } | ||
40 | |||
41 | impl DiagnosticWithFix for NoSuchField { | ||
42 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | ||
43 | let root = sema.db.parse_or_expand(self.file)?; | ||
44 | missing_record_expr_field_fix( | ||
45 | &sema, | ||
46 | self.file.original_file(sema.db), | ||
47 | &self.field.to_node(&root), | ||
48 | ) | ||
49 | } | ||
50 | } | ||
51 | |||
52 | impl DiagnosticWithFix for MissingFields { | ||
53 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | ||
54 | // Note that although we could add a diagnostics to | ||
55 | // fill the missing tuple field, e.g : | ||
56 | // `struct A(usize);` | ||
57 | // `let a = A { 0: () }` | ||
58 | // but it is uncommon usage and it should not be encouraged. | ||
59 | if self.missed_fields.iter().any(|it| it.as_tuple_index().is_some()) { | ||
60 | return None; | ||
61 | } | ||
62 | |||
63 | let root = sema.db.parse_or_expand(self.file)?; | ||
64 | let old_field_list = self.field_list_parent.to_node(&root).record_expr_field_list()?; | ||
65 | let mut new_field_list = old_field_list.clone(); | ||
66 | for f in self.missed_fields.iter() { | ||
67 | let field = | ||
68 | make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit())); | ||
69 | new_field_list = new_field_list.append_field(&field); | ||
70 | } | ||
71 | |||
72 | let edit = { | ||
73 | let mut builder = TextEditBuilder::default(); | ||
74 | algo::diff(&old_field_list.syntax(), &new_field_list.syntax()) | ||
75 | .into_text_edit(&mut builder); | ||
76 | builder.finish() | ||
77 | }; | ||
78 | Some(Fix::new( | ||
79 | "Fill struct fields", | ||
80 | SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(), | ||
81 | sema.original_range(&old_field_list.syntax()).range, | ||
82 | )) | ||
83 | } | ||
84 | } | ||
85 | |||
86 | impl DiagnosticWithFix for MissingOkInTailExpr { | ||
87 | fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { | ||
88 | let root = sema.db.parse_or_expand(self.file)?; | ||
89 | let tail_expr = self.expr.to_node(&root); | ||
90 | let tail_expr_range = tail_expr.syntax().text_range(); | ||
91 | let edit = TextEdit::replace(tail_expr_range, format!("Ok({})", tail_expr.syntax())); | ||
92 | let source_change = | ||
93 | SourceFileEdit { file_id: self.file.original_file(sema.db), edit }.into(); | ||
94 | Some(Fix::new("Wrap with ok", source_change, tail_expr_range)) | ||
95 | } | ||
96 | } | ||
97 | |||
98 | fn missing_record_expr_field_fix( | ||
99 | sema: &Semantics<RootDatabase>, | ||
100 | usage_file_id: FileId, | ||
101 | record_expr_field: &ast::RecordExprField, | ||
102 | ) -> Option<Fix> { | ||
103 | let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; | ||
104 | let def_id = sema.resolve_variant(record_lit)?; | ||
105 | let module; | ||
106 | let def_file_id; | ||
107 | let record_fields = match VariantDef::from(def_id) { | ||
108 | VariantDef::Struct(s) => { | ||
109 | module = s.module(sema.db); | ||
110 | let source = s.source(sema.db); | ||
111 | def_file_id = source.file_id; | ||
112 | let fields = source.value.field_list()?; | ||
113 | record_field_list(fields)? | ||
114 | } | ||
115 | VariantDef::Union(u) => { | ||
116 | module = u.module(sema.db); | ||
117 | let source = u.source(sema.db); | ||
118 | def_file_id = source.file_id; | ||
119 | source.value.record_field_list()? | ||
120 | } | ||
121 | VariantDef::EnumVariant(e) => { | ||
122 | module = e.module(sema.db); | ||
123 | let source = e.source(sema.db); | ||
124 | def_file_id = source.file_id; | ||
125 | let fields = source.value.field_list()?; | ||
126 | record_field_list(fields)? | ||
127 | } | ||
128 | }; | ||
129 | let def_file_id = def_file_id.original_file(sema.db); | ||
130 | |||
131 | let new_field_type = sema.type_of_expr(&record_expr_field.expr()?)?; | ||
132 | if new_field_type.is_unknown() { | ||
133 | return None; | ||
134 | } | ||
135 | let new_field = make::record_field( | ||
136 | record_expr_field.field_name()?, | ||
137 | make::ty(&new_field_type.display_source_code(sema.db, module.into()).ok()?), | ||
138 | ); | ||
139 | |||
140 | let last_field = record_fields.fields().last()?; | ||
141 | let last_field_syntax = last_field.syntax(); | ||
142 | let indent = IndentLevel::from_node(last_field_syntax); | ||
143 | |||
144 | let mut new_field = new_field.to_string(); | ||
145 | if usage_file_id != def_file_id { | ||
146 | new_field = format!("pub(crate) {}", new_field); | ||
147 | } | ||
148 | new_field = format!("\n{}{}", indent, new_field); | ||
149 | |||
150 | let needs_comma = !last_field_syntax.to_string().ends_with(','); | ||
151 | if needs_comma { | ||
152 | new_field = format!(",{}", new_field); | ||
153 | } | ||
154 | |||
155 | let source_change = SourceFileEdit { | ||
156 | file_id: def_file_id, | ||
157 | edit: TextEdit::insert(last_field_syntax.text_range().end(), new_field), | ||
158 | }; | ||
159 | return Some(Fix::new( | ||
160 | "Create field", | ||
161 | source_change.into(), | ||
162 | record_expr_field.syntax().text_range(), | ||
163 | )); | ||
164 | |||
165 | fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { | ||
166 | match field_def_list { | ||
167 | ast::FieldList::RecordFieldList(it) => Some(it), | ||
168 | ast::FieldList::TupleFieldList(_) => None, | ||
169 | } | ||
170 | } | ||
171 | } | ||
diff --git a/crates/ra_ide/src/display/short_label.rs b/crates/ra_ide/src/display/short_label.rs index 0fdf8e9a5..010c34705 100644 --- a/crates/ra_ide/src/display/short_label.rs +++ b/crates/ra_ide/src/display/short_label.rs | |||
@@ -47,6 +47,12 @@ impl ShortLabel for ast::Module { | |||
47 | } | 47 | } |
48 | } | 48 | } |
49 | 49 | ||
50 | impl ShortLabel for ast::SourceFile { | ||
51 | fn short_label(&self) -> Option<String> { | ||
52 | None | ||
53 | } | ||
54 | } | ||
55 | |||
50 | impl ShortLabel for ast::TypeAlias { | 56 | impl ShortLabel for ast::TypeAlias { |
51 | fn short_label(&self) -> Option<String> { | 57 | fn short_label(&self) -> Option<String> { |
52 | short_label_from_node(self, "type ") | 58 | short_label_from_node(self, "type ") |
@@ -55,7 +61,11 @@ impl ShortLabel for ast::TypeAlias { | |||
55 | 61 | ||
56 | impl ShortLabel for ast::Const { | 62 | impl ShortLabel for ast::Const { |
57 | fn short_label(&self) -> Option<String> { | 63 | fn short_label(&self) -> Option<String> { |
58 | short_label_from_ty(self, self.ty(), "const ") | 64 | let mut new_buf = short_label_from_ty(self, self.ty(), "const ")?; |
65 | if let Some(expr) = self.body() { | ||
66 | format_to!(new_buf, " = {}", expr.syntax()); | ||
67 | } | ||
68 | Some(new_buf) | ||
59 | } | 69 | } |
60 | } | 70 | } |
61 | 71 | ||
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index 4e3f428fa..45389fd23 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use hir::Semantics; | 1 | use hir::Semantics; |
2 | use ra_ide_db::{ | 2 | use ra_ide_db::{ |
3 | defs::{classify_name, classify_name_ref, NameClass}, | 3 | defs::{classify_name, classify_name_ref}, |
4 | symbol_index, RootDatabase, | 4 | symbol_index, RootDatabase, |
5 | }; | 5 | }; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -40,10 +40,7 @@ pub(crate) fn goto_definition( | |||
40 | reference_definition(&sema, &name_ref).to_vec() | 40 | reference_definition(&sema, &name_ref).to_vec() |
41 | }, | 41 | }, |
42 | ast::Name(name) => { | 42 | ast::Name(name) => { |
43 | let def = match classify_name(&sema, &name)? { | 43 | let def = classify_name(&sema, &name)?.definition(sema.db); |
44 | NameClass::Definition(def) | NameClass::ConstReference(def) => def, | ||
45 | NameClass::FieldShorthand { local: _, field } => field, | ||
46 | }; | ||
47 | let nav = def.try_to_nav(sema.db)?; | 44 | let nav = def.try_to_nav(sema.db)?; |
48 | vec![nav] | 45 | vec![nav] |
49 | }, | 46 | }, |
@@ -86,8 +83,7 @@ pub(crate) fn reference_definition( | |||
86 | ) -> ReferenceResult { | 83 | ) -> ReferenceResult { |
87 | let name_kind = classify_name_ref(sema, name_ref); | 84 | let name_kind = classify_name_ref(sema, name_ref); |
88 | if let Some(def) = name_kind { | 85 | if let Some(def) = name_kind { |
89 | let def = def.definition(); | 86 | let def = def.definition(sema.db); |
90 | |||
91 | return match def.try_to_nav(sema.db) { | 87 | return match def.try_to_nav(sema.db) { |
92 | Some(nav) => ReferenceResult::Exact(nav), | 88 | Some(nav) => ReferenceResult::Exact(nav), |
93 | None => ReferenceResult::Approximate(Vec::new()), | 89 | None => ReferenceResult::Approximate(Vec::new()), |
@@ -134,6 +130,32 @@ mod tests { | |||
134 | } | 130 | } |
135 | 131 | ||
136 | #[test] | 132 | #[test] |
133 | fn goto_def_for_extern_crate() { | ||
134 | check( | ||
135 | r#" | ||
136 | //- /main.rs | ||
137 | extern crate std<|>; | ||
138 | //- /std/lib.rs | ||
139 | // empty | ||
140 | //^ file | ||
141 | "#, | ||
142 | ) | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn goto_def_for_renamed_extern_crate() { | ||
147 | check( | ||
148 | r#" | ||
149 | //- /main.rs | ||
150 | extern crate std as abc<|>; | ||
151 | //- /std/lib.rs | ||
152 | // empty | ||
153 | //^ file | ||
154 | "#, | ||
155 | ) | ||
156 | } | ||
157 | |||
158 | #[test] | ||
137 | fn goto_def_in_items() { | 159 | fn goto_def_in_items() { |
138 | check( | 160 | check( |
139 | r#" | 161 | r#" |
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs index aa48cb412..f66f62bfb 100644 --- a/crates/ra_ide/src/hover.rs +++ b/crates/ra_ide/src/hover.rs | |||
@@ -85,8 +85,8 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn | |||
85 | let node = token.parent(); | 85 | let node = token.parent(); |
86 | let definition = match_ast! { | 86 | let definition = match_ast! { |
87 | match node { | 87 | match node { |
88 | ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition()), | 88 | ast::NameRef(name_ref) => classify_name_ref(&sema, &name_ref).map(|d| d.definition(sema.db)), |
89 | ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition()), | 89 | ast::Name(name) => classify_name(&sema, &name).map(|d| d.definition(sema.db)), |
90 | _ => None, | 90 | _ => None, |
91 | } | 91 | } |
92 | }; | 92 | }; |
@@ -304,7 +304,10 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
304 | let docs = Documentation::from_ast(&it).map(Into::into); | 304 | let docs = Documentation::from_ast(&it).map(Into::into); |
305 | hover_markup(docs, it.short_label(), mod_path) | 305 | hover_markup(docs, it.short_label(), mod_path) |
306 | } | 306 | } |
307 | _ => None, | 307 | ModuleSource::SourceFile(it) => { |
308 | let docs = Documentation::from_ast(&it).map(Into::into); | ||
309 | hover_markup(docs, it.short_label(), mod_path) | ||
310 | } | ||
308 | }, | 311 | }, |
309 | ModuleDef::Function(it) => from_def_source(db, it, mod_path), | 312 | ModuleDef::Function(it) => from_def_source(db, it, mod_path), |
310 | ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), | 313 | ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path), |
@@ -509,6 +512,37 @@ fn main() { } | |||
509 | } | 512 | } |
510 | 513 | ||
511 | #[test] | 514 | #[test] |
515 | fn hover_shows_fn_doc() { | ||
516 | check( | ||
517 | r#" | ||
518 | /// # Example | ||
519 | /// ``` | ||
520 | /// # use std::path::Path; | ||
521 | /// # | ||
522 | /// foo(Path::new("hello, world!")) | ||
523 | /// ``` | ||
524 | pub fn foo<|>(_: &Path) {} | ||
525 | |||
526 | fn main() { } | ||
527 | "#, | ||
528 | expect![[r#" | ||
529 | *foo* | ||
530 | ```rust | ||
531 | pub fn foo(_: &Path) | ||
532 | ``` | ||
533 | ___ | ||
534 | |||
535 | # Example | ||
536 | ``` | ||
537 | # use std::path::Path; | ||
538 | # | ||
539 | foo(Path::new("hello, world!")) | ||
540 | ``` | ||
541 | "#]], | ||
542 | ); | ||
543 | } | ||
544 | |||
545 | #[test] | ||
512 | fn hover_shows_struct_field_info() { | 546 | fn hover_shows_struct_field_info() { |
513 | // Hovering over the field when instantiating | 547 | // Hovering over the field when instantiating |
514 | check( | 548 | check( |
@@ -556,16 +590,16 @@ fn main() { | |||
556 | #[test] | 590 | #[test] |
557 | fn hover_const_static() { | 591 | fn hover_const_static() { |
558 | check( | 592 | check( |
559 | r#"const foo<|>: u32 = 0;"#, | 593 | r#"const foo<|>: u32 = 123;"#, |
560 | expect![[r#" | 594 | expect![[r#" |
561 | *foo* | 595 | *foo* |
562 | ```rust | 596 | ```rust |
563 | const foo: u32 | 597 | const foo: u32 = 123 |
564 | ``` | 598 | ``` |
565 | "#]], | 599 | "#]], |
566 | ); | 600 | ); |
567 | check( | 601 | check( |
568 | r#"static foo<|>: u32 = 0;"#, | 602 | r#"static foo<|>: u32 = 456;"#, |
569 | expect![[r#" | 603 | expect![[r#" |
570 | *foo* | 604 | *foo* |
571 | ```rust | 605 | ```rust |
@@ -800,7 +834,7 @@ fn main() { | |||
800 | expect![[r#" | 834 | expect![[r#" |
801 | *C* | 835 | *C* |
802 | ```rust | 836 | ```rust |
803 | const C: u32 | 837 | const C: u32 = 1 |
804 | ``` | 838 | ``` |
805 | "#]], | 839 | "#]], |
806 | ) | 840 | ) |
@@ -1107,6 +1141,46 @@ fn bar() { fo<|>o(); } | |||
1107 | } | 1141 | } |
1108 | 1142 | ||
1109 | #[test] | 1143 | #[test] |
1144 | fn test_hover_extern_crate() { | ||
1145 | check( | ||
1146 | r#" | ||
1147 | //- /main.rs | ||
1148 | extern crate st<|>d; | ||
1149 | //- /std/lib.rs | ||
1150 | //! Standard library for this test | ||
1151 | //! | ||
1152 | //! Printed? | ||
1153 | //! abc123 | ||
1154 | "#, | ||
1155 | expect![[r#" | ||
1156 | *std* | ||
1157 | Standard library for this test | ||
1158 | |||
1159 | Printed? | ||
1160 | abc123 | ||
1161 | "#]], | ||
1162 | ); | ||
1163 | check( | ||
1164 | r#" | ||
1165 | //- /main.rs | ||
1166 | extern crate std as ab<|>c; | ||
1167 | //- /std/lib.rs | ||
1168 | //! Standard library for this test | ||
1169 | //! | ||
1170 | //! Printed? | ||
1171 | //! abc123 | ||
1172 | "#, | ||
1173 | expect![[r#" | ||
1174 | *abc* | ||
1175 | Standard library for this test | ||
1176 | |||
1177 | Printed? | ||
1178 | abc123 | ||
1179 | "#]], | ||
1180 | ); | ||
1181 | } | ||
1182 | |||
1183 | #[test] | ||
1110 | fn test_hover_mod_with_same_name_as_function() { | 1184 | fn test_hover_mod_with_same_name_as_function() { |
1111 | check( | 1185 | check( |
1112 | r#" | 1186 | r#" |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 3822b9409..2cbd7e4f0 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -119,13 +119,19 @@ pub struct Diagnostic { | |||
119 | pub struct Fix { | 119 | pub struct Fix { |
120 | pub label: String, | 120 | pub label: String, |
121 | pub source_change: SourceChange, | 121 | pub source_change: SourceChange, |
122 | /// Allows to trigger the fix only when the caret is in the range given | ||
123 | pub fix_trigger_range: TextRange, | ||
122 | } | 124 | } |
123 | 125 | ||
124 | impl Fix { | 126 | impl Fix { |
125 | pub fn new(label: impl Into<String>, source_change: SourceChange) -> Self { | 127 | pub fn new( |
128 | label: impl Into<String>, | ||
129 | source_change: SourceChange, | ||
130 | fix_trigger_range: TextRange, | ||
131 | ) -> Self { | ||
126 | let label = label.into(); | 132 | let label = label.into(); |
127 | assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.')); | 133 | assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.')); |
128 | Self { label, source_change } | 134 | Self { label, source_change, fix_trigger_range } |
129 | } | 135 | } |
130 | } | 136 | } |
131 | 137 | ||
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs index cf456630a..453985de3 100644 --- a/crates/ra_ide/src/references.rs +++ b/crates/ra_ide/src/references.rs | |||
@@ -130,13 +130,13 @@ fn find_name( | |||
130 | opt_name: Option<ast::Name>, | 130 | opt_name: Option<ast::Name>, |
131 | ) -> Option<RangeInfo<Definition>> { | 131 | ) -> Option<RangeInfo<Definition>> { |
132 | if let Some(name) = opt_name { | 132 | if let Some(name) = opt_name { |
133 | let def = classify_name(sema, &name)?.definition(); | 133 | let def = classify_name(sema, &name)?.definition(sema.db); |
134 | let range = name.syntax().text_range(); | 134 | let range = name.syntax().text_range(); |
135 | return Some(RangeInfo::new(range, def)); | 135 | return Some(RangeInfo::new(range, def)); |
136 | } | 136 | } |
137 | let name_ref = | 137 | let name_ref = |
138 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; | 138 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; |
139 | let def = classify_name_ref(sema, &name_ref)?.definition(); | 139 | let def = classify_name_ref(sema, &name_ref)?.definition(sema.db); |
140 | let range = name_ref.syntax().text_range(); | 140 | let range = name_ref.syntax().text_range(); |
141 | Some(RangeInfo::new(range, def)) | 141 | Some(RangeInfo::new(range, def)) |
142 | } | 142 | } |
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs index 4348b43be..8be862fd6 100644 --- a/crates/ra_ide/src/ssr.rs +++ b/crates/ra_ide/src/ssr.rs | |||
@@ -21,8 +21,8 @@ use ra_ssr::{MatchFinder, SsrError, SsrRule}; | |||
21 | // replacement occurs. For example if our replacement template is `foo::Bar` and we match some | 21 | // replacement occurs. For example if our replacement template is `foo::Bar` and we match some |
22 | // code in the `foo` module, we'll insert just `Bar`. | 22 | // code in the `foo` module, we'll insert just `Bar`. |
23 | // | 23 | // |
24 | // Method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will match | 24 | // Inherent method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will |
25 | // `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`. | 25 | // match `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`. |
26 | // | 26 | // |
27 | // The scope of the search / replace will be restricted to the current selection if any, otherwise | 27 | // The scope of the search / replace will be restricted to the current selection if any, otherwise |
28 | // it will apply to the whole workspace. | 28 | // it will apply to the whole workspace. |
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs index a32ae0165..c10e15db8 100644 --- a/crates/ra_ide/src/syntax_highlighting.rs +++ b/crates/ra_ide/src/syntax_highlighting.rs | |||
@@ -4,7 +4,7 @@ mod injection; | |||
4 | #[cfg(test)] | 4 | #[cfg(test)] |
5 | mod tests; | 5 | mod tests; |
6 | 6 | ||
7 | use hir::{Name, Semantics}; | 7 | use hir::{Name, Semantics, VariantDef}; |
8 | use ra_ide_db::{ | 8 | use ra_ide_db::{ |
9 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, | 9 | defs::{classify_name, classify_name_ref, Definition, NameClass, NameRefClass}, |
10 | RootDatabase, | 10 | RootDatabase, |
@@ -455,6 +455,18 @@ fn macro_call_range(macro_call: &ast::MacroCall) -> Option<TextRange> { | |||
455 | Some(TextRange::new(range_start, range_end)) | 455 | Some(TextRange::new(range_start, range_end)) |
456 | } | 456 | } |
457 | 457 | ||
458 | fn is_possibly_unsafe(name_ref: &ast::NameRef) -> bool { | ||
459 | name_ref | ||
460 | .syntax() | ||
461 | .parent() | ||
462 | .and_then(|parent| { | ||
463 | ast::FieldExpr::cast(parent.clone()) | ||
464 | .map(|_| true) | ||
465 | .or_else(|| ast::RecordPatField::cast(parent).map(|_| true)) | ||
466 | }) | ||
467 | .unwrap_or(false) | ||
468 | } | ||
469 | |||
458 | fn highlight_element( | 470 | fn highlight_element( |
459 | sema: &Semantics<RootDatabase>, | 471 | sema: &Semantics<RootDatabase>, |
460 | bindings_shadow_count: &mut FxHashMap<Name, u32>, | 472 | bindings_shadow_count: &mut FxHashMap<Name, u32>, |
@@ -483,11 +495,21 @@ fn highlight_element( | |||
483 | }; | 495 | }; |
484 | 496 | ||
485 | match name_kind { | 497 | match name_kind { |
498 | Some(NameClass::ExternCrate(_)) => HighlightTag::Module.into(), | ||
486 | Some(NameClass::Definition(def)) => { | 499 | Some(NameClass::Definition(def)) => { |
487 | highlight_name(db, def) | HighlightModifier::Definition | 500 | highlight_name(sema, db, def, None, false) | HighlightModifier::Definition |
501 | } | ||
502 | Some(NameClass::ConstReference(def)) => highlight_name(sema, db, def, None, false), | ||
503 | Some(NameClass::FieldShorthand { field, .. }) => { | ||
504 | let mut h = HighlightTag::Field.into(); | ||
505 | if let Definition::Field(field) = field { | ||
506 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
507 | h |= HighlightModifier::Unsafe; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | h | ||
488 | } | 512 | } |
489 | Some(NameClass::ConstReference(def)) => highlight_name(db, def), | ||
490 | Some(NameClass::FieldShorthand { .. }) => HighlightTag::Field.into(), | ||
491 | None => highlight_name_by_syntax(name) | HighlightModifier::Definition, | 513 | None => highlight_name_by_syntax(name) | HighlightModifier::Definition, |
492 | } | 514 | } |
493 | } | 515 | } |
@@ -498,8 +520,10 @@ fn highlight_element( | |||
498 | } | 520 | } |
499 | NAME_REF => { | 521 | NAME_REF => { |
500 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); | 522 | let name_ref = element.into_node().and_then(ast::NameRef::cast).unwrap(); |
523 | let possibly_unsafe = is_possibly_unsafe(&name_ref); | ||
501 | match classify_name_ref(sema, &name_ref) { | 524 | match classify_name_ref(sema, &name_ref) { |
502 | Some(name_kind) => match name_kind { | 525 | Some(name_kind) => match name_kind { |
526 | NameRefClass::ExternCrate(_) => HighlightTag::Module.into(), | ||
503 | NameRefClass::Definition(def) => { | 527 | NameRefClass::Definition(def) => { |
504 | if let Definition::Local(local) = &def { | 528 | if let Definition::Local(local) = &def { |
505 | if let Some(name) = local.name(db) { | 529 | if let Some(name) = local.name(db) { |
@@ -508,11 +532,13 @@ fn highlight_element( | |||
508 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) | 532 | binding_hash = Some(calc_binding_hash(&name, *shadow_count)) |
509 | } | 533 | } |
510 | }; | 534 | }; |
511 | highlight_name(db, def) | 535 | highlight_name(sema, db, def, Some(name_ref), possibly_unsafe) |
512 | } | 536 | } |
513 | NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), | 537 | NameRefClass::FieldShorthand { .. } => HighlightTag::Field.into(), |
514 | }, | 538 | }, |
515 | None if syntactic_name_ref_highlighting => highlight_name_ref_by_syntax(name_ref), | 539 | None if syntactic_name_ref_highlighting => { |
540 | highlight_name_ref_by_syntax(name_ref, sema) | ||
541 | } | ||
516 | None => HighlightTag::UnresolvedReference.into(), | 542 | None => HighlightTag::UnresolvedReference.into(), |
517 | } | 543 | } |
518 | } | 544 | } |
@@ -540,9 +566,20 @@ fn highlight_element( | |||
540 | } | 566 | } |
541 | } | 567 | } |
542 | p if p.is_punct() => match p { | 568 | p if p.is_punct() => match p { |
543 | T![::] | T![->] | T![=>] | T![&] | T![..] | T![=] | T![@] => { | 569 | T![&] => { |
544 | HighlightTag::Operator.into() | 570 | let h = HighlightTag::Operator.into(); |
571 | let is_unsafe = element | ||
572 | .parent() | ||
573 | .and_then(ast::RefExpr::cast) | ||
574 | .map(|ref_expr| sema.is_unsafe_ref_expr(&ref_expr)) | ||
575 | .unwrap_or(false); | ||
576 | if is_unsafe { | ||
577 | h | HighlightModifier::Unsafe | ||
578 | } else { | ||
579 | h | ||
580 | } | ||
545 | } | 581 | } |
582 | T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] => HighlightTag::Operator.into(), | ||
546 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { | 583 | T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { |
547 | HighlightTag::Macro.into() | 584 | HighlightTag::Macro.into() |
548 | } | 585 | } |
@@ -623,6 +660,18 @@ fn highlight_element( | |||
623 | HighlightTag::SelfKeyword.into() | 660 | HighlightTag::SelfKeyword.into() |
624 | } | 661 | } |
625 | } | 662 | } |
663 | T![ref] => element | ||
664 | .parent() | ||
665 | .and_then(ast::IdentPat::cast) | ||
666 | .and_then(|ident_pat| { | ||
667 | if sema.is_unsafe_ident_pat(&ident_pat) { | ||
668 | Some(HighlightModifier::Unsafe) | ||
669 | } else { | ||
670 | None | ||
671 | } | ||
672 | }) | ||
673 | .map(|modifier| h | modifier) | ||
674 | .unwrap_or(h), | ||
626 | _ => h, | 675 | _ => h, |
627 | } | 676 | } |
628 | } | 677 | } |
@@ -652,16 +701,40 @@ fn is_child_of_impl(element: &SyntaxElement) -> bool { | |||
652 | } | 701 | } |
653 | } | 702 | } |
654 | 703 | ||
655 | fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { | 704 | fn highlight_name( |
705 | sema: &Semantics<RootDatabase>, | ||
706 | db: &RootDatabase, | ||
707 | def: Definition, | ||
708 | name_ref: Option<ast::NameRef>, | ||
709 | possibly_unsafe: bool, | ||
710 | ) -> Highlight { | ||
656 | match def { | 711 | match def { |
657 | Definition::Macro(_) => HighlightTag::Macro, | 712 | Definition::Macro(_) => HighlightTag::Macro, |
658 | Definition::Field(_) => HighlightTag::Field, | 713 | Definition::Field(field) => { |
714 | let mut h = HighlightTag::Field.into(); | ||
715 | if possibly_unsafe { | ||
716 | if let VariantDef::Union(_) = field.parent_def(db) { | ||
717 | h |= HighlightModifier::Unsafe; | ||
718 | } | ||
719 | } | ||
720 | |||
721 | return h; | ||
722 | } | ||
659 | Definition::ModuleDef(def) => match def { | 723 | Definition::ModuleDef(def) => match def { |
660 | hir::ModuleDef::Module(_) => HighlightTag::Module, | 724 | hir::ModuleDef::Module(_) => HighlightTag::Module, |
661 | hir::ModuleDef::Function(func) => { | 725 | hir::ModuleDef::Function(func) => { |
662 | let mut h = HighlightTag::Function.into(); | 726 | let mut h = HighlightTag::Function.into(); |
663 | if func.is_unsafe(db) { | 727 | if func.is_unsafe(db) { |
664 | h |= HighlightModifier::Unsafe; | 728 | h |= HighlightModifier::Unsafe; |
729 | } else { | ||
730 | let is_unsafe = name_ref | ||
731 | .and_then(|name_ref| name_ref.syntax().parent()) | ||
732 | .and_then(ast::MethodCallExpr::cast) | ||
733 | .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)) | ||
734 | .unwrap_or(false); | ||
735 | if is_unsafe { | ||
736 | h |= HighlightModifier::Unsafe; | ||
737 | } | ||
665 | } | 738 | } |
666 | return h; | 739 | return h; |
667 | } | 740 | } |
@@ -677,6 +750,7 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight { | |||
677 | let mut h = Highlight::new(HighlightTag::Static); | 750 | let mut h = Highlight::new(HighlightTag::Static); |
678 | if s.is_mut(db) { | 751 | if s.is_mut(db) { |
679 | h |= HighlightModifier::Mutable; | 752 | h |= HighlightModifier::Mutable; |
753 | h |= HighlightModifier::Unsafe; | ||
680 | } | 754 | } |
681 | return h; | 755 | return h; |
682 | } | 756 | } |
@@ -724,7 +798,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight { | |||
724 | tag.into() | 798 | tag.into() |
725 | } | 799 | } |
726 | 800 | ||
727 | fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { | 801 | fn highlight_name_ref_by_syntax(name: ast::NameRef, sema: &Semantics<RootDatabase>) -> Highlight { |
728 | let default = HighlightTag::UnresolvedReference; | 802 | let default = HighlightTag::UnresolvedReference; |
729 | 803 | ||
730 | let parent = match name.syntax().parent() { | 804 | let parent = match name.syntax().parent() { |
@@ -732,9 +806,36 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { | |||
732 | _ => return default.into(), | 806 | _ => return default.into(), |
733 | }; | 807 | }; |
734 | 808 | ||
735 | let tag = match parent.kind() { | 809 | match parent.kind() { |
736 | METHOD_CALL_EXPR => HighlightTag::Function, | 810 | METHOD_CALL_EXPR => { |
737 | FIELD_EXPR => HighlightTag::Field, | 811 | let mut h = Highlight::new(HighlightTag::Function); |
812 | let is_unsafe = ast::MethodCallExpr::cast(parent) | ||
813 | .map(|method_call_expr| sema.is_unsafe_method_call(method_call_expr)) | ||
814 | .unwrap_or(false); | ||
815 | if is_unsafe { | ||
816 | h |= HighlightModifier::Unsafe; | ||
817 | } | ||
818 | |||
819 | h | ||
820 | } | ||
821 | FIELD_EXPR => { | ||
822 | let h = HighlightTag::Field; | ||
823 | let is_union = ast::FieldExpr::cast(parent) | ||
824 | .and_then(|field_expr| { | ||
825 | let field = sema.resolve_field(&field_expr)?; | ||
826 | Some(if let VariantDef::Union(_) = field.parent_def(sema.db) { | ||
827 | true | ||
828 | } else { | ||
829 | false | ||
830 | }) | ||
831 | }) | ||
832 | .unwrap_or(false); | ||
833 | if is_union { | ||
834 | h | HighlightModifier::Unsafe | ||
835 | } else { | ||
836 | h.into() | ||
837 | } | ||
838 | } | ||
738 | PATH_SEGMENT => { | 839 | PATH_SEGMENT => { |
739 | let path = match parent.parent().and_then(ast::Path::cast) { | 840 | let path = match parent.parent().and_then(ast::Path::cast) { |
740 | Some(it) => it, | 841 | Some(it) => it, |
@@ -758,18 +859,15 @@ fn highlight_name_ref_by_syntax(name: ast::NameRef) -> Highlight { | |||
758 | }; | 859 | }; |
759 | 860 | ||
760 | match parent.kind() { | 861 | match parent.kind() { |
761 | CALL_EXPR => HighlightTag::Function, | 862 | CALL_EXPR => HighlightTag::Function.into(), |
762 | _ => { | 863 | _ => if name.text().chars().next().unwrap_or_default().is_uppercase() { |
763 | if name.text().chars().next().unwrap_or_default().is_uppercase() { | 864 | HighlightTag::Struct.into() |
764 | HighlightTag::Struct | 865 | } else { |
765 | } else { | 866 | HighlightTag::Constant |
766 | HighlightTag::Constant | ||
767 | } | ||
768 | } | 867 | } |
868 | .into(), | ||
769 | } | 869 | } |
770 | } | 870 | } |
771 | _ => default, | 871 | _ => default.into(), |
772 | }; | 872 | } |
773 | |||
774 | tag.into() | ||
775 | } | 873 | } |
diff --git a/crates/ra_ide/src/syntax_highlighting/injection.rs b/crates/ra_ide/src/syntax_highlighting/injection.rs index 8665b480f..6046643ef 100644 --- a/crates/ra_ide/src/syntax_highlighting/injection.rs +++ b/crates/ra_ide/src/syntax_highlighting/injection.rs | |||
@@ -4,8 +4,8 @@ use std::{collections::BTreeMap, convert::TryFrom}; | |||
4 | 4 | ||
5 | use ast::{HasQuotes, HasStringValue}; | 5 | use ast::{HasQuotes, HasStringValue}; |
6 | use hir::Semantics; | 6 | use hir::Semantics; |
7 | use itertools::Itertools; | ||
7 | use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; | 8 | use ra_syntax::{ast, AstToken, SyntaxNode, SyntaxToken, TextRange, TextSize}; |
8 | use stdx::SepBy; | ||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | call_info::ActiveParameter, Analysis, Highlight, HighlightModifier, HighlightTag, | 11 | call_info::ActiveParameter, Analysis, Highlight, HighlightModifier, HighlightTag, |
@@ -129,8 +129,7 @@ pub(super) fn extract_doc_comments( | |||
129 | 129 | ||
130 | line[pos..].to_owned() | 130 | line[pos..].to_owned() |
131 | }) | 131 | }) |
132 | .sep_by("\n") | 132 | .join("\n"); |
133 | .to_string(); | ||
134 | 133 | ||
135 | if doctest.is_empty() { | 134 | if doctest.is_empty() { |
136 | return None; | 135 | return None; |
diff --git a/crates/ra_ide/src/syntax_highlighting/tests.rs b/crates/ra_ide/src/syntax_highlighting/tests.rs index 2deee404c..a8087635a 100644 --- a/crates/ra_ide/src/syntax_highlighting/tests.rs +++ b/crates/ra_ide/src/syntax_highlighting/tests.rs | |||
@@ -275,19 +275,64 @@ fn test_unsafe_highlighting() { | |||
275 | r#" | 275 | r#" |
276 | unsafe fn unsafe_fn() {} | 276 | unsafe fn unsafe_fn() {} |
277 | 277 | ||
278 | union Union { | ||
279 | a: u32, | ||
280 | b: f32, | ||
281 | } | ||
282 | |||
278 | struct HasUnsafeFn; | 283 | struct HasUnsafeFn; |
279 | 284 | ||
280 | impl HasUnsafeFn { | 285 | impl HasUnsafeFn { |
281 | unsafe fn unsafe_method(&self) {} | 286 | unsafe fn unsafe_method(&self) {} |
282 | } | 287 | } |
283 | 288 | ||
289 | struct TypeForStaticMut { | ||
290 | a: u8 | ||
291 | } | ||
292 | |||
293 | static mut global_mut: TypeForStaticMut = TypeForStaticMut { a: 0 }; | ||
294 | |||
295 | #[repr(packed)] | ||
296 | struct Packed { | ||
297 | a: u16, | ||
298 | } | ||
299 | |||
300 | trait DoTheAutoref { | ||
301 | fn calls_autoref(&self); | ||
302 | } | ||
303 | |||
304 | impl DoTheAutoref for u16 { | ||
305 | fn calls_autoref(&self) {} | ||
306 | } | ||
307 | |||
284 | fn main() { | 308 | fn main() { |
285 | let x = &5 as *const usize; | 309 | let x = &5 as *const _ as *const usize; |
310 | let u = Union { b: 0 }; | ||
286 | unsafe { | 311 | unsafe { |
312 | // unsafe fn and method calls | ||
287 | unsafe_fn(); | 313 | unsafe_fn(); |
314 | let b = u.b; | ||
315 | match u { | ||
316 | Union { b: 0 } => (), | ||
317 | Union { a } => (), | ||
318 | } | ||
288 | HasUnsafeFn.unsafe_method(); | 319 | HasUnsafeFn.unsafe_method(); |
289 | let y = *(x); | 320 | |
290 | let z = -x; | 321 | // unsafe deref |
322 | let y = *x; | ||
323 | |||
324 | // unsafe access to a static mut | ||
325 | let a = global_mut.a; | ||
326 | |||
327 | // unsafe ref of packed fields | ||
328 | let packed = Packed { a: 0 }; | ||
329 | let a = &packed.a; | ||
330 | let ref a = packed.a; | ||
331 | let Packed { ref a } = packed; | ||
332 | let Packed { a: ref _a } = packed; | ||
333 | |||
334 | // unsafe auto ref of packed field | ||
335 | packed.a.calls_autoref(); | ||
291 | } | 336 | } |
292 | } | 337 | } |
293 | "# | 338 | "# |
@@ -373,6 +418,23 @@ macro_rules! noop { | |||
373 | ); | 418 | ); |
374 | } | 419 | } |
375 | 420 | ||
421 | #[test] | ||
422 | fn test_extern_crate() { | ||
423 | check_highlighting( | ||
424 | r#" | ||
425 | //- /main.rs | ||
426 | extern crate std; | ||
427 | extern crate alloc as abc; | ||
428 | //- /std/lib.rs | ||
429 | pub struct S; | ||
430 | //- /alloc/lib.rs | ||
431 | pub struct A | ||
432 | "#, | ||
433 | expect_file!["crates/ra_ide/test_data/highlight_extern_crate.html"], | ||
434 | false, | ||
435 | ); | ||
436 | } | ||
437 | |||
376 | /// Highlights the code given by the `ra_fixture` argument, renders the | 438 | /// Highlights the code given by the `ra_fixture` argument, renders the |
377 | /// result as HTML, and compares it with the HTML file given as `snapshot`. | 439 | /// result as HTML, and compares it with the HTML file given as `snapshot`. |
378 | /// Note that the `snapshot` file is overwritten by the rendered HTML. | 440 | /// Note that the `snapshot` file is overwritten by the rendered HTML. |
diff --git a/crates/ra_ide/test_data/highlight_extern_crate.html b/crates/ra_ide/test_data/highlight_extern_crate.html new file mode 100644 index 000000000..800d894c7 --- /dev/null +++ b/crates/ra_ide/test_data/highlight_extern_crate.html | |||
@@ -0,0 +1,40 @@ | |||
1 | |||
2 | <style> | ||
3 | body { margin: 0; } | ||
4 | pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; } | ||
5 | |||
6 | .lifetime { color: #DFAF8F; font-style: italic; } | ||
7 | .comment { color: #7F9F7F; } | ||
8 | .documentation { color: #629755; } | ||
9 | .injected { opacity: 0.65 ; } | ||
10 | .struct, .enum { color: #7CB8BB; } | ||
11 | .enum_variant { color: #BDE0F3; } | ||
12 | .string_literal { color: #CC9393; } | ||
13 | .field { color: #94BFF3; } | ||
14 | .function { color: #93E0E3; } | ||
15 | .function.unsafe { color: #BC8383; } | ||
16 | .operator.unsafe { color: #BC8383; } | ||
17 | .parameter { color: #94BFF3; } | ||
18 | .text { color: #DCDCCC; } | ||
19 | .type { color: #7CB8BB; } | ||
20 | .builtin_type { color: #8CD0D3; } | ||
21 | .type_param { color: #DFAF8F; } | ||
22 | .attribute { color: #94BFF3; } | ||
23 | .numeric_literal { color: #BFEBBF; } | ||
24 | .bool_literal { color: #BFE6EB; } | ||
25 | .macro { color: #94BFF3; } | ||
26 | .module { color: #AFD8AF; } | ||
27 | .value_param { color: #DCDCCC; } | ||
28 | .variable { color: #DCDCCC; } | ||
29 | .format_specifier { color: #CC696B; } | ||
30 | .mutable { text-decoration: underline; } | ||
31 | .escape_sequence { color: #94BFF3; } | ||
32 | .keyword { color: #F0DFAF; font-weight: bold; } | ||
33 | .keyword.unsafe { color: #BC8383; font-weight: bold; } | ||
34 | .control { font-style: italic; } | ||
35 | |||
36 | .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } | ||
37 | </style> | ||
38 | <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">std</span><span class="punctuation">;</span> | ||
39 | <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module">alloc</span> <span class="keyword">as</span> <span class="module">abc</span><span class="punctuation">;</span> | ||
40 | </code></pre> \ No newline at end of file | ||
diff --git a/crates/ra_ide/test_data/highlight_unsafe.html b/crates/ra_ide/test_data/highlight_unsafe.html index b81b6f1c3..552fea668 100644 --- a/crates/ra_ide/test_data/highlight_unsafe.html +++ b/crates/ra_ide/test_data/highlight_unsafe.html | |||
@@ -37,18 +37,63 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
37 | </style> | 37 | </style> |
38 | <pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 38 | <pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> |
39 | 39 | ||
40 | <span class="keyword">union</span> <span class="union declaration">Union</span> <span class="punctuation">{</span> | ||
41 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u32</span><span class="punctuation">,</span> | ||
42 | <span class="field declaration">b</span><span class="punctuation">:</span> <span class="builtin_type">f32</span><span class="punctuation">,</span> | ||
43 | <span class="punctuation">}</span> | ||
44 | |||
40 | <span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> | 45 | <span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span><span class="punctuation">;</span> |
41 | 46 | ||
42 | <span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> | 47 | <span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> <span class="punctuation">{</span> |
43 | <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 48 | <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> |
44 | <span class="punctuation">}</span> | 49 | <span class="punctuation">}</span> |
45 | 50 | ||
51 | <span class="keyword">struct</span> <span class="struct declaration">TypeForStaticMut</span> <span class="punctuation">{</span> | ||
52 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u8</span> | ||
53 | <span class="punctuation">}</span> | ||
54 | |||
55 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">global_mut</span><span class="punctuation">:</span> <span class="struct">TypeForStaticMut</span> <span class="operator">=</span> <span class="struct">TypeForStaticMut</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | ||
56 | |||
57 | <span class="attribute">#</span><span class="attribute">[</span><span class="function attribute">repr</span><span class="punctuation">(</span><span class="attribute">packed</span><span class="punctuation">)</span><span class="attribute">]</span> | ||
58 | <span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="punctuation">{</span> | ||
59 | <span class="field declaration">a</span><span class="punctuation">:</span> <span class="builtin_type">u16</span><span class="punctuation">,</span> | ||
60 | <span class="punctuation">}</span> | ||
61 | |||
62 | <span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="punctuation">{</span> | ||
63 | <span class="keyword">fn</span> <span class="function declaration">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span><span class="punctuation">;</span> | ||
64 | <span class="punctuation">}</span> | ||
65 | |||
66 | <span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="punctuation">{</span> | ||
67 | <span class="keyword">fn</span> <span class="function declaration">calls_autoref</span><span class="punctuation">(</span><span class="operator">&</span><span class="self_keyword">self</span><span class="punctuation">)</span> <span class="punctuation">{</span><span class="punctuation">}</span> | ||
68 | <span class="punctuation">}</span> | ||
69 | |||
46 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 70 | <span class="keyword">fn</span> <span class="function declaration">main</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="punctuation">{</span> |
47 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span> | 71 | <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="punctuation">;</span> |
72 | <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="punctuation">{</span> <span class="field">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | ||
48 | <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> | 73 | <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> |
74 | <span class="comment">// unsafe fn and method calls</span> | ||
49 | <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 75 | <span class="function unsafe">unsafe_fn</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> |
76 | <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="punctuation">.</span><span class="field unsafe">b</span><span class="punctuation">;</span> | ||
77 | <span class="keyword control">match</span> <span class="variable">u</span> <span class="punctuation">{</span> | ||
78 | <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">b</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span> <span class="operator">=></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> | ||
79 | <span class="union">Union</span> <span class="punctuation">{</span> <span class="field unsafe">a</span> <span class="punctuation">}</span> <span class="operator">=></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">,</span> | ||
80 | <span class="punctuation">}</span> | ||
50 | <span class="struct">HasUnsafeFn</span><span class="punctuation">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | 81 | <span class="struct">HasUnsafeFn</span><span class="punctuation">.</span><span class="function unsafe">unsafe_method</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> |
51 | <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="punctuation">(</span><span class="variable">x</span><span class="punctuation">)</span><span class="punctuation">;</span> | 82 | |
52 | <span class="keyword">let</span> <span class="variable declaration">z</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="variable">x</span><span class="punctuation">;</span> | 83 | <span class="comment">// unsafe deref</span> |
84 | <span class="keyword">let</span> <span class="variable declaration">y</span> <span class="operator">=</span> <span class="operator unsafe">*</span><span class="variable">x</span><span class="punctuation">;</span> | ||
85 | |||
86 | <span class="comment">// unsafe access to a static mut</span> | ||
87 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="static mutable unsafe">global_mut</span><span class="punctuation">.</span><span class="field">a</span><span class="punctuation">;</span> | ||
88 | |||
89 | <span class="comment">// unsafe ref of packed fields</span> | ||
90 | <span class="keyword">let</span> <span class="variable declaration">packed</span> <span class="operator">=</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="numeric_literal">0</span> <span class="punctuation">}</span><span class="punctuation">;</span> | ||
91 | <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="operator unsafe">&</span><span class="variable">packed</span><span class="punctuation">.</span><span class="field">a</span><span class="punctuation">;</span> | ||
92 | <span class="keyword">let</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">.</span><span class="field">a</span><span class="punctuation">;</span> | ||
93 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="keyword unsafe">ref</span> <span class="field">a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> | ||
94 | <span class="keyword">let</span> <span class="struct">Packed</span> <span class="punctuation">{</span> <span class="field">a</span><span class="punctuation">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="punctuation">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="punctuation">;</span> | ||
95 | |||
96 | <span class="comment">// unsafe auto ref of packed field</span> | ||
97 | <span class="variable">packed</span><span class="punctuation">.</span><span class="field">a</span><span class="punctuation">.</span><span class="function unsafe">calls_autoref</span><span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">;</span> | ||
53 | <span class="punctuation">}</span> | 98 | <span class="punctuation">}</span> |
54 | <span class="punctuation">}</span></code></pre> \ No newline at end of file | 99 | <span class="punctuation">}</span></code></pre> \ No newline at end of file |
diff --git a/crates/ra_ide/test_data/highlighting.html b/crates/ra_ide/test_data/highlighting.html index 23c25ad8c..8e0160eee 100644 --- a/crates/ra_ide/test_data/highlighting.html +++ b/crates/ra_ide/test_data/highlighting.html | |||
@@ -64,7 +64,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
64 | <span class="punctuation">}</span> | 64 | <span class="punctuation">}</span> |
65 | <span class="punctuation">}</span> | 65 | <span class="punctuation">}</span> |
66 | 66 | ||
67 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> | 67 | <span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">STATIC_MUT</span><span class="punctuation">:</span> <span class="builtin_type">i32</span> <span class="operator">=</span> <span class="numeric_literal">0</span><span class="punctuation">;</span> |
68 | 68 | ||
69 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation"><</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="type_param">T</span> <span class="punctuation">{</span> | 69 | <span class="keyword">fn</span> <span class="function declaration">foo</span><span class="punctuation"><</span><span class="lifetime declaration">'a</span><span class="punctuation">,</span> <span class="type_param declaration">T</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="type_param">T</span> <span class="punctuation">{</span> |
70 | <span class="function">foo</span><span class="operator">::</span><span class="punctuation"><</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> | 70 | <span class="function">foo</span><span class="operator">::</span><span class="punctuation"><</span><span class="lifetime">'a</span><span class="punctuation">,</span> <span class="builtin_type">i32</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> |
@@ -97,7 +97,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
97 | <span class="punctuation">}</span> | 97 | <span class="punctuation">}</span> |
98 | <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> | 98 | <span class="keyword unsafe">unsafe</span> <span class="punctuation">{</span> |
99 | <span class="variable mutable">vec</span><span class="punctuation">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span> | 99 | <span class="variable mutable">vec</span><span class="punctuation">.</span><span class="unresolved_reference">set_len</span><span class="punctuation">(</span><span class="numeric_literal">0</span><span class="punctuation">)</span><span class="punctuation">;</span> |
100 | <span class="static mutable">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span> | 100 | <span class="static mutable unsafe">STATIC_MUT</span> <span class="operator">=</span> <span class="numeric_literal">1</span><span class="punctuation">;</span> |
101 | <span class="punctuation">}</span> | 101 | <span class="punctuation">}</span> |
102 | 102 | ||
103 | <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span> | 103 | <span class="keyword control">for</span> <span class="variable declaration">e</span> <span class="keyword control">in</span> <span class="variable mutable">vec</span> <span class="punctuation">{</span> |
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index b51000b03..9bb95277d 100644 --- a/crates/ra_ide_db/src/defs.rs +++ b/crates/ra_ide_db/src/defs.rs | |||
@@ -6,8 +6,8 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, Name, PathResolution, | 9 | db::HirDatabase, Crate, Field, HasVisibility, ImplDef, Local, MacroDef, Module, ModuleDef, |
10 | Semantics, TypeParam, Visibility, | 10 | Name, PathResolution, Semantics, TypeParam, Visibility, |
11 | }; | 11 | }; |
12 | use ra_prof::profile; | 12 | use ra_prof::profile; |
13 | use ra_syntax::{ | 13 | use ra_syntax::{ |
@@ -80,6 +80,7 @@ impl Definition { | |||
80 | 80 | ||
81 | #[derive(Debug)] | 81 | #[derive(Debug)] |
82 | pub enum NameClass { | 82 | pub enum NameClass { |
83 | ExternCrate(Crate), | ||
83 | Definition(Definition), | 84 | Definition(Definition), |
84 | /// `None` in `if let None = Some(82) {}` | 85 | /// `None` in `if let None = Some(82) {}` |
85 | ConstReference(Definition), | 86 | ConstReference(Definition), |
@@ -90,16 +91,18 @@ pub enum NameClass { | |||
90 | } | 91 | } |
91 | 92 | ||
92 | impl NameClass { | 93 | impl NameClass { |
93 | pub fn into_definition(self) -> Option<Definition> { | 94 | pub fn into_definition(self, db: &dyn HirDatabase) -> Option<Definition> { |
94 | match self { | 95 | Some(match self { |
95 | NameClass::Definition(it) => Some(it), | 96 | NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()), |
96 | NameClass::ConstReference(_) => None, | 97 | NameClass::Definition(it) => it, |
97 | NameClass::FieldShorthand { local, field: _ } => Some(Definition::Local(local)), | 98 | NameClass::ConstReference(_) => return None, |
98 | } | 99 | NameClass::FieldShorthand { local, field: _ } => Definition::Local(local), |
100 | }) | ||
99 | } | 101 | } |
100 | 102 | ||
101 | pub fn definition(self) -> Definition { | 103 | pub fn definition(self, db: &dyn HirDatabase) -> Definition { |
102 | match self { | 104 | match self { |
105 | NameClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()), | ||
103 | NameClass::Definition(it) | NameClass::ConstReference(it) => it, | 106 | NameClass::Definition(it) | NameClass::ConstReference(it) => it, |
104 | NameClass::FieldShorthand { local: _, field } => field, | 107 | NameClass::FieldShorthand { local: _, field } => field, |
105 | } | 108 | } |
@@ -120,32 +123,37 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option | |||
120 | match_ast! { | 123 | match_ast! { |
121 | match parent { | 124 | match parent { |
122 | ast::Rename(it) => { | 125 | ast::Rename(it) => { |
123 | let use_tree = it.syntax().parent().and_then(ast::UseTree::cast)?; | 126 | if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) { |
124 | let path = use_tree.path()?; | 127 | let path = use_tree.path()?; |
125 | let path_segment = path.segment()?; | 128 | let path_segment = path.segment()?; |
126 | let name_ref_class = path_segment | 129 | let name_ref_class = path_segment |
127 | .name_ref() | 130 | .name_ref() |
128 | // The rename might be from a `self` token, so fallback to the name higher | 131 | // The rename might be from a `self` token, so fallback to the name higher |
129 | // in the use tree. | 132 | // in the use tree. |
130 | .or_else(||{ | 133 | .or_else(||{ |
131 | if path_segment.self_token().is_none() { | 134 | if path_segment.self_token().is_none() { |
132 | return None; | 135 | return None; |
133 | } | 136 | } |
134 | 137 | ||
135 | let use_tree = use_tree | 138 | let use_tree = use_tree |
136 | .syntax() | 139 | .syntax() |
137 | .parent() | 140 | .parent() |
138 | .as_ref() | 141 | .as_ref() |
139 | // Skip over UseTreeList | 142 | // Skip over UseTreeList |
140 | .and_then(SyntaxNode::parent) | 143 | .and_then(SyntaxNode::parent) |
141 | .and_then(ast::UseTree::cast)?; | 144 | .and_then(ast::UseTree::cast)?; |
142 | let path = use_tree.path()?; | 145 | let path = use_tree.path()?; |
143 | let path_segment = path.segment()?; | 146 | let path_segment = path.segment()?; |
144 | path_segment.name_ref() | 147 | path_segment.name_ref() |
145 | }) | 148 | }) |
146 | .and_then(|name_ref| classify_name_ref(sema, &name_ref))?; | 149 | .and_then(|name_ref| classify_name_ref(sema, &name_ref))?; |
147 | 150 | ||
148 | Some(NameClass::Definition(name_ref_class.definition())) | 151 | Some(NameClass::Definition(name_ref_class.definition(sema.db))) |
152 | } else { | ||
153 | let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?; | ||
154 | let resolved = sema.resolve_extern_crate(&extern_crate)?; | ||
155 | Some(NameClass::ExternCrate(resolved)) | ||
156 | } | ||
149 | }, | 157 | }, |
150 | ast::IdentPat(it) => { | 158 | ast::IdentPat(it) => { |
151 | let local = sema.to_def(&it)?; | 159 | let local = sema.to_def(&it)?; |
@@ -220,13 +228,15 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option | |||
220 | 228 | ||
221 | #[derive(Debug)] | 229 | #[derive(Debug)] |
222 | pub enum NameRefClass { | 230 | pub enum NameRefClass { |
231 | ExternCrate(Crate), | ||
223 | Definition(Definition), | 232 | Definition(Definition), |
224 | FieldShorthand { local: Local, field: Definition }, | 233 | FieldShorthand { local: Local, field: Definition }, |
225 | } | 234 | } |
226 | 235 | ||
227 | impl NameRefClass { | 236 | impl NameRefClass { |
228 | pub fn definition(self) -> Definition { | 237 | pub fn definition(self, db: &dyn HirDatabase) -> Definition { |
229 | match self { | 238 | match self { |
239 | NameRefClass::ExternCrate(krate) => Definition::ModuleDef(krate.root_module(db).into()), | ||
230 | NameRefClass::Definition(def) => def, | 240 | NameRefClass::Definition(def) => def, |
231 | NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local), | 241 | NameRefClass::FieldShorthand { local, field: _ } => Definition::Local(local), |
232 | } | 242 | } |
@@ -307,9 +317,15 @@ pub fn classify_name_ref( | |||
307 | } | 317 | } |
308 | } | 318 | } |
309 | 319 | ||
310 | let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; | 320 | if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) { |
311 | let resolved = sema.resolve_path(&path)?; | 321 | if let Some(resolved) = sema.resolve_path(&path) { |
312 | Some(NameRefClass::Definition(resolved.into())) | 322 | return Some(NameRefClass::Definition(resolved.into())); |
323 | } | ||
324 | } | ||
325 | |||
326 | let extern_crate = ast::ExternCrate::cast(parent)?; | ||
327 | let resolved = sema.resolve_extern_crate(&extern_crate)?; | ||
328 | Some(NameRefClass::ExternCrate(resolved)) | ||
313 | } | 329 | } |
314 | 330 | ||
315 | impl From<PathResolution> for Definition { | 331 | impl From<PathResolution> for Definition { |
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs index 1fba71ff8..9e040973b 100644 --- a/crates/ra_ide_db/src/imports_locator.rs +++ b/crates/ra_ide_db/src/imports_locator.rs | |||
@@ -61,5 +61,5 @@ fn get_name_definition<'a>( | |||
61 | candidate_node | 61 | candidate_node |
62 | }; | 62 | }; |
63 | let name = ast::Name::cast(candidate_name_node)?; | 63 | let name = ast::Name::cast(candidate_name_node)?; |
64 | classify_name(sema, &name)?.into_definition() | 64 | classify_name(sema, &name)?.into_definition(sema.db) |
65 | } | 65 | } |
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs index f9e515b81..933a3a3b5 100644 --- a/crates/ra_mbe/src/mbe_expander/matcher.rs +++ b/crates/ra_mbe/src/mbe_expander/matcher.rs | |||
@@ -276,7 +276,7 @@ impl<'a> TtIter<'a> { | |||
276 | Ok(tt::Subtree { | 276 | Ok(tt::Subtree { |
277 | delimiter: None, | 277 | delimiter: None, |
278 | token_trees: vec![ | 278 | token_trees: vec![ |
279 | tt::Leaf::Punct(punct.clone()).into(), | 279 | tt::Leaf::Punct(*punct).into(), |
280 | tt::Leaf::Ident(ident.clone()).into(), | 280 | tt::Leaf::Ident(ident.clone()).into(), |
281 | ], | 281 | ], |
282 | } | 282 | } |
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index c2e1d701e..88468bc97 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs | |||
@@ -110,7 +110,7 @@ pub(crate) mod fragments { | |||
110 | } | 110 | } |
111 | 111 | ||
112 | pub(crate) fn item(p: &mut Parser) { | 112 | pub(crate) fn item(p: &mut Parser) { |
113 | items::item_or_macro(p, true, items::ItemFlavor::Mod) | 113 | items::item_or_macro(p, true) |
114 | } | 114 | } |
115 | 115 | ||
116 | pub(crate) fn macro_items(p: &mut Parser) { | 116 | pub(crate) fn macro_items(p: &mut Parser) { |
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index e1c25a838..3291e3f14 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -73,7 +73,7 @@ pub(super) fn stmt(p: &mut Parser, with_semi: StmtWithSemi) { | |||
73 | 73 | ||
74 | // test block_items | 74 | // test block_items |
75 | // fn a() { fn b() {} } | 75 | // fn a() { fn b() {} } |
76 | let m = match items::maybe_item(p, m, items::ItemFlavor::Mod) { | 76 | let m = match items::maybe_item(p, m) { |
77 | Ok(()) => return, | 77 | Ok(()) => return, |
78 | Err(m) => m, | 78 | Err(m) => m, |
79 | }; | 79 | }; |
@@ -509,7 +509,6 @@ fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
509 | // x.1i32; | 509 | // x.1i32; |
510 | // x.0x01; | 510 | // x.0x01; |
511 | // } | 511 | // } |
512 | #[allow(clippy::if_same_then_else)] | ||
513 | fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | 512 | fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { |
514 | assert!(p.at(T![.])); | 513 | assert!(p.at(T![.])); |
515 | let m = lhs.precede(p); | 514 | let m = lhs.precede(p); |
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index cca524cea..d091b0fbb 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs | |||
@@ -22,24 +22,19 @@ use super::*; | |||
22 | pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { | 22 | pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { |
23 | attributes::inner_attributes(p); | 23 | attributes::inner_attributes(p); |
24 | while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) { | 24 | while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) { |
25 | item_or_macro(p, stop_on_r_curly, ItemFlavor::Mod) | 25 | item_or_macro(p, stop_on_r_curly) |
26 | } | 26 | } |
27 | } | 27 | } |
28 | 28 | ||
29 | pub(super) enum ItemFlavor { | ||
30 | Mod, | ||
31 | Trait, | ||
32 | } | ||
33 | |||
34 | pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ | 29 | pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ |
35 | FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, | 30 | FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, |
36 | CRATE_KW, USE_KW, MACRO_KW | 31 | CRATE_KW, USE_KW, MACRO_KW |
37 | ]; | 32 | ]; |
38 | 33 | ||
39 | pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { | 34 | pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) { |
40 | let m = p.start(); | 35 | let m = p.start(); |
41 | attributes::outer_attributes(p); | 36 | attributes::outer_attributes(p); |
42 | let m = match maybe_item(p, m, flavor) { | 37 | let m = match maybe_item(p, m) { |
43 | Ok(()) => { | 38 | Ok(()) => { |
44 | if p.at(T![;]) { | 39 | if p.at(T![;]) { |
45 | p.err_and_bump( | 40 | p.err_and_bump( |
@@ -76,7 +71,7 @@ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemF | |||
76 | } | 71 | } |
77 | } | 72 | } |
78 | 73 | ||
79 | pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Result<(), Marker> { | 74 | pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { |
80 | // test_err pub_expr | 75 | // test_err pub_expr |
81 | // fn foo() { pub 92; } | 76 | // fn foo() { pub 92; } |
82 | let has_visibility = opt_visibility(p); | 77 | let has_visibility = opt_visibility(p); |
@@ -114,38 +109,31 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul | |||
114 | has_mods = true; | 109 | has_mods = true; |
115 | } | 110 | } |
116 | 111 | ||
117 | if p.at(IDENT) | 112 | // test default_item |
118 | && p.at_contextual_kw("default") | 113 | // default impl T for Foo {} |
119 | && (match p.nth(1) { | 114 | if p.at(IDENT) && p.at_contextual_kw("default") { |
120 | T![impl] => true, | 115 | match p.nth(1) { |
116 | T![fn] | T![type] | T![const] | T![impl] => { | ||
117 | p.bump_remap(T![default]); | ||
118 | has_mods = true; | ||
119 | } | ||
121 | T![unsafe] => { | 120 | T![unsafe] => { |
122 | // test default_unsafe_impl | 121 | // test default_unsafe_item |
123 | // default unsafe impl Foo {} | 122 | // default unsafe impl T for Foo { |
124 | |||
125 | // test default_unsafe_fn | ||
126 | // impl T for Foo { | ||
127 | // default unsafe fn foo() {} | 123 | // default unsafe fn foo() {} |
128 | // } | 124 | // } |
129 | if p.nth(2) == T![impl] || p.nth(2) == T![fn] { | 125 | if matches!(p.nth(2), T![impl] | T![fn]) { |
130 | p.bump_remap(T![default]); | 126 | p.bump_remap(T![default]); |
131 | p.bump(T![unsafe]); | 127 | p.bump(T![unsafe]); |
132 | has_mods = true; | 128 | has_mods = true; |
133 | } | 129 | } |
134 | false | ||
135 | } | 130 | } |
136 | T![fn] | T![type] | T![const] => { | 131 | _ => (), |
137 | if let ItemFlavor::Mod = flavor { | 132 | } |
138 | true | ||
139 | } else { | ||
140 | false | ||
141 | } | ||
142 | } | ||
143 | _ => false, | ||
144 | }) | ||
145 | { | ||
146 | p.bump_remap(T![default]); | ||
147 | has_mods = true; | ||
148 | } | 133 | } |
134 | |||
135 | // test existential_type | ||
136 | // existential type Foo: Fn() -> usize; | ||
149 | if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] { | 137 | if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] { |
150 | p.bump_remap(T![existential]); | 138 | p.bump_remap(T![existential]); |
151 | has_mods = true; | 139 | has_mods = true; |
@@ -153,79 +141,31 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul | |||
153 | 141 | ||
154 | // items | 142 | // items |
155 | match p.current() { | 143 | match p.current() { |
156 | // test async_fn | 144 | // test fn |
157 | // async fn foo() {} | 145 | // fn foo() {} |
158 | |||
159 | // test extern_fn | ||
160 | // extern fn foo() {} | ||
161 | |||
162 | // test const_fn | ||
163 | // const fn foo() {} | ||
164 | |||
165 | // test const_unsafe_fn | ||
166 | // const unsafe fn foo() {} | ||
167 | |||
168 | // test unsafe_extern_fn | ||
169 | // unsafe extern "C" fn foo() {} | ||
170 | |||
171 | // test unsafe_fn | ||
172 | // unsafe fn foo() {} | ||
173 | |||
174 | // test combined_fns | ||
175 | // async unsafe fn foo() {} | ||
176 | // const unsafe fn bar() {} | ||
177 | |||
178 | // test_err wrong_order_fns | ||
179 | // unsafe async fn foo() {} | ||
180 | // unsafe const fn bar() {} | ||
181 | T![fn] => { | 146 | T![fn] => { |
182 | fn_def(p); | 147 | fn_def(p); |
183 | m.complete(p, FN); | 148 | m.complete(p, FN); |
184 | } | 149 | } |
185 | 150 | ||
186 | // test unsafe_trait | 151 | // test trait |
187 | // unsafe trait T {} | 152 | // trait T {} |
188 | |||
189 | // test auto_trait | ||
190 | // auto trait T {} | ||
191 | |||
192 | // test unsafe_auto_trait | ||
193 | // unsafe auto trait T {} | ||
194 | T![trait] => { | 153 | T![trait] => { |
195 | traits::trait_def(p); | 154 | traits::trait_def(p); |
196 | m.complete(p, TRAIT); | 155 | m.complete(p, TRAIT); |
197 | } | 156 | } |
198 | 157 | ||
199 | // test unsafe_impl | ||
200 | // unsafe impl Foo {} | ||
201 | |||
202 | // test default_impl | ||
203 | // default impl Foo {} | ||
204 | |||
205 | // test_err default_fn_type | ||
206 | // trait T { | ||
207 | // default type T = Bar; | ||
208 | // default fn foo() {} | ||
209 | // } | ||
210 | |||
211 | // test default_fn_type | ||
212 | // impl T for Foo { | ||
213 | // default type T = Bar; | ||
214 | // default fn foo() {} | ||
215 | // } | ||
216 | T![const] => { | 158 | T![const] => { |
217 | consts::const_def(p, m); | 159 | consts::const_def(p, m); |
218 | } | 160 | } |
219 | 161 | ||
220 | // test unsafe_default_impl | 162 | // test impl |
221 | // unsafe default impl Foo {} | 163 | // impl T for S {} |
222 | T![impl] => { | 164 | T![impl] => { |
223 | traits::impl_def(p); | 165 | traits::impl_def(p); |
224 | m.complete(p, IMPL); | 166 | m.complete(p, IMPL); |
225 | } | 167 | } |
226 | 168 | ||
227 | // test existential_type | ||
228 | // existential type Foo: Fn() -> usize; | ||
229 | T![type] => { | 169 | T![type] => { |
230 | type_def(p, m); | 170 | type_def(p, m); |
231 | } | 171 | } |
diff --git a/crates/ra_parser/src/grammar/items/traits.rs b/crates/ra_parser/src/grammar/items/traits.rs index ef9c8ff5b..751ce65f2 100644 --- a/crates/ra_parser/src/grammar/items/traits.rs +++ b/crates/ra_parser/src/grammar/items/traits.rs | |||
@@ -47,7 +47,7 @@ pub(crate) fn trait_item_list(p: &mut Parser) { | |||
47 | error_block(p, "expected an item"); | 47 | error_block(p, "expected an item"); |
48 | continue; | 48 | continue; |
49 | } | 49 | } |
50 | item_or_macro(p, true, ItemFlavor::Trait); | 50 | item_or_macro(p, true); |
51 | } | 51 | } |
52 | p.expect(T!['}']); | 52 | p.expect(T!['}']); |
53 | m.complete(p, ASSOC_ITEM_LIST); | 53 | m.complete(p, ASSOC_ITEM_LIST); |
@@ -104,7 +104,7 @@ pub(crate) fn impl_item_list(p: &mut Parser) { | |||
104 | error_block(p, "expected an item"); | 104 | error_block(p, "expected an item"); |
105 | continue; | 105 | continue; |
106 | } | 106 | } |
107 | item_or_macro(p, true, ItemFlavor::Mod); | 107 | item_or_macro(p, true); |
108 | } | 108 | } |
109 | p.expect(T!['}']); | 109 | p.expect(T!['}']); |
110 | m.complete(p, ASSOC_ITEM_LIST); | 110 | m.complete(p, ASSOC_ITEM_LIST); |
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs index d797f2cc9..d2487acc3 100644 --- a/crates/ra_parser/src/parser.rs +++ b/crates/ra_parser/src/parser.rs | |||
@@ -269,8 +269,8 @@ impl Marker { | |||
269 | pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker { | 269 | pub(crate) fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker { |
270 | self.bomb.defuse(); | 270 | self.bomb.defuse(); |
271 | let idx = self.pos as usize; | 271 | let idx = self.pos as usize; |
272 | match p.events[idx] { | 272 | match &mut p.events[idx] { |
273 | Event::Start { kind: ref mut slot, .. } => { | 273 | Event::Start { kind: slot, .. } => { |
274 | *slot = kind; | 274 | *slot = kind; |
275 | } | 275 | } |
276 | _ => unreachable!(), | 276 | _ => unreachable!(), |
@@ -320,8 +320,8 @@ impl CompletedMarker { | |||
320 | pub(crate) fn precede(self, p: &mut Parser) -> Marker { | 320 | pub(crate) fn precede(self, p: &mut Parser) -> Marker { |
321 | let new_pos = p.start(); | 321 | let new_pos = p.start(); |
322 | let idx = self.start_pos as usize; | 322 | let idx = self.start_pos as usize; |
323 | match p.events[idx] { | 323 | match &mut p.events[idx] { |
324 | Event::Start { ref mut forward_parent, .. } => { | 324 | Event::Start { forward_parent, .. } => { |
325 | *forward_parent = Some(new_pos.pos - self.start_pos); | 325 | *forward_parent = Some(new_pos.pos - self.start_pos); |
326 | } | 326 | } |
327 | _ => unreachable!(), | 327 | _ => unreachable!(), |
@@ -333,12 +333,12 @@ impl CompletedMarker { | |||
333 | pub(crate) fn undo_completion(self, p: &mut Parser) -> Marker { | 333 | pub(crate) fn undo_completion(self, p: &mut Parser) -> Marker { |
334 | let start_idx = self.start_pos as usize; | 334 | let start_idx = self.start_pos as usize; |
335 | let finish_idx = self.finish_pos as usize; | 335 | let finish_idx = self.finish_pos as usize; |
336 | match p.events[start_idx] { | 336 | match &mut p.events[start_idx] { |
337 | Event::Start { ref mut kind, forward_parent: None } => *kind = TOMBSTONE, | 337 | Event::Start { kind, forward_parent: None } => *kind = TOMBSTONE, |
338 | _ => unreachable!(), | 338 | _ => unreachable!(), |
339 | } | 339 | } |
340 | match p.events[finish_idx] { | 340 | match &mut p.events[finish_idx] { |
341 | ref mut slot @ Event::Finish => *slot = Event::tombstone(), | 341 | slot @ Event::Finish => *slot = Event::tombstone(), |
342 | _ => unreachable!(), | 342 | _ => unreachable!(), |
343 | } | 343 | } |
344 | Marker::new(self.start_pos) | 344 | Marker::new(self.start_pos) |
diff --git a/crates/ra_proc_macro/src/process.rs b/crates/ra_proc_macro/src/process.rs index 5bcdacb48..37dd3f496 100644 --- a/crates/ra_proc_macro/src/process.rs +++ b/crates/ra_proc_macro/src/process.rs | |||
@@ -90,7 +90,7 @@ impl ProcMacroProcessSrv { | |||
90 | } | 90 | } |
91 | Some(it) => it, | 91 | Some(it) => it, |
92 | }; | 92 | }; |
93 | sender.send(Task { req: req.into(), result_tx }).unwrap(); | 93 | sender.send(Task { req, result_tx }).unwrap(); |
94 | let res = result_rx | 94 | let res = result_rx |
95 | .recv() | 95 | .recv() |
96 | .map_err(|_| ra_tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?; | 96 | .map_err(|_| ra_tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?; |
diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs index c2ecbd33c..83390212a 100644 --- a/crates/ra_prof/src/memory_usage.rs +++ b/crates/ra_prof/src/memory_usage.rs | |||
@@ -24,7 +24,7 @@ impl std::ops::Sub for MemoryUsage { | |||
24 | impl MemoryUsage { | 24 | impl MemoryUsage { |
25 | pub fn current() -> MemoryUsage { | 25 | pub fn current() -> MemoryUsage { |
26 | cfg_if! { | 26 | cfg_if! { |
27 | if #[cfg(target_os = "linux")] { | 27 | if #[cfg(all(target_os = "linux", target_env = "gnu"))] { |
28 | // Note: This is incredibly slow. | 28 | // Note: This is incredibly slow. |
29 | let alloc = unsafe { libc::mallinfo() }.uordblks as isize; | 29 | let alloc = unsafe { libc::mallinfo() }.uordblks as isize; |
30 | MemoryUsage { allocated: Bytes(alloc) } | 30 | MemoryUsage { allocated: Bytes(alloc) } |
diff --git a/crates/ra_ssr/src/resolving.rs b/crates/ra_ssr/src/resolving.rs index df60048eb..d53bd46c7 100644 --- a/crates/ra_ssr/src/resolving.rs +++ b/crates/ra_ssr/src/resolving.rs | |||
@@ -5,7 +5,7 @@ use crate::{parsing, SsrError}; | |||
5 | use parsing::Placeholder; | 5 | use parsing::Placeholder; |
6 | use ra_db::FilePosition; | 6 | use ra_db::FilePosition; |
7 | use ra_syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken}; | 7 | use ra_syntax::{ast, SmolStr, SyntaxKind, SyntaxNode, SyntaxToken}; |
8 | use rustc_hash::{FxHashMap, FxHashSet}; | 8 | use rustc_hash::FxHashMap; |
9 | use test_utils::mark; | 9 | use test_utils::mark; |
10 | 10 | ||
11 | pub(crate) struct ResolutionScope<'db> { | 11 | pub(crate) struct ResolutionScope<'db> { |
@@ -124,8 +124,10 @@ impl Resolver<'_, '_> { | |||
124 | .resolution_scope | 124 | .resolution_scope |
125 | .resolve_path(&path) | 125 | .resolve_path(&path) |
126 | .ok_or_else(|| error!("Failed to resolve path `{}`", node.text()))?; | 126 | .ok_or_else(|| error!("Failed to resolve path `{}`", node.text()))?; |
127 | resolved_paths.insert(node, ResolvedPath { resolution, depth }); | 127 | if self.ok_to_use_path_resolution(&resolution) { |
128 | return Ok(()); | 128 | resolved_paths.insert(node, ResolvedPath { resolution, depth }); |
129 | return Ok(()); | ||
130 | } | ||
129 | } | 131 | } |
130 | } | 132 | } |
131 | for node in node.children() { | 133 | for node in node.children() { |
@@ -149,6 +151,27 @@ impl Resolver<'_, '_> { | |||
149 | } | 151 | } |
150 | false | 152 | false |
151 | } | 153 | } |
154 | |||
155 | fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool { | ||
156 | match resolution { | ||
157 | hir::PathResolution::AssocItem(hir::AssocItem::Function(function)) => { | ||
158 | if function.has_self_param(self.resolution_scope.scope.db) { | ||
159 | // If we don't use this path resolution, then we won't be able to match method | ||
160 | // calls. e.g. `Foo::bar($s)` should match `x.bar()`. | ||
161 | true | ||
162 | } else { | ||
163 | mark::hit!(replace_associated_trait_default_function_call); | ||
164 | false | ||
165 | } | ||
166 | } | ||
167 | hir::PathResolution::AssocItem(_) => { | ||
168 | // Not a function. Could be a constant or an associated type. | ||
169 | mark::hit!(replace_associated_trait_constant); | ||
170 | false | ||
171 | } | ||
172 | _ => true, | ||
173 | } | ||
174 | } | ||
152 | } | 175 | } |
153 | 176 | ||
154 | impl<'db> ResolutionScope<'db> { | 177 | impl<'db> ResolutionScope<'db> { |
@@ -195,7 +218,7 @@ impl<'db> ResolutionScope<'db> { | |||
195 | adt.ty(self.scope.db).iterate_path_candidates( | 218 | adt.ty(self.scope.db).iterate_path_candidates( |
196 | self.scope.db, | 219 | self.scope.db, |
197 | self.scope.module()?.krate(), | 220 | self.scope.module()?.krate(), |
198 | &FxHashSet::default(), | 221 | &self.scope.traits_in_scope(), |
199 | Some(hir_path.segments().last()?.name), | 222 | Some(hir_path.segments().last()?.name), |
200 | |_ty, assoc_item| Some(hir::PathResolution::AssocItem(assoc_item)), | 223 | |_ty, assoc_item| Some(hir::PathResolution::AssocItem(assoc_item)), |
201 | ) | 224 | ) |
diff --git a/crates/ra_ssr/src/tests.rs b/crates/ra_ssr/src/tests.rs index d483640df..7d4d470c0 100644 --- a/crates/ra_ssr/src/tests.rs +++ b/crates/ra_ssr/src/tests.rs | |||
@@ -550,6 +550,70 @@ fn replace_associated_function_call() { | |||
550 | } | 550 | } |
551 | 551 | ||
552 | #[test] | 552 | #[test] |
553 | fn replace_associated_trait_default_function_call() { | ||
554 | mark::check!(replace_associated_trait_default_function_call); | ||
555 | assert_ssr_transform( | ||
556 | "Bar2::foo() ==>> Bar2::foo2()", | ||
557 | r#" | ||
558 | trait Foo { fn foo() {} } | ||
559 | pub struct Bar {} | ||
560 | impl Foo for Bar {} | ||
561 | pub struct Bar2 {} | ||
562 | impl Foo for Bar2 {} | ||
563 | impl Bar2 { fn foo2() {} } | ||
564 | fn main() { | ||
565 | Bar::foo(); | ||
566 | Bar2::foo(); | ||
567 | } | ||
568 | "#, | ||
569 | expect![[r#" | ||
570 | trait Foo { fn foo() {} } | ||
571 | pub struct Bar {} | ||
572 | impl Foo for Bar {} | ||
573 | pub struct Bar2 {} | ||
574 | impl Foo for Bar2 {} | ||
575 | impl Bar2 { fn foo2() {} } | ||
576 | fn main() { | ||
577 | Bar::foo(); | ||
578 | Bar2::foo2(); | ||
579 | } | ||
580 | "#]], | ||
581 | ); | ||
582 | } | ||
583 | |||
584 | #[test] | ||
585 | fn replace_associated_trait_constant() { | ||
586 | mark::check!(replace_associated_trait_constant); | ||
587 | assert_ssr_transform( | ||
588 | "Bar2::VALUE ==>> Bar2::VALUE_2222", | ||
589 | r#" | ||
590 | trait Foo { const VALUE: i32; const VALUE_2222: i32; } | ||
591 | pub struct Bar {} | ||
592 | impl Foo for Bar { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; } | ||
593 | pub struct Bar2 {} | ||
594 | impl Foo for Bar2 { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; } | ||
595 | impl Bar2 { fn foo2() {} } | ||
596 | fn main() { | ||
597 | Bar::VALUE; | ||
598 | Bar2::VALUE; | ||
599 | } | ||
600 | "#, | ||
601 | expect![[r#" | ||
602 | trait Foo { const VALUE: i32; const VALUE_2222: i32; } | ||
603 | pub struct Bar {} | ||
604 | impl Foo for Bar { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; } | ||
605 | pub struct Bar2 {} | ||
606 | impl Foo for Bar2 { const VALUE: i32 = 1; const VALUE_2222: i32 = 2; } | ||
607 | impl Bar2 { fn foo2() {} } | ||
608 | fn main() { | ||
609 | Bar::VALUE; | ||
610 | Bar2::VALUE_2222; | ||
611 | } | ||
612 | "#]], | ||
613 | ); | ||
614 | } | ||
615 | |||
616 | #[test] | ||
553 | fn replace_path_in_different_contexts() { | 617 | fn replace_path_in_different_contexts() { |
554 | // Note the <|> inside module a::b which marks the point where the rule is interpreted. We | 618 | // Note the <|> inside module a::b which marks the point where the rule is interpreted. We |
555 | // replace foo with bar, but both need different path qualifiers in different contexts. In f4, | 619 | // replace foo with bar, but both need different path qualifiers in different contexts. In f4, |
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index 3a56b1674..0bdc22d95 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Various traits that are implemented by ast nodes. | 1 | //! Various traits that are implemented by ast nodes. |
2 | //! | 2 | //! |
3 | //! The implementations are usually trivial, and live in generated.rs | 3 | //! The implementations are usually trivial, and live in generated.rs |
4 | use stdx::SepBy; | 4 | use itertools::Itertools; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | ast::{self, support, AstChildren, AstNode, AstToken}, | 7 | ast::{self, support, AstChildren, AstNode, AstToken}, |
@@ -119,8 +119,7 @@ impl CommentIter { | |||
119 | // of a line in markdown. | 119 | // of a line in markdown. |
120 | line[pos..end].to_owned() | 120 | line[pos..end].to_owned() |
121 | }) | 121 | }) |
122 | .sep_by("\n") | 122 | .join("\n"); |
123 | .to_string(); | ||
124 | 123 | ||
125 | if has_comments { | 124 | if has_comments { |
126 | Some(docs) | 125 | Some(docs) |
diff --git a/crates/ra_syntax/test_data/parser/err/0043_default_const.rast b/crates/ra_syntax/test_data/parser/err/0043_default_const.rast deleted file mode 100644 index 51ad2a846..000000000 --- a/crates/ra_syntax/test_data/parser/err/0043_default_const.rast +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "trait" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "T" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] "\n " | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] "default" | ||
16 | [email protected] " " | ||
17 | [email protected] | ||
18 | [email protected] "const" | ||
19 | [email protected] " " | ||
20 | [email protected] | ||
21 | [email protected] "f" | ||
22 | [email protected] ":" | ||
23 | [email protected] " " | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] | ||
27 | [email protected] | ||
28 | [email protected] "u8" | ||
29 | [email protected] " " | ||
30 | [email protected] "=" | ||
31 | [email protected] " " | ||
32 | [email protected] | ||
33 | [email protected] "0" | ||
34 | [email protected] ";" | ||
35 | [email protected] "\n" | ||
36 | [email protected] "}" | ||
37 | [email protected] "\n" | ||
38 | error 19..19: expected BANG | ||
39 | error 19..19: expected `{`, `[`, `(` | ||
40 | error 19..19: expected SEMICOLON | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0043_default_const.rs b/crates/ra_syntax/test_data/parser/err/0043_default_const.rs deleted file mode 100644 index 80f15474a..000000000 --- a/crates/ra_syntax/test_data/parser/err/0043_default_const.rs +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | trait T { | ||
2 | default const f: u8 = 0; | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast b/crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rast index df29017e7..df29017e7 100644 --- a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rast +++ b/crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rast | |||
diff --git a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rs b/crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rs index 8fa324c1a..8fa324c1a 100644 --- a/crates/ra_syntax/test_data/parser/err/0163_weird_blocks.rs +++ b/crates/ra_syntax/test_data/parser/err/0043_weird_blocks.rs | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast b/crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rast index a6e6552a9..a6e6552a9 100644 --- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rast +++ b/crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rast | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs b/crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rs index 731e58013..731e58013 100644 --- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs +++ b/crates/ra_syntax/test_data/parser/err/0045_item_modifiers.rs | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast b/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast deleted file mode 100644 index acd72094b..000000000 --- a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rast +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "trait" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "T" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] "\n " | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] "default" | ||
16 | [email protected] " " | ||
17 | [email protected] | ||
18 | [email protected] "type" | ||
19 | [email protected] " " | ||
20 | [email protected] | ||
21 | [email protected] "T" | ||
22 | [email protected] " " | ||
23 | [email protected] "=" | ||
24 | [email protected] " " | ||
25 | [email protected] | ||
26 | [email protected] | ||
27 | [email protected] | ||
28 | [email protected] | ||
29 | [email protected] "Bar" | ||
30 | [email protected] ";" | ||
31 | [email protected] "\n " | ||
32 | [email protected] | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] | ||
36 | [email protected] "default" | ||
37 | [email protected] " " | ||
38 | [email protected] | ||
39 | [email protected] "fn" | ||
40 | [email protected] " " | ||
41 | [email protected] | ||
42 | [email protected] "foo" | ||
43 | [email protected] | ||
44 | [email protected] "(" | ||
45 | [email protected] ")" | ||
46 | [email protected] " " | ||
47 | [email protected] | ||
48 | [email protected] "{" | ||
49 | [email protected] "}" | ||
50 | [email protected] "\n" | ||
51 | [email protected] "}" | ||
52 | [email protected] "\n" | ||
53 | error 21..21: expected BANG | ||
54 | error 21..21: expected `{`, `[`, `(` | ||
55 | error 21..21: expected SEMICOLON | ||
56 | error 47..47: expected BANG | ||
57 | error 47..47: expected `{`, `[`, `(` | ||
58 | error 47..47: expected SEMICOLON | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rs b/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rs deleted file mode 100644 index 15ba8f4a8..000000000 --- a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.rs +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | trait T { | ||
2 | default type T = Bar; | ||
3 | default fn foo() {} | ||
4 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast deleted file mode 100644 index 625ab4c2d..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rast +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "unsafe" | ||
4 | [email protected] " " | ||
5 | [email protected] "trait" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] "T" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] "{" | ||
12 | [email protected] "}" | ||
13 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rs b/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rs deleted file mode 100644 index 04e021550..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0016_unsafe_trait.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | unsafe trait T {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast deleted file mode 100644 index 293b1d64c..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rast +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "unsafe" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "extern" | ||
7 | [email protected] " " | ||
8 | [email protected] "\"C\"" | ||
9 | [email protected] " " | ||
10 | [email protected] "fn" | ||
11 | [email protected] " " | ||
12 | [email protected] | ||
13 | [email protected] "foo" | ||
14 | [email protected] | ||
15 | [email protected] "(" | ||
16 | [email protected] ")" | ||
17 | [email protected] " " | ||
18 | [email protected] | ||
19 | [email protected] "{" | ||
20 | [email protected] "}" | ||
21 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rs deleted file mode 100644 index 1295c2cd2..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0036_unsafe_extern_fn.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | unsafe extern "C" fn foo() {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast deleted file mode 100644 index d6dfa83b7..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rast +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "unsafe" | ||
4 | [email protected] " " | ||
5 | [email protected] "default" | ||
6 | [email protected] " " | ||
7 | [email protected] "impl" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] "Foo" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] "{" | ||
17 | [email protected] "}" | ||
18 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rs deleted file mode 100644 index 9cd6c57bd..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0047_unsafe_default_impl.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | unsafe default impl Foo {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast deleted file mode 100644 index 97548a5ee..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rast +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "const" | ||
4 | [email protected] " " | ||
5 | [email protected] "fn" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] "foo" | ||
9 | [email protected] | ||
10 | [email protected] "(" | ||
11 | [email protected] ")" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] "{" | ||
15 | [email protected] "}" | ||
16 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rs deleted file mode 100644 index 8c84d9cd7..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0057_const_fn.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | const fn foo() {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast deleted file mode 100644 index 43c09affe..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rast +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "unsafe" | ||
4 | [email protected] " " | ||
5 | [email protected] "impl" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] | ||
10 | [email protected] | ||
11 | [email protected] "Foo" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] "{" | ||
15 | [email protected] "}" | ||
16 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rs deleted file mode 100644 index 41055f41d..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0087_unsafe_impl.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | unsafe impl Foo {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast deleted file mode 100644 index 405b6a259..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rast +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] "extern" | ||
5 | [email protected] " " | ||
6 | [email protected] "fn" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "foo" | ||
10 | [email protected] | ||
11 | [email protected] "(" | ||
12 | [email protected] ")" | ||
13 | [email protected] " " | ||
14 | [email protected] | ||
15 | [email protected] "{" | ||
16 | [email protected] "}" | ||
17 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rs deleted file mode 100644 index 394a049f0..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0089_extern_fn.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | extern fn foo() {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast deleted file mode 100644 index 0cac9ac43..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rast +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "auto" | ||
4 | [email protected] " " | ||
5 | [email protected] "trait" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] "T" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] "{" | ||
12 | [email protected] "}" | ||
13 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rs b/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rs deleted file mode 100644 index 72adf6035..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0091_auto_trait.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | auto trait T {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast deleted file mode 100644 index 0ef11c682..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rast +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "unsafe" | ||
4 | [email protected] " " | ||
5 | [email protected] "auto" | ||
6 | [email protected] " " | ||
7 | [email protected] "trait" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] "T" | ||
11 | [email protected] " " | ||
12 | [email protected] | ||
13 | [email protected] "{" | ||
14 | [email protected] "}" | ||
15 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rs b/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rs deleted file mode 100644 index 03d29f324..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0094_unsafe_auto_trait.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | unsafe auto trait T {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast deleted file mode 100644 index 0a1b21d6e..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rast +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "default" | ||
4 | [email protected] " " | ||
5 | [email protected] "impl" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] | ||
10 | [email protected] | ||
11 | [email protected] "Foo" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] "{" | ||
15 | [email protected] "}" | ||
16 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rs deleted file mode 100644 index ef6aa84a2..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0097_default_impl.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | default impl Foo {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast deleted file mode 100644 index 32a77ba49..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rast +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "const" | ||
4 | [email protected] " " | ||
5 | [email protected] "unsafe" | ||
6 | [email protected] " " | ||
7 | [email protected] "fn" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] "foo" | ||
11 | [email protected] | ||
12 | [email protected] "(" | ||
13 | [email protected] ")" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] "{" | ||
17 | [email protected] "}" | ||
18 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rs deleted file mode 100644 index 31a1e435f..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0098_const_unsafe_fn.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | const unsafe fn foo() {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast deleted file mode 100644 index 73c94e5d4..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rast +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "unsafe" | ||
4 | [email protected] " " | ||
5 | [email protected] "fn" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] "foo" | ||
9 | [email protected] | ||
10 | [email protected] "(" | ||
11 | [email protected] ")" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] "{" | ||
15 | [email protected] "}" | ||
16 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rs deleted file mode 100644 index 33cfc4cd7..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0101_unsafe_fn.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | unsafe fn foo() {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast deleted file mode 100644 index a7df188bd..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rast +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "async" | ||
4 | [email protected] " " | ||
5 | [email protected] "fn" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] "foo" | ||
9 | [email protected] | ||
10 | [email protected] "(" | ||
11 | [email protected] ")" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] "{" | ||
15 | [email protected] "}" | ||
16 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rs deleted file mode 100644 index f4adcb62b..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0124_async_fn.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | async fn foo() {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast deleted file mode 100644 index 98a20f36d..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rast +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "async" | ||
4 | [email protected] " " | ||
5 | [email protected] "unsafe" | ||
6 | [email protected] " " | ||
7 | [email protected] "fn" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] "foo" | ||
11 | [email protected] | ||
12 | [email protected] "(" | ||
13 | [email protected] ")" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] "{" | ||
17 | [email protected] "}" | ||
18 | [email protected] "\n" | ||
19 | [email protected] | ||
20 | [email protected] "const" | ||
21 | [email protected] " " | ||
22 | [email protected] "unsafe" | ||
23 | [email protected] " " | ||
24 | [email protected] "fn" | ||
25 | [email protected] " " | ||
26 | [email protected] | ||
27 | [email protected] "bar" | ||
28 | [email protected] | ||
29 | [email protected] "(" | ||
30 | [email protected] ")" | ||
31 | [email protected] " " | ||
32 | [email protected] | ||
33 | [email protected] "{" | ||
34 | [email protected] "}" | ||
35 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs deleted file mode 100644 index 126287145..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | async unsafe fn foo() {} | ||
2 | const unsafe fn bar() {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast b/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast deleted file mode 100644 index b8d26a53a..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rast +++ /dev/null | |||
@@ -1,55 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "impl" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] "T" | ||
10 | [email protected] " " | ||
11 | [email protected] "for" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] "Foo" | ||
18 | [email protected] " " | ||
19 | [email protected] | ||
20 | [email protected] "{" | ||
21 | [email protected] "\n " | ||
22 | [email protected] | ||
23 | [email protected] "default" | ||
24 | [email protected] " " | ||
25 | [email protected] "type" | ||
26 | [email protected] " " | ||
27 | [email protected] | ||
28 | [email protected] "T" | ||
29 | [email protected] " " | ||
30 | [email protected] "=" | ||
31 | [email protected] " " | ||
32 | [email protected] | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] | ||
36 | [email protected] "Bar" | ||
37 | [email protected] ";" | ||
38 | [email protected] "\n " | ||
39 | [email protected] | ||
40 | [email protected] "default" | ||
41 | [email protected] " " | ||
42 | [email protected] "fn" | ||
43 | [email protected] " " | ||
44 | [email protected] | ||
45 | [email protected] "foo" | ||
46 | [email protected] | ||
47 | [email protected] "(" | ||
48 | [email protected] ")" | ||
49 | [email protected] " " | ||
50 | [email protected] | ||
51 | [email protected] "{" | ||
52 | [email protected] "}" | ||
53 | [email protected] "\n" | ||
54 | [email protected] "}" | ||
55 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rs b/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rs deleted file mode 100644 index 8f5d61113..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0132_default_fn_type.rs +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | impl T for Foo { | ||
2 | default type T = Bar; | ||
3 | default fn foo() {} | ||
4 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rast new file mode 100644 index 000000000..23c4269b3 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rast | |||
@@ -0,0 +1,14 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "fn" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "foo" | ||
7 | [email protected] | ||
8 | [email protected] "(" | ||
9 | [email protected] ")" | ||
10 | [email protected] " " | ||
11 | [email protected] | ||
12 | [email protected] "{" | ||
13 | [email protected] "}" | ||
14 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rs new file mode 100644 index 000000000..8f3b7ef11 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0151_fn.rs | |||
@@ -0,0 +1 @@ | |||
fn foo() {} | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rast new file mode 100644 index 000000000..7968cf9ff --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rast | |||
@@ -0,0 +1,22 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "impl" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] "T" | ||
10 | [email protected] " " | ||
11 | [email protected] "for" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] "S" | ||
18 | [email protected] " " | ||
19 | [email protected] | ||
20 | [email protected] "{" | ||
21 | [email protected] "}" | ||
22 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rs new file mode 100644 index 000000000..a1a550d8a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0152_impl.rs | |||
@@ -0,0 +1 @@ | |||
impl T for S {} | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rast b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rast new file mode 100644 index 000000000..9881e5048 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rast | |||
@@ -0,0 +1,11 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "trait" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "T" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] "}" | ||
11 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rs b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rs new file mode 100644 index 000000000..8d183dbb5 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait.rs | |||
@@ -0,0 +1 @@ | |||
trait T {} | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast deleted file mode 100644 index 1269621dc..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rast +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "impl" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] "T" | ||
10 | [email protected] " " | ||
11 | [email protected] "for" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] "Foo" | ||
18 | [email protected] " " | ||
19 | [email protected] | ||
20 | [email protected] "{" | ||
21 | [email protected] "\n " | ||
22 | [email protected] | ||
23 | [email protected] "default" | ||
24 | [email protected] " " | ||
25 | [email protected] "unsafe" | ||
26 | [email protected] " " | ||
27 | [email protected] "fn" | ||
28 | [email protected] " " | ||
29 | [email protected] | ||
30 | [email protected] "foo" | ||
31 | [email protected] | ||
32 | [email protected] "(" | ||
33 | [email protected] ")" | ||
34 | [email protected] " " | ||
35 | [email protected] | ||
36 | [email protected] "{" | ||
37 | [email protected] "}" | ||
38 | [email protected] "\n" | ||
39 | [email protected] "}" | ||
40 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast deleted file mode 100644 index 6bfe925af..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rast +++ /dev/null | |||
@@ -1,18 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "default" | ||
4 | [email protected] " " | ||
5 | [email protected] "unsafe" | ||
6 | [email protected] " " | ||
7 | [email protected] "impl" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] "Foo" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] "{" | ||
17 | [email protected] "}" | ||
18 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs deleted file mode 100644 index ba0998ff4..000000000 --- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_impl.rs +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | default unsafe impl Foo {} | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rast b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rast new file mode 100644 index 000000000..f2e201460 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rast | |||
@@ -0,0 +1,44 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "default" | ||
4 | [email protected] " " | ||
5 | [email protected] "unsafe" | ||
6 | [email protected] " " | ||
7 | [email protected] "impl" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] "T" | ||
14 | [email protected] " " | ||
15 | [email protected] "for" | ||
16 | [email protected] " " | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] "Foo" | ||
22 | [email protected] " " | ||
23 | [email protected] | ||
24 | [email protected] "{" | ||
25 | [email protected] "\n " | ||
26 | [email protected] | ||
27 | [email protected] "default" | ||
28 | [email protected] " " | ||
29 | [email protected] "unsafe" | ||
30 | [email protected] " " | ||
31 | [email protected] "fn" | ||
32 | [email protected] " " | ||
33 | [email protected] | ||
34 | [email protected] "foo" | ||
35 | [email protected] | ||
36 | [email protected] "(" | ||
37 | [email protected] ")" | ||
38 | [email protected] " " | ||
39 | [email protected] | ||
40 | [email protected] "{" | ||
41 | [email protected] "}" | ||
42 | [email protected] "\n" | ||
43 | [email protected] "}" | ||
44 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rs index 12926cd8a..96340f84a 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_fn.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0163_default_unsafe_item.rs | |||
@@ -1,3 +1,3 @@ | |||
1 | impl T for Foo { | 1 | default unsafe impl T for Foo { |
2 | default unsafe fn foo() {} | 2 | default unsafe fn foo() {} |
3 | } | 3 | } |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rast b/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rast new file mode 100644 index 000000000..9282772f3 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rast | |||
@@ -0,0 +1,24 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "default" | ||
4 | [email protected] " " | ||
5 | [email protected] "impl" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] | ||
10 | [email protected] | ||
11 | [email protected] "T" | ||
12 | [email protected] " " | ||
13 | [email protected] "for" | ||
14 | [email protected] " " | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "Foo" | ||
20 | [email protected] " " | ||
21 | [email protected] | ||
22 | [email protected] "{" | ||
23 | [email protected] "}" | ||
24 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rs b/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rs new file mode 100644 index 000000000..a6836cbd5 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0164_default_item.rs | |||
@@ -0,0 +1 @@ | |||
default impl T for Foo {} | |||
diff --git a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast b/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast deleted file mode 100644 index 5524efaaf..000000000 --- a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rast +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] | ||
4 | [email protected] "extern" | ||
5 | [email protected] " " | ||
6 | [email protected] "fn" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "foo" | ||
10 | [email protected] | ||
11 | [email protected] "(" | ||
12 | [email protected] ")" | ||
13 | [email protected] " " | ||
14 | [email protected] | ||
15 | [email protected] "{" | ||
16 | [email protected] "\n" | ||
17 | [email protected] "}" | ||
18 | [email protected] "\n\n" | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] "extern" | ||
22 | [email protected] " " | ||
23 | [email protected] "\"C\"" | ||
24 | [email protected] " " | ||
25 | [email protected] "fn" | ||
26 | [email protected] " " | ||
27 | [email protected] | ||
28 | [email protected] "bar" | ||
29 | [email protected] | ||
30 | [email protected] "(" | ||
31 | [email protected] ")" | ||
32 | [email protected] " " | ||
33 | [email protected] | ||
34 | [email protected] "{" | ||
35 | [email protected] "\n" | ||
36 | [email protected] "}" | ||
37 | [email protected] "\n\n" | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] "extern" | ||
41 | [email protected] " " | ||
42 | [email protected] "r\"D\"" | ||
43 | [email protected] " " | ||
44 | [email protected] "fn" | ||
45 | [email protected] " " | ||
46 | [email protected] | ||
47 | [email protected] "baz" | ||
48 | [email protected] | ||
49 | [email protected] "(" | ||
50 | [email protected] ")" | ||
51 | [email protected] " " | ||
52 | [email protected] | ||
53 | [email protected] "{" | ||
54 | [email protected] "\n" | ||
55 | [email protected] "}" | ||
56 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rs b/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rs deleted file mode 100644 index e929eef74..000000000 --- a/crates/ra_syntax/test_data/parser/ok/0021_extern_fn.rs +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | extern fn foo() { | ||
2 | } | ||
3 | |||
4 | extern "C" fn bar() { | ||
5 | } | ||
6 | |||
7 | extern r"D" fn baz() { | ||
8 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast deleted file mode 100644 index 6246a31a6..000000000 --- a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rast +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "impl" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] | ||
7 | [email protected] | ||
8 | [email protected] | ||
9 | [email protected] "T" | ||
10 | [email protected] " " | ||
11 | [email protected] "for" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] | ||
16 | [email protected] | ||
17 | [email protected] "Foo" | ||
18 | [email protected] " " | ||
19 | [email protected] | ||
20 | [email protected] "{" | ||
21 | [email protected] "\n " | ||
22 | [email protected] | ||
23 | [email protected] "default" | ||
24 | [email protected] " " | ||
25 | [email protected] "const" | ||
26 | [email protected] " " | ||
27 | [email protected] | ||
28 | [email protected] "f" | ||
29 | [email protected] ":" | ||
30 | [email protected] " " | ||
31 | [email protected] | ||
32 | [email protected] | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] "u8" | ||
36 | [email protected] " " | ||
37 | [email protected] "=" | ||
38 | [email protected] " " | ||
39 | [email protected] | ||
40 | [email protected] "0" | ||
41 | [email protected] ";" | ||
42 | [email protected] "\n" | ||
43 | [email protected] "}" | ||
44 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs b/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs deleted file mode 100644 index dfb3b92dc..000000000 --- a/crates/ra_syntax/test_data/parser/ok/0066_default_const.rs +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | impl T for Foo { | ||
2 | default const f: u8 = 0; | ||
3 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rast b/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rast new file mode 100644 index 000000000..e9b57ec3b --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rast | |||
@@ -0,0 +1,218 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "trait" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "T" | ||
7 | [email protected] " " | ||
8 | [email protected] | ||
9 | [email protected] "{" | ||
10 | [email protected] "\n " | ||
11 | [email protected] | ||
12 | [email protected] "default" | ||
13 | [email protected] " " | ||
14 | [email protected] "type" | ||
15 | [email protected] " " | ||
16 | [email protected] | ||
17 | [email protected] "T" | ||
18 | [email protected] " " | ||
19 | [email protected] "=" | ||
20 | [email protected] " " | ||
21 | [email protected] | ||
22 | [email protected] | ||
23 | [email protected] | ||
24 | [email protected] | ||
25 | [email protected] "Bar" | ||
26 | [email protected] ";" | ||
27 | [email protected] "\n " | ||
28 | [email protected] | ||
29 | [email protected] "default" | ||
30 | [email protected] " " | ||
31 | [email protected] "const" | ||
32 | [email protected] " " | ||
33 | [email protected] | ||
34 | [email protected] "f" | ||
35 | [email protected] ":" | ||
36 | [email protected] " " | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] | ||
41 | [email protected] "u8" | ||
42 | [email protected] " " | ||
43 | [email protected] "=" | ||
44 | [email protected] " " | ||
45 | [email protected] | ||
46 | [email protected] "0" | ||
47 | [email protected] ";" | ||
48 | [email protected] "\n " | ||
49 | [email protected] | ||
50 | [email protected] "default" | ||
51 | [email protected] " " | ||
52 | [email protected] "fn" | ||
53 | [email protected] " " | ||
54 | [email protected] | ||
55 | [email protected] "foo" | ||
56 | [email protected] | ||
57 | [email protected] "(" | ||
58 | [email protected] ")" | ||
59 | [email protected] " " | ||
60 | [email protected] | ||
61 | [email protected] "{" | ||
62 | [email protected] "}" | ||
63 | [email protected] "\n " | ||
64 | [email protected] | ||
65 | [email protected] "default" | ||
66 | [email protected] " " | ||
67 | [email protected] "unsafe" | ||
68 | [email protected] " " | ||
69 | [email protected] "fn" | ||
70 | [email protected] " " | ||
71 | [email protected] | ||
72 | [email protected] "bar" | ||
73 | [email protected] | ||
74 | [email protected] "(" | ||
75 | [email protected] ")" | ||
76 | [email protected] " " | ||
77 | [email protected] | ||
78 | [email protected] "{" | ||
79 | [email protected] "}" | ||
80 | [email protected] "\n" | ||
81 | [email protected] "}" | ||
82 | [email protected] "\n\n" | ||
83 | [email protected] | ||
84 | [email protected] "impl" | ||
85 | [email protected] " " | ||
86 | [email protected] | ||
87 | [email protected] | ||
88 | [email protected] | ||
89 | [email protected] | ||
90 | [email protected] "T" | ||
91 | [email protected] " " | ||
92 | [email protected] "for" | ||
93 | [email protected] " " | ||
94 | [email protected] | ||
95 | [email protected] | ||
96 | [email protected] | ||
97 | [email protected] | ||
98 | [email protected] "Foo" | ||
99 | [email protected] " " | ||
100 | [email protected] | ||
101 | [email protected] "{" | ||
102 | [email protected] "\n " | ||
103 | [email protected] | ||
104 | [email protected] "default" | ||
105 | [email protected] " " | ||
106 | [email protected] "type" | ||
107 | [email protected] " " | ||
108 | [email protected] | ||
109 | [email protected] "T" | ||
110 | [email protected] " " | ||
111 | [email protected] "=" | ||
112 | [email protected] " " | ||
113 | [email protected] | ||
114 | [email protected] | ||
115 | [email protected] | ||
116 | [email protected] | ||
117 | [email protected] "Bar" | ||
118 | [email protected] ";" | ||
119 | [email protected] "\n " | ||
120 | [email protected] | ||
121 | [email protected] "default" | ||
122 | [email protected] " " | ||
123 | [email protected] "const" | ||
124 | [email protected] " " | ||
125 | [email protected] | ||
126 | [email protected] "f" | ||
127 | [email protected] ":" | ||
128 | [email protected] " " | ||
129 | [email protected] | ||
130 | [email protected] | ||
131 | [email protected] | ||
132 | [email protected] | ||
133 | [email protected] "u8" | ||
134 | [email protected] " " | ||
135 | [email protected] "=" | ||
136 | [email protected] " " | ||
137 | [email protected] | ||
138 | [email protected] "0" | ||
139 | [email protected] ";" | ||
140 | [email protected] "\n " | ||
141 | [email protected] | ||
142 | [email protected] "default" | ||
143 | [email protected] " " | ||
144 | [email protected] "fn" | ||
145 | [email protected] " " | ||
146 | [email protected] | ||
147 | [email protected] "foo" | ||
148 | [email protected] | ||
149 | [email protected] "(" | ||
150 | [email protected] ")" | ||
151 | [email protected] " " | ||
152 | [email protected] | ||
153 | [email protected] "{" | ||
154 | [email protected] "}" | ||
155 | [email protected] "\n " | ||
156 | [email protected] | ||
157 | [email protected] "default" | ||
158 | [email protected] " " | ||
159 | [email protected] "unsafe" | ||
160 | [email protected] " " | ||
161 | [email protected] "fn" | ||
162 | [email protected] " " | ||
163 | [email protected] | ||
164 | [email protected] "bar" | ||
165 | [email protected] | ||
166 | [email protected] "(" | ||
167 | [email protected] ")" | ||
168 | [email protected] " " | ||
169 | [email protected] | ||
170 | [email protected] "{" | ||
171 | [email protected] "}" | ||
172 | [email protected] "\n" | ||
173 | [email protected] "}" | ||
174 | [email protected] "\n\n" | ||
175 | [email protected] | ||
176 | [email protected] "default" | ||
177 | [email protected] " " | ||
178 | [email protected] "impl" | ||
179 | [email protected] " " | ||
180 | [email protected] | ||
181 | [email protected] | ||
182 | [email protected] | ||
183 | [email protected] | ||
184 | [email protected] "T" | ||
185 | [email protected] " " | ||
186 | [email protected] "for" | ||
187 | [email protected] " " | ||
188 | [email protected] | ||
189 | [email protected] "(" | ||
190 | [email protected] ")" | ||
191 | [email protected] " " | ||
192 | [email protected] | ||
193 | [email protected] "{" | ||
194 | [email protected] "}" | ||
195 | [email protected] "\n" | ||
196 | [email protected] | ||
197 | [email protected] "default" | ||
198 | [email protected] " " | ||
199 | [email protected] "unsafe" | ||
200 | [email protected] " " | ||
201 | [email protected] "impl" | ||
202 | [email protected] " " | ||
203 | [email protected] | ||
204 | [email protected] | ||
205 | [email protected] | ||
206 | [email protected] | ||
207 | [email protected] "T" | ||
208 | [email protected] " " | ||
209 | [email protected] "for" | ||
210 | [email protected] " " | ||
211 | [email protected] | ||
212 | [email protected] "(" | ||
213 | [email protected] ")" | ||
214 | [email protected] " " | ||
215 | [email protected] | ||
216 | [email protected] "{" | ||
217 | [email protected] "}" | ||
218 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rs b/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rs new file mode 100644 index 000000000..e443e3495 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0066_default_modifier.rs | |||
@@ -0,0 +1,16 @@ | |||
1 | trait T { | ||
2 | default type T = Bar; | ||
3 | default const f: u8 = 0; | ||
4 | default fn foo() {} | ||
5 | default unsafe fn bar() {} | ||
6 | } | ||
7 | |||
8 | impl T for Foo { | ||
9 | default type T = Bar; | ||
10 | default const f: u8 = 0; | ||
11 | default fn foo() {} | ||
12 | default unsafe fn bar() {} | ||
13 | } | ||
14 | |||
15 | default impl T for () {} | ||
16 | default unsafe impl T for () {} | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rast b/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rast new file mode 100644 index 000000000..50a6d8ee9 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rast | |||
@@ -0,0 +1,218 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "async" | ||
4 | [email protected] " " | ||
5 | [email protected] "fn" | ||
6 | [email protected] " " | ||
7 | [email protected] | ||
8 | [email protected] "foo" | ||
9 | [email protected] | ||
10 | [email protected] "(" | ||
11 | [email protected] ")" | ||
12 | [email protected] " " | ||
13 | [email protected] | ||
14 | [email protected] "{" | ||
15 | [email protected] "}" | ||
16 | [email protected] "\n" | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "extern" | ||
20 | [email protected] " " | ||
21 | [email protected] "fn" | ||
22 | [email protected] " " | ||
23 | [email protected] | ||
24 | [email protected] "foo" | ||
25 | [email protected] | ||
26 | [email protected] "(" | ||
27 | [email protected] ")" | ||
28 | [email protected] " " | ||
29 | [email protected] | ||
30 | [email protected] "{" | ||
31 | [email protected] "}" | ||
32 | [email protected] "\n" | ||
33 | [email protected] | ||
34 | [email protected] "const" | ||
35 | [email protected] " " | ||
36 | [email protected] "fn" | ||
37 | [email protected] " " | ||
38 | [email protected] | ||
39 | [email protected] "foo" | ||
40 | [email protected] | ||
41 | [email protected] "(" | ||
42 | [email protected] ")" | ||
43 | [email protected] " " | ||
44 | [email protected] | ||
45 | [email protected] "{" | ||
46 | [email protected] "}" | ||
47 | [email protected] "\n" | ||
48 | [email protected] | ||
49 | [email protected] "const" | ||
50 | [email protected] " " | ||
51 | [email protected] "unsafe" | ||
52 | [email protected] " " | ||
53 | [email protected] "fn" | ||
54 | [email protected] " " | ||
55 | [email protected] | ||
56 | [email protected] "foo" | ||
57 | [email protected] | ||
58 | [email protected] "(" | ||
59 | [email protected] ")" | ||
60 | [email protected] " " | ||
61 | [email protected] | ||
62 | [email protected] "{" | ||
63 | [email protected] "}" | ||
64 | [email protected] "\n" | ||
65 | [email protected] | ||
66 | [email protected] "unsafe" | ||
67 | [email protected] " " | ||
68 | [email protected] | ||
69 | [email protected] "extern" | ||
70 | [email protected] " " | ||
71 | [email protected] "\"C\"" | ||
72 | [email protected] " " | ||
73 | [email protected] "fn" | ||
74 | [email protected] " " | ||
75 | [email protected] | ||
76 | [email protected] "foo" | ||
77 | [email protected] | ||
78 | [email protected] "(" | ||
79 | [email protected] ")" | ||
80 | [email protected] " " | ||
81 | [email protected] | ||
82 | [email protected] "{" | ||
83 | [email protected] "}" | ||
84 | [email protected] "\n" | ||
85 | [email protected] | ||
86 | [email protected] "unsafe" | ||
87 | [email protected] " " | ||
88 | [email protected] "fn" | ||
89 | [email protected] " " | ||
90 | [email protected] | ||
91 | [email protected] "foo" | ||
92 | [email protected] | ||
93 | [email protected] "(" | ||
94 | [email protected] ")" | ||
95 | [email protected] " " | ||
96 | [email protected] | ||
97 | [email protected] "{" | ||
98 | [email protected] "}" | ||
99 | [email protected] "\n" | ||
100 | [email protected] | ||
101 | [email protected] "async" | ||
102 | [email protected] " " | ||
103 | [email protected] "unsafe" | ||
104 | [email protected] " " | ||
105 | [email protected] "fn" | ||
106 | [email protected] " " | ||
107 | [email protected] | ||
108 | [email protected] "foo" | ||
109 | [email protected] | ||
110 | [email protected] "(" | ||
111 | [email protected] ")" | ||
112 | [email protected] " " | ||
113 | [email protected] | ||
114 | [email protected] "{" | ||
115 | [email protected] "}" | ||
116 | [email protected] "\n" | ||
117 | [email protected] | ||
118 | [email protected] "const" | ||
119 | [email protected] " " | ||
120 | [email protected] "unsafe" | ||
121 | [email protected] " " | ||
122 | [email protected] "fn" | ||
123 | [email protected] " " | ||
124 | [email protected] | ||
125 | [email protected] "bar" | ||
126 | [email protected] | ||
127 | [email protected] "(" | ||
128 | [email protected] ")" | ||
129 | [email protected] " " | ||
130 | [email protected] | ||
131 | [email protected] "{" | ||
132 | [email protected] "}" | ||
133 | [email protected] "\n\n" | ||
134 | [email protected] | ||
135 | [email protected] "unsafe" | ||
136 | [email protected] " " | ||
137 | [email protected] "trait" | ||
138 | [email protected] " " | ||
139 | [email protected] | ||
140 | [email protected] "T" | ||
141 | [email protected] " " | ||
142 | [email protected] | ||
143 | [email protected] "{" | ||
144 | [email protected] "}" | ||
145 | [email protected] "\n" | ||
146 | [email protected] | ||
147 | [email protected] "auto" | ||
148 | [email protected] " " | ||
149 | [email protected] "trait" | ||
150 | [email protected] " " | ||
151 | [email protected] | ||
152 | [email protected] "T" | ||
153 | [email protected] " " | ||
154 | [email protected] | ||
155 | [email protected] "{" | ||
156 | [email protected] "}" | ||
157 | [email protected] "\n" | ||
158 | [email protected] | ||
159 | [email protected] "unsafe" | ||
160 | [email protected] " " | ||
161 | [email protected] "auto" | ||
162 | [email protected] " " | ||
163 | [email protected] "trait" | ||
164 | [email protected] " " | ||
165 | [email protected] | ||
166 | [email protected] "T" | ||
167 | [email protected] " " | ||
168 | [email protected] | ||
169 | [email protected] "{" | ||
170 | [email protected] "}" | ||
171 | [email protected] "\n\n" | ||
172 | [email protected] | ||
173 | [email protected] "unsafe" | ||
174 | [email protected] " " | ||
175 | [email protected] "impl" | ||
176 | [email protected] " " | ||
177 | [email protected] | ||
178 | [email protected] | ||
179 | [email protected] | ||
180 | [email protected] | ||
181 | [email protected] "Foo" | ||
182 | [email protected] " " | ||
183 | [email protected] | ||
184 | [email protected] "{" | ||
185 | [email protected] "}" | ||
186 | [email protected] "\n" | ||
187 | [email protected] | ||
188 | [email protected] "default" | ||
189 | [email protected] " " | ||
190 | [email protected] "impl" | ||
191 | [email protected] " " | ||
192 | [email protected] | ||
193 | [email protected] | ||
194 | [email protected] | ||
195 | [email protected] | ||
196 | [email protected] "Foo" | ||
197 | [email protected] " " | ||
198 | [email protected] | ||
199 | [email protected] "{" | ||
200 | [email protected] "}" | ||
201 | [email protected] "\n" | ||
202 | [email protected] | ||
203 | [email protected] "unsafe" | ||
204 | [email protected] " " | ||
205 | [email protected] "default" | ||
206 | [email protected] " " | ||
207 | [email protected] "impl" | ||
208 | [email protected] " " | ||
209 | [email protected] | ||
210 | [email protected] | ||
211 | [email protected] | ||
212 | [email protected] | ||
213 | [email protected] "Foo" | ||
214 | [email protected] " " | ||
215 | [email protected] | ||
216 | [email protected] "{" | ||
217 | [email protected] "}" | ||
218 | [email protected] "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rs b/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rs new file mode 100644 index 000000000..8d697c04b --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0068_item_modifiers.rs | |||
@@ -0,0 +1,16 @@ | |||
1 | async fn foo() {} | ||
2 | extern fn foo() {} | ||
3 | const fn foo() {} | ||
4 | const unsafe fn foo() {} | ||
5 | unsafe extern "C" fn foo() {} | ||
6 | unsafe fn foo() {} | ||
7 | async unsafe fn foo() {} | ||
8 | const unsafe fn bar() {} | ||
9 | |||
10 | unsafe trait T {} | ||
11 | auto trait T {} | ||
12 | unsafe auto trait T {} | ||
13 | |||
14 | unsafe impl Foo {} | ||
15 | default impl Foo {} | ||
16 | unsafe default impl Foo {} | ||
diff --git a/crates/ra_text_edit/src/lib.rs b/crates/ra_text_edit/src/lib.rs index 25554f583..d68791cf1 100644 --- a/crates/ra_text_edit/src/lib.rs +++ b/crates/ra_text_edit/src/lib.rs | |||
@@ -76,10 +76,6 @@ impl TextEdit { | |||
76 | self.indels.iter() | 76 | self.indels.iter() |
77 | } | 77 | } |
78 | 78 | ||
79 | pub fn into_iter(self) -> vec::IntoIter<Indel> { | ||
80 | self.indels.into_iter() | ||
81 | } | ||
82 | |||
83 | pub fn apply(&self, text: &mut String) { | 79 | pub fn apply(&self, text: &mut String) { |
84 | match self.len() { | 80 | match self.len() { |
85 | 0 => return, | 81 | 0 => return, |
@@ -141,6 +137,15 @@ impl TextEdit { | |||
141 | } | 137 | } |
142 | } | 138 | } |
143 | 139 | ||
140 | impl IntoIterator for TextEdit { | ||
141 | type Item = Indel; | ||
142 | type IntoIter = vec::IntoIter<Self::Item>; | ||
143 | |||
144 | fn into_iter(self) -> Self::IntoIter { | ||
145 | self.indels.into_iter() | ||
146 | } | ||
147 | } | ||
148 | |||
144 | impl TextEditBuilder { | 149 | impl TextEditBuilder { |
145 | pub fn replace(&mut self, range: TextRange, replace_with: String) { | 150 | pub fn replace(&mut self, range: TextRange, replace_with: String) { |
146 | self.indels.push(Indel::replace(range, replace_with)) | 151 | self.indels.push(Indel::replace(range, replace_with)) |
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs index 8faf1cc67..20c3f5eab 100644 --- a/crates/ra_tt/src/lib.rs +++ b/crates/ra_tt/src/lib.rs | |||
@@ -107,7 +107,7 @@ fn print_debug_subtree(f: &mut fmt::Formatter<'_>, subtree: &Subtree, level: usi | |||
107 | for (idx, child) in subtree.token_trees.iter().enumerate() { | 107 | for (idx, child) in subtree.token_trees.iter().enumerate() { |
108 | print_debug_token(f, child, level + 1)?; | 108 | print_debug_token(f, child, level + 1)?; |
109 | if idx != subtree.token_trees.len() - 1 { | 109 | if idx != subtree.token_trees.len() - 1 { |
110 | writeln!(f, "")?; | 110 | writeln!(f)?; |
111 | } | 111 | } |
112 | } | 112 | } |
113 | } | 113 | } |
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 721d41a58..0d386841e 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -72,7 +72,7 @@ impl AnalysisStatsCmd { | |||
72 | shuffle(&mut rng, &mut krates); | 72 | shuffle(&mut rng, &mut krates); |
73 | } | 73 | } |
74 | for krate in krates { | 74 | for krate in krates { |
75 | let module = krate.root_module(db).expect("crate without root module"); | 75 | let module = krate.root_module(db); |
76 | let file_id = module.definition_source(db).file_id; | 76 | let file_id = module.definition_source(db).file_id; |
77 | let file_id = file_id.original_file(db); | 77 | let file_id = file_id.original_file(db); |
78 | let source_root = db.file_source_root(file_id); | 78 | let source_root = db.file_source_root(file_id); |
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs index 4ac8c8772..f17fc5dfe 100644 --- a/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/crates/rust-analyzer/src/cli/diagnostics.rs | |||
@@ -28,7 +28,7 @@ pub fn diagnostics( | |||
28 | let mut work = Vec::new(); | 28 | let mut work = Vec::new(); |
29 | let krates = Crate::all(db); | 29 | let krates = Crate::all(db); |
30 | for krate in krates { | 30 | for krate in krates { |
31 | let module = krate.root_module(db).expect("crate without root module"); | 31 | let module = krate.root_module(db); |
32 | let file_id = module.definition_source(db).file_id; | 32 | let file_id = module.definition_source(db).file_id; |
33 | let file_id = file_id.original_file(db); | 33 | let file_id = file_id.original_file(db); |
34 | let source_root = db.file_source_root(file_id); | 34 | let source_root = db.file_source_root(file_id); |
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 46cb7ebe2..f9f045f13 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -73,6 +73,7 @@ pub(crate) struct GlobalState { | |||
73 | pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, | 73 | pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, |
74 | pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, | 74 | pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, |
75 | pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, | 75 | pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>, |
76 | pub(crate) shutdown_requested: bool, | ||
76 | pub(crate) status: Status, | 77 | pub(crate) status: Status, |
77 | pub(crate) source_root_config: SourceRootConfig, | 78 | pub(crate) source_root_config: SourceRootConfig, |
78 | pub(crate) proc_macro_client: ProcMacroClient, | 79 | pub(crate) proc_macro_client: ProcMacroClient, |
@@ -124,6 +125,7 @@ impl GlobalState { | |||
124 | mem_docs: FxHashMap::default(), | 125 | mem_docs: FxHashMap::default(), |
125 | semantic_tokens_cache: Arc::new(Default::default()), | 126 | semantic_tokens_cache: Arc::new(Default::default()), |
126 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), | 127 | vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), |
128 | shutdown_requested: false, | ||
127 | status: Status::default(), | 129 | status: Status::default(), |
128 | source_root_config: SourceRootConfig::default(), | 130 | source_root_config: SourceRootConfig::default(), |
129 | proc_macro_client: ProcMacroClient::dummy(), | 131 | proc_macro_client: ProcMacroClient::dummy(), |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 067259e24..785dd2a26 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -773,12 +773,11 @@ fn handle_fixes( | |||
773 | 773 | ||
774 | let diagnostics = snap.analysis.diagnostics(file_id, snap.config.experimental_diagnostics)?; | 774 | let diagnostics = snap.analysis.diagnostics(file_id, snap.config.experimental_diagnostics)?; |
775 | 775 | ||
776 | let fixes_from_diagnostics = diagnostics | 776 | for fix in diagnostics |
777 | .into_iter() | 777 | .into_iter() |
778 | .filter_map(|d| Some((d.range, d.fix?))) | 778 | .filter_map(|d| d.fix) |
779 | .filter(|(diag_range, _fix)| diag_range.intersect(range).is_some()) | 779 | .filter(|fix| fix.fix_trigger_range.intersect(range).is_some()) |
780 | .map(|(_range, fix)| fix); | 780 | { |
781 | for fix in fixes_from_diagnostics { | ||
782 | let title = fix.label; | 781 | let title = fix.label; |
783 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; | 782 | let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?; |
784 | let action = lsp_ext::CodeAction { | 783 | let action = lsp_ext::CodeAction { |
@@ -864,7 +863,7 @@ pub(crate) fn handle_resolve_code_action( | |||
864 | let (id_string, index) = split_once(¶ms.id, ':').unwrap(); | 863 | let (id_string, index) = split_once(¶ms.id, ':').unwrap(); |
865 | let index = index.parse::<usize>().unwrap(); | 864 | let index = index.parse::<usize>().unwrap(); |
866 | let assist = &assists[index]; | 865 | let assist = &assists[index]; |
867 | assert!(assist.assist.id.0 == id_string); | 866 | assert!(assist.assist.id().0 == id_string); |
868 | Ok(to_proto::resolved_code_action(&snap, assist.clone())?.edit) | 867 | Ok(to_proto::resolved_code_action(&snap, assist.clone())?.edit) |
869 | } | 868 | } |
870 | 869 | ||
@@ -892,7 +891,7 @@ pub(crate) fn handle_code_lens( | |||
892 | } | 891 | } |
893 | 892 | ||
894 | let action = runnable.action(); | 893 | let action = runnable.action(); |
895 | let range = to_proto::range(&line_index, runnable.nav.focus_or_full_range()); | 894 | let range = to_proto::range(&line_index, runnable.nav.full_range); |
896 | let r = to_proto::runnable(&snap, file_id, runnable)?; | 895 | let r = to_proto::runnable(&snap, file_id, runnable)?; |
897 | if snap.config.lens.run { | 896 | if snap.config.lens.run { |
898 | let lens = CodeLens { | 897 | let lens = CodeLens { |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ceddb2b05..e6cf46df2 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -47,7 +47,7 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> { | |||
47 | SetThreadPriority(thread, thread_priority_above_normal); | 47 | SetThreadPriority(thread, thread_priority_above_normal); |
48 | } | 48 | } |
49 | 49 | ||
50 | GlobalState::new(connection.sender.clone(), config).run(connection.receiver) | 50 | GlobalState::new(connection.sender, config).run(connection.receiver) |
51 | } | 51 | } |
52 | 52 | ||
53 | enum Event { | 53 | enum Event { |
@@ -337,11 +337,34 @@ impl GlobalState { | |||
337 | fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> { | 337 | fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> { |
338 | self.register_request(&req, request_received); | 338 | self.register_request(&req, request_received); |
339 | 339 | ||
340 | if self.shutdown_requested { | ||
341 | self.respond(Response::new_err( | ||
342 | req.id, | ||
343 | lsp_server::ErrorCode::InvalidRequest as i32, | ||
344 | "Shutdown already requested.".to_owned(), | ||
345 | )); | ||
346 | |||
347 | return Ok(()); | ||
348 | } | ||
349 | |||
350 | if self.status == Status::Loading && req.method != "shutdown" { | ||
351 | self.respond(lsp_server::Response::new_err( | ||
352 | req.id, | ||
353 | // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion) | ||
354 | lsp_server::ErrorCode::ContentModified as i32, | ||
355 | "Rust Analyzer is still loading...".to_owned(), | ||
356 | )); | ||
357 | return Ok(()); | ||
358 | } | ||
359 | |||
340 | RequestDispatcher { req: Some(req), global_state: self } | 360 | RequestDispatcher { req: Some(req), global_state: self } |
341 | .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))? | 361 | .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))? |
342 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? | 362 | .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? |
343 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? | 363 | .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? |
344 | .on_sync::<lsp_types::request::Shutdown>(|_, ()| Ok(()))? | 364 | .on_sync::<lsp_types::request::Shutdown>(|s, ()| { |
365 | s.shutdown_requested = true; | ||
366 | Ok(()) | ||
367 | })? | ||
345 | .on_sync::<lsp_types::request::SelectionRangeRequest>(|s, p| { | 368 | .on_sync::<lsp_types::request::SelectionRangeRequest>(|s, p| { |
346 | handlers::handle_selection_range(s.snapshot(), p) | 369 | handlers::handle_selection_range(s.snapshot(), p) |
347 | })? | 370 | })? |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 5eba1f155..62fda8a1f 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -704,10 +704,10 @@ 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, | 707 | title: assist.label(), |
708 | id: Some(format!("{}:{}", assist.id.0.to_owned(), index.to_string())), | 708 | id: Some(format!("{}:{}", assist.id().0.to_owned(), 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)), |
711 | edit: None, | 711 | edit: None, |
712 | is_preferred: None, | 712 | is_preferred: None, |
713 | }; | 713 | }; |
@@ -755,7 +755,8 @@ pub(crate) fn runnable( | |||
755 | } | 755 | } |
756 | 756 | ||
757 | pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent { | 757 | pub(crate) fn markup_content(markup: Markup) -> lsp_types::MarkupContent { |
758 | lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value: markup.into() } | 758 | let value = crate::markdown::format_docs(markup.as_str()); |
759 | lsp_types::MarkupContent { kind: lsp_types::MarkupKind::Markdown, value } | ||
759 | } | 760 | } |
760 | 761 | ||
761 | #[cfg(test)] | 762 | #[cfg(test)] |
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs index b65875c96..3c5027fe5 100644 --- a/crates/stdx/src/lib.rs +++ b/crates/stdx/src/lib.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! Missing batteries for standard libraries. | 1 | //! Missing batteries for standard libraries. |
2 | use std::{cell::Cell, fmt, time::Instant}; | 2 | use std::time::Instant; |
3 | 3 | ||
4 | mod macros; | 4 | mod macros; |
5 | 5 | ||
@@ -8,69 +8,6 @@ pub fn is_ci() -> bool { | |||
8 | option_env!("CI").is_some() | 8 | option_env!("CI").is_some() |
9 | } | 9 | } |
10 | 10 | ||
11 | pub trait SepBy: Sized { | ||
12 | /// Returns an `impl fmt::Display`, which joins elements via a separator. | ||
13 | fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>; | ||
14 | } | ||
15 | |||
16 | impl<I> SepBy for I | ||
17 | where | ||
18 | I: Iterator, | ||
19 | I::Item: fmt::Display, | ||
20 | { | ||
21 | fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self> { | ||
22 | SepByBuilder::new(sep, self) | ||
23 | } | ||
24 | } | ||
25 | |||
26 | pub struct SepByBuilder<'a, I> { | ||
27 | sep: &'a str, | ||
28 | prefix: &'a str, | ||
29 | suffix: &'a str, | ||
30 | iter: Cell<Option<I>>, | ||
31 | } | ||
32 | |||
33 | impl<'a, I> SepByBuilder<'a, I> { | ||
34 | fn new(sep: &'a str, iter: I) -> SepByBuilder<'a, I> { | ||
35 | SepByBuilder { sep, prefix: "", suffix: "", iter: Cell::new(Some(iter)) } | ||
36 | } | ||
37 | |||
38 | pub fn prefix(mut self, prefix: &'a str) -> Self { | ||
39 | self.prefix = prefix; | ||
40 | self | ||
41 | } | ||
42 | |||
43 | pub fn suffix(mut self, suffix: &'a str) -> Self { | ||
44 | self.suffix = suffix; | ||
45 | self | ||
46 | } | ||
47 | |||
48 | /// Set both suffix and prefix. | ||
49 | pub fn surround_with(self, prefix: &'a str, suffix: &'a str) -> Self { | ||
50 | self.prefix(prefix).suffix(suffix) | ||
51 | } | ||
52 | } | ||
53 | |||
54 | impl<I> fmt::Display for SepByBuilder<'_, I> | ||
55 | where | ||
56 | I: Iterator, | ||
57 | I::Item: fmt::Display, | ||
58 | { | ||
59 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
60 | f.write_str(self.prefix)?; | ||
61 | let mut first = true; | ||
62 | for item in self.iter.take().unwrap() { | ||
63 | if !first { | ||
64 | f.write_str(self.sep)?; | ||
65 | } | ||
66 | first = false; | ||
67 | fmt::Display::fmt(&item, f)?; | ||
68 | } | ||
69 | f.write_str(self.suffix)?; | ||
70 | Ok(()) | ||
71 | } | ||
72 | } | ||
73 | |||
74 | #[must_use] | 11 | #[must_use] |
75 | pub fn timeit(label: &'static str) -> impl Drop { | 12 | pub fn timeit(label: &'static str) -> impl Drop { |
76 | struct Guard { | 13 | struct Guard { |
diff --git a/docs/dev/README.md b/docs/dev/README.md index 67813a9c0..51cf716b3 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -256,9 +256,9 @@ Release steps: | |||
256 | * checkout the `release` branch | 256 | * checkout the `release` branch |
257 | * reset it to `upstream/nightly` | 257 | * reset it to `upstream/nightly` |
258 | * push it to `upstream`. This triggers GitHub Actions which: | 258 | * push it to `upstream`. This triggers GitHub Actions which: |
259 | ** runs `cargo xtask dist` to package binaries and VS Code extension | 259 | * runs `cargo xtask dist` to package binaries and VS Code extension |
260 | ** makes a GitHub release | 260 | * makes a GitHub release |
261 | ** pushes VS Code extension to the marketplace | 261 | * pushes VS Code extension to the marketplace |
262 | * create new changelog in `rust-analyzer.github.io` | 262 | * create new changelog in `rust-analyzer.github.io` |
263 | * create `rust-analyzer.github.io/git.log` file with the log of merge commits since last release | 263 | * create `rust-analyzer.github.io/git.log` file with the log of merge commits since last release |
264 | 2. While the release is in progress, fill-in the changelog using `git.log` | 264 | 2. While the release is in progress, fill-in the changelog using `git.log` |
diff --git a/docs/dev/syntax.md b/docs/dev/syntax.md index d4bc4b07c..f1bcdc4af 100644 --- a/docs/dev/syntax.md +++ b/docs/dev/syntax.md | |||
@@ -74,7 +74,7 @@ Points of note: | |||
74 | * The original text can be recovered by concatenating the texts of all tokens in order. | 74 | * The original text can be recovered by concatenating the texts of all tokens in order. |
75 | * Accessing a child of particular type (for example, parameter list of a function) generally involves linerary traversing the children, looking for a specific `kind`. | 75 | * Accessing a child of particular type (for example, parameter list of a function) generally involves linerary traversing the children, looking for a specific `kind`. |
76 | * Modifying the tree is roughly `O(depth)`. | 76 | * Modifying the tree is roughly `O(depth)`. |
77 | We don't make special efforts to guarantree that the depth is not liner, but, in practice, syntax trees are branchy and shallow. | 77 | We don't make special efforts to guarantee that the depth is not linear, but, in practice, syntax trees are branchy and shallow. |
78 | * If mandatory (grammar wise) node is missing from the input, it's just missing from the tree. | 78 | * If mandatory (grammar wise) node is missing from the input, it's just missing from the tree. |
79 | * If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node. | 79 | * If an extra erroneous input is present, it is wrapped into a node with `ERROR` kind, and treated just like any other node. |
80 | * Parser errors are not a part of syntax tree. | 80 | * Parser errors are not a part of syntax tree. |
diff --git a/editors/code/package.json b/editors/code/package.json index 86584c071..d186d1474 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -607,7 +607,7 @@ | |||
607 | "items": { | 607 | "items": { |
608 | "type": "string" | 608 | "type": "string" |
609 | }, | 609 | }, |
610 | "description": "List of warnings 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 hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", |
611 | "default": [] | 611 | "default": [] |
612 | }, | 612 | }, |
613 | "rust-analyzer.analysis.disabledDiagnostics": { | 613 | "rust-analyzer.analysis.disabledDiagnostics": { |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 18948cb3c..f5db55b8c 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -4,7 +4,7 @@ import * as ra from '../src/lsp_ext'; | |||
4 | import * as Is from 'vscode-languageclient/lib/utils/is'; | 4 | import * as Is from 'vscode-languageclient/lib/utils/is'; |
5 | 5 | ||
6 | import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; | 6 | import { CallHierarchyFeature } from 'vscode-languageclient/lib/callHierarchy.proposed'; |
7 | import { SemanticTokensFeature, DocumentSemanticsTokensSignature } from 'vscode-languageclient/lib/semanticTokens.proposed'; | 7 | import { SemanticTokensFeature } from 'vscode-languageclient/lib/semanticTokens.proposed'; |
8 | import { assert } from './util'; | 8 | import { assert } from './util'; |
9 | 9 | ||
10 | function renderCommand(cmd: ra.CommandLink) { | 10 | function renderCommand(cmd: ra.CommandLink) { |
@@ -44,12 +44,6 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
44 | diagnosticCollectionName: "rustc", | 44 | diagnosticCollectionName: "rustc", |
45 | traceOutputChannel, | 45 | traceOutputChannel, |
46 | middleware: { | 46 | middleware: { |
47 | // Workaround for https://github.com/microsoft/vscode-languageserver-node/issues/576 | ||
48 | async provideDocumentSemanticTokens(document: vscode.TextDocument, token: vscode.CancellationToken, next: DocumentSemanticsTokensSignature) { | ||
49 | const res = await next(document, token); | ||
50 | if (res === undefined) throw new Error('busy'); | ||
51 | return res; | ||
52 | }, | ||
53 | async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, _next: lc.ProvideHoverSignature) { | 47 | async provideHover(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, _next: lc.ProvideHoverSignature) { |
54 | return client.sendRequest(lc.HoverRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then( | 48 | return client.sendRequest(lc.HoverRequest.type, client.code2ProtocolConverter.asTextDocumentPositionParams(document, position), token).then( |
55 | (result) => { | 49 | (result) => { |
@@ -135,7 +129,7 @@ export function createClient(serverPath: string, cwd: string): lc.LanguageClient | |||
135 | ); | 129 | ); |
136 | } | 130 | } |
137 | 131 | ||
138 | } as any | 132 | } |
139 | }; | 133 | }; |
140 | 134 | ||
141 | const client = new lc.LanguageClient( | 135 | const client = new lc.LanguageClient( |
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 970fedb37..49d2d1c6f 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts | |||
@@ -64,7 +64,8 @@ export async function sendRequestWithRetry<TParam, TRet>( | |||
64 | param: TParam, | 64 | param: TParam, |
65 | token?: vscode.CancellationToken, | 65 | token?: vscode.CancellationToken, |
66 | ): Promise<TRet> { | 66 | ): Promise<TRet> { |
67 | for (const delay of [2, 4, 6, 8, 10, null]) { | 67 | // The sequence is `10 * (2 ** (2 * n))` where n is 1, 2, 3... |
68 | for (const delay of [40, 160, 640, 2560, 10240, null]) { | ||
68 | try { | 69 | try { |
69 | return await (token | 70 | return await (token |
70 | ? client.sendRequest(reqType, param, token) | 71 | ? client.sendRequest(reqType, param, token) |
@@ -84,8 +85,7 @@ export async function sendRequestWithRetry<TParam, TRet>( | |||
84 | log.warn("LSP request failed", { method: reqType.method, param, error }); | 85 | log.warn("LSP request failed", { method: reqType.method, param, error }); |
85 | throw error; | 86 | throw error; |
86 | } | 87 | } |
87 | 88 | await sleep(delay); | |
88 | await sleep(10 * (1 << delay)); | ||
89 | } | 89 | } |
90 | } | 90 | } |
91 | throw 'unreachable'; | 91 | throw 'unreachable'; |
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs index d65a2acbc..4ff72865e 100644 --- a/xtask/tests/tidy.rs +++ b/xtask/tests/tidy.rs | |||
@@ -44,11 +44,26 @@ fn rust_files_are_tidy() { | |||
44 | let text = fs2::read_to_string(&path).unwrap(); | 44 | let text = fs2::read_to_string(&path).unwrap(); |
45 | check_todo(&path, &text); | 45 | check_todo(&path, &text); |
46 | check_trailing_ws(&path, &text); | 46 | check_trailing_ws(&path, &text); |
47 | deny_clippy(&path, &text); | ||
47 | tidy_docs.visit(&path, &text); | 48 | tidy_docs.visit(&path, &text); |
48 | } | 49 | } |
49 | tidy_docs.finish(); | 50 | tidy_docs.finish(); |
50 | } | 51 | } |
51 | 52 | ||
53 | fn deny_clippy(path: &PathBuf, text: &String) { | ||
54 | if text.contains("[\u{61}llow(clippy") { | ||
55 | panic!( | ||
56 | "\n\nallowing lints is forbidden: {}. | ||
57 | rust-analyzer intentionally doesn't check clippy on CI. | ||
58 | You can allow lint globally via `xtask clippy`. | ||
59 | See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion. | ||
60 | |||
61 | ", | ||
62 | path.display() | ||
63 | ) | ||
64 | } | ||
65 | } | ||
66 | |||
52 | #[test] | 67 | #[test] |
53 | fn check_licenses() { | 68 | fn check_licenses() { |
54 | let expected = " | 69 | let expected = " |