diff options
22 files changed, 681 insertions, 66 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 02a3b6228..00f299ff1 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml | |||
@@ -20,25 +20,14 @@ jobs: | |||
20 | name: Audit Rust vulnerabilities | 20 | name: Audit Rust vulnerabilities |
21 | runs-on: ubuntu-latest | 21 | runs-on: ubuntu-latest |
22 | steps: | 22 | steps: |
23 | - name: Install Rust toolchain | ||
24 | uses: actions-rs/toolchain@v1 | ||
25 | with: | ||
26 | toolchain: stable | ||
27 | profile: minimal | ||
28 | override: true | ||
29 | |||
30 | - name: Checkout repository | 23 | - name: Checkout repository |
31 | uses: actions/checkout@v2 | 24 | uses: actions/checkout@v2 |
32 | 25 | ||
33 | - run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/ | 26 | - uses: actions-rs/[email protected] |
34 | |||
35 | - name: Cache cargo | ||
36 | uses: actions/cache@v1 | ||
37 | with: | 27 | with: |
38 | path: ~/.cargo/ | 28 | crate: cargo-audit |
39 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | 29 | use-tool-cache: true |
40 | 30 | ||
41 | - run: cargo install cargo-audit | ||
42 | - run: cargo audit | 31 | - run: cargo audit |
43 | 32 | ||
44 | rust: | 33 | rust: |
diff --git a/Cargo.lock b/Cargo.lock index 34c535162..975c1aef8 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -425,6 +425,17 @@ dependencies = [ | |||
425 | ] | 425 | ] |
426 | 426 | ||
427 | [[package]] | 427 | [[package]] |
428 | name = "goblin" | ||
429 | version = "0.2.1" | ||
430 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
431 | checksum = "ddd5e3132801a1ac34ac53b97acde50c4685414dd2f291b9ea52afa6f07468c8" | ||
432 | dependencies = [ | ||
433 | "log", | ||
434 | "plain", | ||
435 | "scroll", | ||
436 | ] | ||
437 | |||
438 | [[package]] | ||
428 | name = "heck" | 439 | name = "heck" |
429 | version = "0.3.1" | 440 | version = "0.3.1" |
430 | source = "registry+https://github.com/rust-lang/crates.io-index" | 441 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -587,6 +598,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
587 | checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" | 598 | checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" |
588 | 599 | ||
589 | [[package]] | 600 | [[package]] |
601 | name = "libloading" | ||
602 | version = "0.6.0" | ||
603 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
604 | checksum = "2c979a19ffb457f0273965c333053f3d586bf759bf7b683fbebc37f9a9ebedc4" | ||
605 | dependencies = [ | ||
606 | "winapi 0.3.8", | ||
607 | ] | ||
608 | |||
609 | [[package]] | ||
590 | name = "linked-hash-map" | 610 | name = "linked-hash-map" |
591 | version = "0.5.2" | 611 | version = "0.5.2" |
592 | source = "registry+https://github.com/rust-lang/crates.io-index" | 612 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -826,6 +846,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
826 | checksum = "3ad1f1b834a05d42dae330066e9699a173b28185b3bdc3dbf14ca239585de8cc" | 846 | checksum = "3ad1f1b834a05d42dae330066e9699a173b28185b3bdc3dbf14ca239585de8cc" |
827 | 847 | ||
828 | [[package]] | 848 | [[package]] |
849 | name = "plain" | ||
850 | version = "0.2.3" | ||
851 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
852 | checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" | ||
853 | |||
854 | [[package]] | ||
829 | name = "ppv-lite86" | 855 | name = "ppv-lite86" |
830 | version = "0.2.6" | 856 | version = "0.2.6" |
831 | source = "registry+https://github.com/rust-lang/crates.io-index" | 857 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1082,10 +1108,13 @@ version = "0.1.0" | |||
1082 | dependencies = [ | 1108 | dependencies = [ |
1083 | "cargo_metadata", | 1109 | "cargo_metadata", |
1084 | "difference", | 1110 | "difference", |
1111 | "goblin", | ||
1112 | "libloading", | ||
1085 | "ra_mbe", | 1113 | "ra_mbe", |
1086 | "ra_proc_macro", | 1114 | "ra_proc_macro", |
1087 | "ra_tt", | 1115 | "ra_tt", |
1088 | "serde_derive", | 1116 | "serde_derive", |
1117 | "test_utils", | ||
1089 | ] | 1118 | ] |
1090 | 1119 | ||
1091 | [[package]] | 1120 | [[package]] |
@@ -1404,6 +1433,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
1404 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" | 1433 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" |
1405 | 1434 | ||
1406 | [[package]] | 1435 | [[package]] |
1436 | name = "scroll" | ||
1437 | version = "0.10.1" | ||
1438 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1439 | checksum = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" | ||
1440 | dependencies = [ | ||
1441 | "scroll_derive", | ||
1442 | ] | ||
1443 | |||
1444 | [[package]] | ||
1445 | name = "scroll_derive" | ||
1446 | version = "0.10.1" | ||
1447 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1448 | checksum = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" | ||
1449 | dependencies = [ | ||
1450 | "proc-macro2", | ||
1451 | "quote", | ||
1452 | "syn", | ||
1453 | ] | ||
1454 | |||
1455 | [[package]] | ||
1407 | name = "semver" | 1456 | name = "semver" |
1408 | version = "0.9.0" | 1457 | version = "0.9.0" |
1409 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 5f9d53ecb..e09996c6f 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -236,7 +236,7 @@ impl Index<PatId> for Body { | |||
236 | 236 | ||
237 | impl BodySourceMap { | 237 | impl BodySourceMap { |
238 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { | 238 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { |
239 | self.expr_map_back[expr] | 239 | self.expr_map_back[expr].clone() |
240 | } | 240 | } |
241 | 241 | ||
242 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { | 242 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { |
@@ -255,7 +255,7 @@ impl BodySourceMap { | |||
255 | } | 255 | } |
256 | 256 | ||
257 | pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { | 257 | pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { |
258 | self.pat_map_back[pat] | 258 | self.pat_map_back[pat].clone() |
259 | } | 259 | } |
260 | 260 | ||
261 | pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { | 261 | pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { |
@@ -264,6 +264,6 @@ impl BodySourceMap { | |||
264 | } | 264 | } |
265 | 265 | ||
266 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | 266 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { |
267 | self.field_map[&(expr, field)] | 267 | self.field_map[&(expr, field)].clone() |
268 | } | 268 | } |
269 | } | 269 | } |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 0855c1d3a..9d6ee095e 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -106,7 +106,7 @@ impl ExprCollector<'_> { | |||
106 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | 106 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { |
107 | let ptr = Either::Left(ptr); | 107 | let ptr = Either::Left(ptr); |
108 | let src = self.expander.to_source(ptr); | 108 | let src = self.expander.to_source(ptr); |
109 | let id = self.make_expr(expr, Ok(src)); | 109 | let id = self.make_expr(expr, Ok(src.clone())); |
110 | self.source_map.expr_map.insert(src, id); | 110 | self.source_map.expr_map.insert(src, id); |
111 | id | 111 | id |
112 | } | 112 | } |
@@ -118,7 +118,7 @@ impl ExprCollector<'_> { | |||
118 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { | 118 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { |
119 | let ptr = Either::Right(ptr); | 119 | let ptr = Either::Right(ptr); |
120 | let src = self.expander.to_source(ptr); | 120 | let src = self.expander.to_source(ptr); |
121 | let id = self.make_expr(expr, Ok(src)); | 121 | let id = self.make_expr(expr, Ok(src.clone())); |
122 | self.source_map.expr_map.insert(src, id); | 122 | self.source_map.expr_map.insert(src, id); |
123 | id | 123 | id |
124 | } | 124 | } |
@@ -136,7 +136,7 @@ impl ExprCollector<'_> { | |||
136 | 136 | ||
137 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { | 137 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { |
138 | let src = self.expander.to_source(ptr); | 138 | let src = self.expander.to_source(ptr); |
139 | let id = self.make_pat(pat, Ok(src)); | 139 | let id = self.make_pat(pat, Ok(src.clone())); |
140 | self.source_map.pat_map.insert(src, id); | 140 | self.source_map.pat_map.insert(src, id); |
141 | id | 141 | id |
142 | } | 142 | } |
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index 095498429..cfa0f2f76 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -20,7 +20,7 @@ impl Diagnostic for UnresolvedModule { | |||
20 | "unresolved module".to_string() | 20 | "unresolved module".to_string() |
21 | } | 21 | } |
22 | fn source(&self) -> InFile<SyntaxNodePtr> { | 22 | fn source(&self) -> InFile<SyntaxNodePtr> { |
23 | InFile { file_id: self.file, value: self.decl.into() } | 23 | InFile { file_id: self.file, value: self.decl.clone().into() } |
24 | } | 24 | } |
25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
26 | self | 26 | self |
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index 5643ecdce..a3ca302c2 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs | |||
@@ -90,7 +90,7 @@ impl AstIdMap { | |||
90 | } | 90 | } |
91 | 91 | ||
92 | pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { | 92 | pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { |
93 | self.arena[id.raw].cast::<N>().unwrap() | 93 | self.arena[id.raw].clone().cast::<N>().unwrap() |
94 | } | 94 | } |
95 | 95 | ||
96 | fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { | 96 | fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { |
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 3f18acf1d..927896d6f 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | fn source(&self) -> InFile<SyntaxNodePtr> { | 23 | fn source(&self) -> InFile<SyntaxNodePtr> { |
24 | InFile { file_id: self.file, value: self.field.into() } | 24 | InFile { file_id: self.file, value: self.field.clone().into() } |
25 | } | 25 | } |
26 | 26 | ||
27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -45,7 +45,7 @@ impl Diagnostic for MissingFields { | |||
45 | buf | 45 | buf |
46 | } | 46 | } |
47 | fn source(&self) -> InFile<SyntaxNodePtr> { | 47 | fn source(&self) -> InFile<SyntaxNodePtr> { |
48 | InFile { file_id: self.file, value: self.field_list.into() } | 48 | InFile { file_id: self.file, value: self.field_list.clone().into() } |
49 | } | 49 | } |
50 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 50 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
51 | self | 51 | self |
@@ -78,7 +78,7 @@ impl Diagnostic for MissingPatFields { | |||
78 | buf | 78 | buf |
79 | } | 79 | } |
80 | fn source(&self) -> InFile<SyntaxNodePtr> { | 80 | fn source(&self) -> InFile<SyntaxNodePtr> { |
81 | InFile { file_id: self.file, value: self.field_list.into() } | 81 | InFile { file_id: self.file, value: self.field_list.clone().into() } |
82 | } | 82 | } |
83 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 83 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
84 | self | 84 | self |
@@ -97,7 +97,7 @@ impl Diagnostic for MissingMatchArms { | |||
97 | String::from("Missing match arm") | 97 | String::from("Missing match arm") |
98 | } | 98 | } |
99 | fn source(&self) -> InFile<SyntaxNodePtr> { | 99 | fn source(&self) -> InFile<SyntaxNodePtr> { |
100 | InFile { file_id: self.file, value: self.match_expr.into() } | 100 | InFile { file_id: self.file, value: self.match_expr.clone().into() } |
101 | } | 101 | } |
102 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 102 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
103 | self | 103 | self |
@@ -115,7 +115,7 @@ impl Diagnostic for MissingOkInTailExpr { | |||
115 | "wrap return expression in Ok".to_string() | 115 | "wrap return expression in Ok".to_string() |
116 | } | 116 | } |
117 | fn source(&self) -> InFile<SyntaxNodePtr> { | 117 | fn source(&self) -> InFile<SyntaxNodePtr> { |
118 | InFile { file_id: self.file, value: self.expr.into() } | 118 | InFile { file_id: self.file, value: self.expr.clone().into() } |
119 | } | 119 | } |
120 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 120 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
121 | self | 121 | self |
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index a7c8d74ab..827b687de 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs | |||
@@ -89,7 +89,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
89 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 89 | let (_, source_map) = db.body_with_source_map(self.func.into()); |
90 | 90 | ||
91 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 91 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
92 | if let Some(expr) = source_ptr.value.left() { | 92 | if let Some(expr) = source_ptr.value.as_ref().left() { |
93 | let root = source_ptr.file_syntax(db.upcast()); | 93 | let root = source_ptr.file_syntax(db.upcast()); |
94 | if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { | 94 | if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { |
95 | if let Some(field_list) = record_lit.record_field_list() { | 95 | if let Some(field_list) = record_lit.record_field_list() { |
@@ -120,7 +120,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
120 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 120 | let (_, source_map) = db.body_with_source_map(self.func.into()); |
121 | 121 | ||
122 | if let Ok(source_ptr) = source_map.pat_syntax(id) { | 122 | if let Ok(source_ptr) = source_map.pat_syntax(id) { |
123 | if let Some(expr) = source_ptr.value.left() { | 123 | if let Some(expr) = source_ptr.value.as_ref().left() { |
124 | let root = source_ptr.file_syntax(db.upcast()); | 124 | let root = source_ptr.file_syntax(db.upcast()); |
125 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | 125 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { |
126 | if let Some(field_list) = record_pat.record_field_pat_list() { | 126 | if let Some(field_list) = record_pat.record_field_pat_list() { |
@@ -205,7 +205,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
205 | } | 205 | } |
206 | 206 | ||
207 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 207 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
208 | if let Some(expr) = source_ptr.value.left() { | 208 | if let Some(expr) = source_ptr.value.as_ref().left() { |
209 | let root = source_ptr.file_syntax(db.upcast()); | 209 | let root = source_ptr.file_syntax(db.upcast()); |
210 | if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) { | 210 | if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) { |
211 | if let (Some(match_expr), Some(arms)) = | 211 | if let (Some(match_expr), Some(arms)) = |
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 47a7b9ffd..54e31602f 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -87,7 +87,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | |||
87 | } | 87 | } |
88 | Err(SyntheticSyntax) => continue, | 88 | Err(SyntheticSyntax) => continue, |
89 | }; | 89 | }; |
90 | types.push((syntax_ptr, ty)); | 90 | types.push((syntax_ptr.clone(), ty)); |
91 | if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { | 91 | if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { |
92 | mismatches.push((syntax_ptr, mismatch)); | 92 | mismatches.push((syntax_ptr, mismatch)); |
93 | } | 93 | } |
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index da9f55a69..45b9f7802 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs | |||
@@ -235,7 +235,10 @@ fn should_show_param_hint( | |||
235 | param_name: &str, | 235 | param_name: &str, |
236 | argument: &ast::Expr, | 236 | argument: &ast::Expr, |
237 | ) -> bool { | 237 | ) -> bool { |
238 | if param_name.is_empty() || is_argument_similar_to_param(argument, param_name) { | 238 | if param_name.is_empty() |
239 | || is_argument_similar_to_param(argument, param_name) | ||
240 | || Some(param_name) == fn_signature.name.as_ref().map(String::as_str) | ||
241 | { | ||
239 | return false; | 242 | return false; |
240 | } | 243 | } |
241 | 244 | ||
@@ -247,10 +250,7 @@ fn should_show_param_hint( | |||
247 | 250 | ||
248 | // avoid displaying hints for common functions like map, filter, etc. | 251 | // avoid displaying hints for common functions like map, filter, etc. |
249 | // or other obvious words used in std | 252 | // or other obvious words used in std |
250 | if parameters_len == 1 && is_obvious_param(param_name) { | 253 | parameters_len != 1 || !is_obvious_param(param_name) |
251 | return false; | ||
252 | } | ||
253 | true | ||
254 | } | 254 | } |
255 | 255 | ||
256 | fn is_argument_similar_to_param(argument: &ast::Expr, param_name: &str) -> bool { | 256 | fn is_argument_similar_to_param(argument: &ast::Expr, param_name: &str) -> bool { |
@@ -1086,6 +1086,8 @@ impl Test { | |||
1086 | } | 1086 | } |
1087 | 1087 | ||
1088 | fn no_hints_expected(&self, _: i32, test_var: i32) {} | 1088 | fn no_hints_expected(&self, _: i32, test_var: i32) {} |
1089 | |||
1090 | fn frob(&self, frob: bool) {} | ||
1089 | } | 1091 | } |
1090 | 1092 | ||
1091 | struct Param {} | 1093 | struct Param {} |
@@ -1093,6 +1095,8 @@ struct Param {} | |||
1093 | fn different_order(param: &Param) {} | 1095 | fn different_order(param: &Param) {} |
1094 | fn different_order_mut(param: &mut Param) {} | 1096 | fn different_order_mut(param: &mut Param) {} |
1095 | 1097 | ||
1098 | fn twiddle(twiddle: bool) {} | ||
1099 | |||
1096 | fn main() { | 1100 | fn main() { |
1097 | let container: TestVarContainer = TestVarContainer { test_var: 42 }; | 1101 | let container: TestVarContainer = TestVarContainer { test_var: 42 }; |
1098 | let test: Test = Test {}; | 1102 | let test: Test = Test {}; |
@@ -1105,6 +1109,9 @@ fn main() { | |||
1105 | let test_var: i32 = 55; | 1109 | let test_var: i32 = 55; |
1106 | test_processed.no_hints_expected(22, test_var); | 1110 | test_processed.no_hints_expected(22, test_var); |
1107 | test_processed.no_hints_expected(33, container.test_var); | 1111 | test_processed.no_hints_expected(33, container.test_var); |
1112 | test_processed.frob(false); | ||
1113 | |||
1114 | twiddle(true); | ||
1108 | 1115 | ||
1109 | let param_begin: Param = Param {}; | 1116 | let param_begin: Param = Param {}; |
1110 | different_order(¶m_begin); | 1117 | different_order(¶m_begin); |
diff --git a/crates/ra_proc_macro_srv/Cargo.toml b/crates/ra_proc_macro_srv/Cargo.toml index f08de5fc7..1e0f50339 100644 --- a/crates/ra_proc_macro_srv/Cargo.toml +++ b/crates/ra_proc_macro_srv/Cargo.toml | |||
@@ -12,9 +12,12 @@ doctest = false | |||
12 | ra_tt = { path = "../ra_tt" } | 12 | ra_tt = { path = "../ra_tt" } |
13 | ra_mbe = { path = "../ra_mbe" } | 13 | ra_mbe = { path = "../ra_mbe" } |
14 | ra_proc_macro = { path = "../ra_proc_macro" } | 14 | ra_proc_macro = { path = "../ra_proc_macro" } |
15 | goblin = "0.2.1" | ||
16 | libloading = "0.6.0" | ||
17 | test_utils = { path = "../test_utils" } | ||
15 | 18 | ||
16 | [dev-dependencies] | 19 | [dev-dependencies] |
17 | cargo_metadata = "0.9.1" | 20 | cargo_metadata = "0.9.1" |
18 | difference = "2.0.0" | 21 | difference = "2.0.0" |
19 | # used as proc macro test target | 22 | # used as proc macro test target |
20 | serde_derive = "=1.0.104" \ No newline at end of file | 23 | serde_derive = "=1.0.104" |
diff --git a/crates/ra_proc_macro_srv/src/dylib.rs b/crates/ra_proc_macro_srv/src/dylib.rs new file mode 100644 index 000000000..ec63d587b --- /dev/null +++ b/crates/ra_proc_macro_srv/src/dylib.rs | |||
@@ -0,0 +1,211 @@ | |||
1 | //! Handles dynamic library loading for proc macro | ||
2 | |||
3 | use crate::{proc_macro::bridge, rustc_server::TokenStream}; | ||
4 | use std::path::Path; | ||
5 | |||
6 | use goblin::{mach::Mach, Object}; | ||
7 | use libloading::Library; | ||
8 | use ra_proc_macro::ProcMacroKind; | ||
9 | |||
10 | use std::io::Error as IoError; | ||
11 | use std::io::ErrorKind as IoErrorKind; | ||
12 | |||
13 | const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_"; | ||
14 | |||
15 | fn invalid_data_err(e: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> IoError { | ||
16 | IoError::new(IoErrorKind::InvalidData, e) | ||
17 | } | ||
18 | |||
19 | fn get_symbols_from_lib(file: &Path) -> Result<Vec<String>, IoError> { | ||
20 | let buffer = std::fs::read(file)?; | ||
21 | let object = Object::parse(&buffer).map_err(invalid_data_err)?; | ||
22 | |||
23 | match object { | ||
24 | Object::Elf(elf) => { | ||
25 | let symbols = elf.dynstrtab.to_vec().map_err(invalid_data_err)?; | ||
26 | let names = symbols.iter().map(|s| s.to_string()).collect(); | ||
27 | Ok(names) | ||
28 | } | ||
29 | Object::PE(pe) => { | ||
30 | let symbol_names = | ||
31 | pe.exports.iter().flat_map(|s| s.name).map(|n| n.to_string()).collect(); | ||
32 | Ok(symbol_names) | ||
33 | } | ||
34 | Object::Mach(mach) => match mach { | ||
35 | Mach::Binary(binary) => { | ||
36 | let exports = binary.exports().map_err(invalid_data_err)?; | ||
37 | let names = exports | ||
38 | .into_iter() | ||
39 | .map(|s| { | ||
40 | // In macos doc: | ||
41 | // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/dlsym.3.html | ||
42 | // Unlike other dyld API's, the symbol name passed to dlsym() must NOT be | ||
43 | // prepended with an underscore. | ||
44 | if s.name.starts_with("_") { | ||
45 | s.name[1..].to_string() | ||
46 | } else { | ||
47 | s.name | ||
48 | } | ||
49 | }) | ||
50 | .collect(); | ||
51 | Ok(names) | ||
52 | } | ||
53 | Mach::Fat(_) => Ok(vec![]), | ||
54 | }, | ||
55 | Object::Archive(_) | Object::Unknown(_) => Ok(vec![]), | ||
56 | } | ||
57 | } | ||
58 | |||
59 | fn is_derive_registrar_symbol(symbol: &str) -> bool { | ||
60 | symbol.contains(NEW_REGISTRAR_SYMBOL) | ||
61 | } | ||
62 | |||
63 | fn find_registrar_symbol(file: &Path) -> Result<Option<String>, IoError> { | ||
64 | let symbols = get_symbols_from_lib(file)?; | ||
65 | Ok(symbols.into_iter().find(|s| is_derive_registrar_symbol(s))) | ||
66 | } | ||
67 | |||
68 | /// Loads dynamic library in platform dependent manner. | ||
69 | /// | ||
70 | /// For unix, you have to use RTLD_DEEPBIND flag to escape problems described | ||
71 | /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample) | ||
72 | /// and [here](https://github.com/rust-lang/rust/issues/60593). | ||
73 | /// | ||
74 | /// Usage of RTLD_DEEPBIND | ||
75 | /// [here](https://github.com/fedochet/rust-proc-macro-panic-inside-panic-expample/issues/1) | ||
76 | /// | ||
77 | /// It seems that on Windows that behaviour is default, so we do nothing in that case. | ||
78 | #[cfg(windows)] | ||
79 | fn load_library(file: &Path) -> Result<Library, libloading::Error> { | ||
80 | Library::new(file) | ||
81 | } | ||
82 | |||
83 | #[cfg(unix)] | ||
84 | fn load_library(file: &Path) -> Result<Library, libloading::Error> { | ||
85 | use libloading::os::unix::Library as UnixLibrary; | ||
86 | use std::os::raw::c_int; | ||
87 | |||
88 | const RTLD_NOW: c_int = 0x00002; | ||
89 | const RTLD_DEEPBIND: c_int = 0x00008; | ||
90 | |||
91 | UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) | ||
92 | } | ||
93 | |||
94 | struct ProcMacroLibraryLibloading { | ||
95 | // Hold the dylib to prevent it for unloadeding | ||
96 | _lib: Library, | ||
97 | exported_macros: Vec<bridge::client::ProcMacro>, | ||
98 | } | ||
99 | |||
100 | impl ProcMacroLibraryLibloading { | ||
101 | fn open(file: &Path) -> Result<Self, IoError> { | ||
102 | let symbol_name = find_registrar_symbol(file)? | ||
103 | .ok_or(invalid_data_err(format!("Cannot find registrar symbol in file {:?}", file)))?; | ||
104 | |||
105 | let lib = load_library(file).map_err(invalid_data_err)?; | ||
106 | let exported_macros = { | ||
107 | let macros: libloading::Symbol<&&[bridge::client::ProcMacro]> = | ||
108 | unsafe { lib.get(symbol_name.as_bytes()) }.map_err(invalid_data_err)?; | ||
109 | macros.to_vec() | ||
110 | }; | ||
111 | |||
112 | Ok(ProcMacroLibraryLibloading { _lib: lib, exported_macros }) | ||
113 | } | ||
114 | } | ||
115 | |||
116 | type ProcMacroLibraryImpl = ProcMacroLibraryLibloading; | ||
117 | |||
118 | pub struct Expander { | ||
119 | libs: Vec<ProcMacroLibraryImpl>, | ||
120 | } | ||
121 | |||
122 | impl Expander { | ||
123 | pub fn new<P: AsRef<Path>>(lib: &P) -> Result<Expander, String> { | ||
124 | let mut libs = vec![]; | ||
125 | /* Some libraries for dynamic loading require canonicalized path (even when it is | ||
126 | already absolute | ||
127 | */ | ||
128 | let lib = | ||
129 | lib.as_ref().canonicalize().expect(&format!("Cannot canonicalize {:?}", lib.as_ref())); | ||
130 | |||
131 | let library = ProcMacroLibraryImpl::open(&lib).map_err(|e| e.to_string())?; | ||
132 | libs.push(library); | ||
133 | |||
134 | Ok(Expander { libs }) | ||
135 | } | ||
136 | |||
137 | pub fn expand( | ||
138 | &self, | ||
139 | macro_name: &str, | ||
140 | macro_body: &ra_tt::Subtree, | ||
141 | attributes: Option<&ra_tt::Subtree>, | ||
142 | ) -> Result<ra_tt::Subtree, bridge::PanicMessage> { | ||
143 | let parsed_body = TokenStream::with_subtree(macro_body.clone()); | ||
144 | |||
145 | let parsed_attributes = attributes | ||
146 | .map_or(crate::rustc_server::TokenStream::new(), |attr| { | ||
147 | TokenStream::with_subtree(attr.clone()) | ||
148 | }); | ||
149 | |||
150 | for lib in &self.libs { | ||
151 | for proc_macro in &lib.exported_macros { | ||
152 | match proc_macro { | ||
153 | bridge::client::ProcMacro::CustomDerive { trait_name, client, .. } | ||
154 | if *trait_name == macro_name => | ||
155 | { | ||
156 | let res = client.run( | ||
157 | &crate::proc_macro::bridge::server::SameThread, | ||
158 | crate::rustc_server::Rustc::default(), | ||
159 | parsed_body, | ||
160 | ); | ||
161 | return res.map(|it| it.subtree); | ||
162 | } | ||
163 | bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => { | ||
164 | let res = client.run( | ||
165 | &crate::proc_macro::bridge::server::SameThread, | ||
166 | crate::rustc_server::Rustc::default(), | ||
167 | parsed_body, | ||
168 | ); | ||
169 | return res.map(|it| it.subtree); | ||
170 | } | ||
171 | bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => { | ||
172 | let res = client.run( | ||
173 | &crate::proc_macro::bridge::server::SameThread, | ||
174 | crate::rustc_server::Rustc::default(), | ||
175 | parsed_attributes, | ||
176 | parsed_body, | ||
177 | ); | ||
178 | |||
179 | return res.map(|it| it.subtree); | ||
180 | } | ||
181 | _ => continue, | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | |||
186 | Err(bridge::PanicMessage::String("Nothing to expand".to_string())) | ||
187 | } | ||
188 | |||
189 | pub fn list_macros(&self) -> Result<Vec<(String, ProcMacroKind)>, bridge::PanicMessage> { | ||
190 | let mut result = vec![]; | ||
191 | |||
192 | for lib in &self.libs { | ||
193 | for proc_macro in &lib.exported_macros { | ||
194 | let res = match proc_macro { | ||
195 | bridge::client::ProcMacro::CustomDerive { trait_name, .. } => { | ||
196 | (trait_name.to_string(), ProcMacroKind::CustomDerive) | ||
197 | } | ||
198 | bridge::client::ProcMacro::Bang { name, .. } => { | ||
199 | (name.to_string(), ProcMacroKind::FuncLike) | ||
200 | } | ||
201 | bridge::client::ProcMacro::Attr { name, .. } => { | ||
202 | (name.to_string(), ProcMacroKind::Attr) | ||
203 | } | ||
204 | }; | ||
205 | result.push(res); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | Ok(result) | ||
210 | } | ||
211 | } | ||
diff --git a/crates/ra_proc_macro_srv/src/lib.rs b/crates/ra_proc_macro_srv/src/lib.rs index f376df236..59716cbb3 100644 --- a/crates/ra_proc_macro_srv/src/lib.rs +++ b/crates/ra_proc_macro_srv/src/lib.rs | |||
@@ -17,13 +17,41 @@ mod proc_macro; | |||
17 | #[doc(hidden)] | 17 | #[doc(hidden)] |
18 | mod rustc_server; | 18 | mod rustc_server; |
19 | 19 | ||
20 | mod dylib; | ||
21 | |||
20 | use proc_macro::bridge::client::TokenStream; | 22 | use proc_macro::bridge::client::TokenStream; |
21 | use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; | 23 | use ra_proc_macro::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask}; |
22 | 24 | ||
23 | pub fn expand_task(_task: &ExpansionTask) -> Result<ExpansionResult, String> { | 25 | pub fn expand_task(task: &ExpansionTask) -> Result<ExpansionResult, String> { |
24 | unimplemented!() | 26 | let expander = dylib::Expander::new(&task.lib) |
27 | .expect(&format!("Cannot expand with provided libraries: ${:?}", &task.lib)); | ||
28 | |||
29 | match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) { | ||
30 | Ok(expansion) => Ok(ExpansionResult { expansion }), | ||
31 | Err(msg) => { | ||
32 | let reason = format!( | ||
33 | "Cannot perform expansion for {}: error {:?}!", | ||
34 | &task.macro_name, | ||
35 | msg.as_str() | ||
36 | ); | ||
37 | Err(reason) | ||
38 | } | ||
39 | } | ||
25 | } | 40 | } |
26 | 41 | ||
27 | pub fn list_macros(_task: &ListMacrosTask) -> Result<ListMacrosResult, String> { | 42 | pub fn list_macros(task: &ListMacrosTask) -> Result<ListMacrosResult, String> { |
28 | unimplemented!() | 43 | let expander = dylib::Expander::new(&task.lib) |
44 | .expect(&format!("Cannot expand with provided libraries: ${:?}", &task.lib)); | ||
45 | |||
46 | match expander.list_macros() { | ||
47 | Ok(macros) => Ok(ListMacrosResult { macros }), | ||
48 | Err(msg) => { | ||
49 | let reason = | ||
50 | format!("Cannot perform expansion for {:?}: error {:?}!", &task.lib, msg.as_str()); | ||
51 | Err(reason) | ||
52 | } | ||
53 | } | ||
29 | } | 54 | } |
55 | |||
56 | #[cfg(test)] | ||
57 | mod tests; | ||
diff --git a/crates/ra_proc_macro_srv/src/rustc_server.rs b/crates/ra_proc_macro_srv/src/rustc_server.rs index 92d1fd989..ec0d35692 100644 --- a/crates/ra_proc_macro_srv/src/rustc_server.rs +++ b/crates/ra_proc_macro_srv/src/rustc_server.rs | |||
@@ -34,6 +34,10 @@ impl TokenStream { | |||
34 | TokenStream { subtree: Default::default() } | 34 | TokenStream { subtree: Default::default() } |
35 | } | 35 | } |
36 | 36 | ||
37 | pub fn with_subtree(subtree: tt::Subtree) -> Self { | ||
38 | TokenStream { subtree } | ||
39 | } | ||
40 | |||
37 | pub fn is_empty(&self) -> bool { | 41 | pub fn is_empty(&self) -> bool { |
38 | self.subtree.token_trees.is_empty() | 42 | self.subtree.token_trees.is_empty() |
39 | } | 43 | } |
diff --git a/crates/ra_proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt b/crates/ra_proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt new file mode 100644 index 000000000..24507d98d --- /dev/null +++ b/crates/ra_proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt | |||
@@ -0,0 +1,188 @@ | |||
1 | SUBTREE $ | ||
2 | PUNCH # [alone] 4294967295 | ||
3 | SUBTREE [] 4294967295 | ||
4 | IDENT allow 4294967295 | ||
5 | SUBTREE () 4294967295 | ||
6 | IDENT non_upper_case_globals 4294967295 | ||
7 | PUNCH , [alone] 4294967295 | ||
8 | IDENT unused_attributes 4294967295 | ||
9 | PUNCH , [alone] 4294967295 | ||
10 | IDENT unused_qualifications 4294967295 | ||
11 | IDENT const 4294967295 | ||
12 | IDENT _IMPL_SERIALIZE_FOR_Foo 4294967295 | ||
13 | PUNCH : [alone] 4294967295 | ||
14 | SUBTREE () 4294967295 | ||
15 | PUNCH = [alone] 4294967295 | ||
16 | SUBTREE {} 4294967295 | ||
17 | PUNCH # [alone] 4294967295 | ||
18 | SUBTREE [] 4294967295 | ||
19 | IDENT allow 4294967295 | ||
20 | SUBTREE () 4294967295 | ||
21 | IDENT unknown_lints 4294967295 | ||
22 | PUNCH # [alone] 4294967295 | ||
23 | SUBTREE [] 4294967295 | ||
24 | IDENT cfg_attr 4294967295 | ||
25 | SUBTREE () 4294967295 | ||
26 | IDENT feature 4294967295 | ||
27 | PUNCH = [alone] 4294967295 | ||
28 | SUBTREE $ | ||
29 | LITERAL "cargo-clippy" 0 | ||
30 | PUNCH , [alone] 4294967295 | ||
31 | IDENT allow 4294967295 | ||
32 | SUBTREE () 4294967295 | ||
33 | IDENT useless_attribute 4294967295 | ||
34 | PUNCH # [alone] 4294967295 | ||
35 | SUBTREE [] 4294967295 | ||
36 | IDENT allow 4294967295 | ||
37 | SUBTREE () 4294967295 | ||
38 | IDENT rust_2018_idioms 4294967295 | ||
39 | IDENT extern 4294967295 | ||
40 | IDENT crate 4294967295 | ||
41 | IDENT serde 4294967295 | ||
42 | IDENT as 4294967295 | ||
43 | IDENT _serde 4294967295 | ||
44 | PUNCH ; [alone] 4294967295 | ||
45 | PUNCH # [alone] 4294967295 | ||
46 | SUBTREE [] 4294967295 | ||
47 | IDENT allow 4294967295 | ||
48 | SUBTREE () 4294967295 | ||
49 | IDENT unused_macros 4294967295 | ||
50 | IDENT macro_rules 4294967295 | ||
51 | PUNCH ! [alone] 4294967295 | ||
52 | IDENT try 4294967295 | ||
53 | SUBTREE {} 4294967295 | ||
54 | SUBTREE () 4294967295 | ||
55 | PUNCH $ [alone] 4294967295 | ||
56 | IDENT __expr 4294967295 | ||
57 | PUNCH : [alone] 4294967295 | ||
58 | IDENT expr 4294967295 | ||
59 | PUNCH = [joint] 4294967295 | ||
60 | PUNCH > [alone] 4294967295 | ||
61 | SUBTREE {} 4294967295 | ||
62 | IDENT match 4294967295 | ||
63 | PUNCH $ [alone] 4294967295 | ||
64 | IDENT __expr 4294967295 | ||
65 | SUBTREE {} 4294967295 | ||
66 | IDENT _serde 4294967295 | ||
67 | PUNCH : [joint] 4294967295 | ||
68 | PUNCH : [alone] 4294967295 | ||
69 | IDENT export 4294967295 | ||
70 | PUNCH : [joint] 4294967295 | ||
71 | PUNCH : [alone] 4294967295 | ||
72 | IDENT Ok 4294967295 | ||
73 | SUBTREE () 4294967295 | ||
74 | IDENT __val 4294967295 | ||
75 | PUNCH = [joint] 4294967295 | ||
76 | PUNCH > [alone] 4294967295 | ||
77 | IDENT __val 4294967295 | ||
78 | PUNCH , [alone] 4294967295 | ||
79 | IDENT _serde 4294967295 | ||
80 | PUNCH : [joint] 4294967295 | ||
81 | PUNCH : [alone] 4294967295 | ||
82 | IDENT export 4294967295 | ||
83 | PUNCH : [joint] 4294967295 | ||
84 | PUNCH : [alone] 4294967295 | ||
85 | IDENT Err 4294967295 | ||
86 | SUBTREE () 4294967295 | ||
87 | IDENT __err 4294967295 | ||
88 | PUNCH = [joint] 4294967295 | ||
89 | PUNCH > [alone] 4294967295 | ||
90 | SUBTREE {} 4294967295 | ||
91 | IDENT return 4294967295 | ||
92 | IDENT _serde 4294967295 | ||
93 | PUNCH : [joint] 4294967295 | ||
94 | PUNCH : [alone] 4294967295 | ||
95 | IDENT export 4294967295 | ||
96 | PUNCH : [joint] 4294967295 | ||
97 | PUNCH : [alone] 4294967295 | ||
98 | IDENT Err 4294967295 | ||
99 | SUBTREE () 4294967295 | ||
100 | IDENT __err 4294967295 | ||
101 | PUNCH ; [alone] 4294967295 | ||
102 | PUNCH # [alone] 4294967295 | ||
103 | SUBTREE [] 4294967295 | ||
104 | IDENT automatically_derived 4294967295 | ||
105 | IDENT impl 4294967295 | ||
106 | IDENT _serde 4294967295 | ||
107 | PUNCH : [joint] 4294967295 | ||
108 | PUNCH : [alone] 4294967295 | ||
109 | IDENT Serialize 4294967295 | ||
110 | IDENT for 4294967295 | ||
111 | IDENT Foo 1 | ||
112 | SUBTREE {} 4294967295 | ||
113 | IDENT fn 4294967295 | ||
114 | IDENT serialize 4294967295 | ||
115 | PUNCH < [alone] 4294967295 | ||
116 | IDENT __S 4294967295 | ||
117 | PUNCH > [alone] 4294967295 | ||
118 | SUBTREE () 4294967295 | ||
119 | PUNCH & [alone] 4294967295 | ||
120 | IDENT self 4294967295 | ||
121 | PUNCH , [alone] 4294967295 | ||
122 | IDENT __serializer 4294967295 | ||
123 | PUNCH : [alone] 4294967295 | ||
124 | IDENT __S 4294967295 | ||
125 | PUNCH - [joint] 4294967295 | ||
126 | PUNCH > [alone] 4294967295 | ||
127 | IDENT _serde 4294967295 | ||
128 | PUNCH : [joint] 4294967295 | ||
129 | PUNCH : [alone] 4294967295 | ||
130 | IDENT export 4294967295 | ||
131 | PUNCH : [joint] 4294967295 | ||
132 | PUNCH : [alone] 4294967295 | ||
133 | IDENT Result 4294967295 | ||
134 | PUNCH < [alone] 4294967295 | ||
135 | IDENT __S 4294967295 | ||
136 | PUNCH : [joint] 4294967295 | ||
137 | PUNCH : [alone] 4294967295 | ||
138 | IDENT Ok 4294967295 | ||
139 | PUNCH , [alone] 4294967295 | ||
140 | IDENT __S 4294967295 | ||
141 | PUNCH : [joint] 4294967295 | ||
142 | PUNCH : [alone] 4294967295 | ||
143 | IDENT Error 4294967295 | ||
144 | PUNCH > [alone] 4294967295 | ||
145 | IDENT where 4294967295 | ||
146 | IDENT __S 4294967295 | ||
147 | PUNCH : [alone] 4294967295 | ||
148 | IDENT _serde 4294967295 | ||
149 | PUNCH : [joint] 4294967295 | ||
150 | PUNCH : [alone] 4294967295 | ||
151 | IDENT Serializer 4294967295 | ||
152 | PUNCH , [alone] 4294967295 | ||
153 | SUBTREE {} 4294967295 | ||
154 | IDENT let 4294967295 | ||
155 | IDENT __serde_state 4294967295 | ||
156 | PUNCH = [alone] 4294967295 | ||
157 | IDENT try 4294967295 | ||
158 | PUNCH ! [alone] 4294967295 | ||
159 | SUBTREE () 4294967295 | ||
160 | IDENT _serde 4294967295 | ||
161 | PUNCH : [joint] 4294967295 | ||
162 | PUNCH : [alone] 4294967295 | ||
163 | IDENT Serializer 4294967295 | ||
164 | PUNCH : [joint] 4294967295 | ||
165 | PUNCH : [alone] 4294967295 | ||
166 | IDENT serialize_struct 4294967295 | ||
167 | SUBTREE () 4294967295 | ||
168 | IDENT __serializer 4294967295 | ||
169 | PUNCH , [alone] 4294967295 | ||
170 | LITERAL "Foo" 4294967295 | ||
171 | PUNCH , [alone] 4294967295 | ||
172 | IDENT false 4294967295 | ||
173 | IDENT as 4294967295 | ||
174 | IDENT usize 4294967295 | ||
175 | PUNCH ; [alone] 4294967295 | ||
176 | IDENT _serde 4294967295 | ||
177 | PUNCH : [joint] 4294967295 | ||
178 | PUNCH : [alone] 4294967295 | ||
179 | IDENT ser 4294967295 | ||
180 | PUNCH : [joint] 4294967295 | ||
181 | PUNCH : [alone] 4294967295 | ||
182 | IDENT SerializeStruct 4294967295 | ||
183 | PUNCH : [joint] 4294967295 | ||
184 | PUNCH : [alone] 4294967295 | ||
185 | IDENT end 4294967295 | ||
186 | SUBTREE () 4294967295 | ||
187 | IDENT __serde_state 4294967295 | ||
188 | PUNCH ; [alone] 4294967295 \ No newline at end of file | ||
diff --git a/crates/ra_proc_macro_srv/src/tests/mod.rs b/crates/ra_proc_macro_srv/src/tests/mod.rs new file mode 100644 index 000000000..03f79bc5d --- /dev/null +++ b/crates/ra_proc_macro_srv/src/tests/mod.rs | |||
@@ -0,0 +1,47 @@ | |||
1 | //! proc-macro tests | ||
2 | |||
3 | #[macro_use] | ||
4 | mod utils; | ||
5 | use test_utils::assert_eq_text; | ||
6 | use utils::*; | ||
7 | |||
8 | #[test] | ||
9 | fn test_derive_serialize_proc_macro() { | ||
10 | assert_expand( | ||
11 | "serde_derive", | ||
12 | "Serialize", | ||
13 | "1.0.104", | ||
14 | r##"struct Foo {}"##, | ||
15 | include_str!("fixtures/test_serialize_proc_macro.txt"), | ||
16 | ); | ||
17 | } | ||
18 | |||
19 | #[test] | ||
20 | fn test_derive_serialize_proc_macro_failed() { | ||
21 | assert_expand( | ||
22 | "serde_derive", | ||
23 | "Serialize", | ||
24 | "1.0.104", | ||
25 | r##" | ||
26 | struct {} | ||
27 | "##, | ||
28 | r##" | ||
29 | SUBTREE $ | ||
30 | IDENT compile_error 4294967295 | ||
31 | PUNCH ! [alone] 4294967295 | ||
32 | SUBTREE {} 4294967295 | ||
33 | LITERAL "expected identifier" 4294967295 | ||
34 | "##, | ||
35 | ); | ||
36 | } | ||
37 | |||
38 | #[test] | ||
39 | fn test_derive_proc_macro_list() { | ||
40 | let res = list("serde_derive", "1.0.104").join("\n"); | ||
41 | |||
42 | assert_eq_text!( | ||
43 | &res, | ||
44 | r#"Serialize [CustomDerive] | ||
45 | Deserialize [CustomDerive]"# | ||
46 | ); | ||
47 | } | ||
diff --git a/crates/ra_proc_macro_srv/src/tests/utils.rs b/crates/ra_proc_macro_srv/src/tests/utils.rs new file mode 100644 index 000000000..1ee409449 --- /dev/null +++ b/crates/ra_proc_macro_srv/src/tests/utils.rs | |||
@@ -0,0 +1,65 @@ | |||
1 | //! utils used in proc-macro tests | ||
2 | |||
3 | use crate::dylib; | ||
4 | use crate::list_macros; | ||
5 | pub use difference::Changeset as __Changeset; | ||
6 | use ra_proc_macro::ListMacrosTask; | ||
7 | use std::str::FromStr; | ||
8 | use test_utils::assert_eq_text; | ||
9 | |||
10 | mod fixtures { | ||
11 | use cargo_metadata::{parse_messages, Message}; | ||
12 | use std::process::Command; | ||
13 | |||
14 | // Use current project metadata to get the proc-macro dylib path | ||
15 | pub fn dylib_path(crate_name: &str, version: &str) -> std::path::PathBuf { | ||
16 | let command = Command::new("cargo") | ||
17 | .args(&["check", "--message-format", "json"]) | ||
18 | .output() | ||
19 | .unwrap() | ||
20 | .stdout; | ||
21 | |||
22 | for message in parse_messages(command.as_slice()) { | ||
23 | match message.unwrap() { | ||
24 | Message::CompilerArtifact(artifact) => { | ||
25 | if artifact.target.kind.contains(&"proc-macro".to_string()) { | ||
26 | let repr = format!("{} {}", crate_name, version); | ||
27 | if artifact.package_id.repr.starts_with(&repr) { | ||
28 | return artifact.filenames[0].clone(); | ||
29 | } | ||
30 | } | ||
31 | } | ||
32 | _ => (), // Unknown message | ||
33 | } | ||
34 | } | ||
35 | |||
36 | panic!("No proc-macro dylib for {} found!", crate_name); | ||
37 | } | ||
38 | } | ||
39 | |||
40 | fn parse_string(code: &str) -> Option<crate::rustc_server::TokenStream> { | ||
41 | Some(crate::rustc_server::TokenStream::from_str(code).unwrap()) | ||
42 | } | ||
43 | |||
44 | pub fn assert_expand( | ||
45 | crate_name: &str, | ||
46 | macro_name: &str, | ||
47 | version: &str, | ||
48 | fixture: &str, | ||
49 | expect: &str, | ||
50 | ) { | ||
51 | let path = fixtures::dylib_path(crate_name, version); | ||
52 | let expander = dylib::Expander::new(&path).unwrap(); | ||
53 | let fixture = parse_string(fixture).unwrap(); | ||
54 | |||
55 | let res = expander.expand(macro_name, &fixture.subtree, None).unwrap(); | ||
56 | assert_eq_text!(&format!("{:?}", res), &expect.trim()); | ||
57 | } | ||
58 | |||
59 | pub fn list(crate_name: &str, version: &str) -> Vec<String> { | ||
60 | let path = fixtures::dylib_path(crate_name, version); | ||
61 | let task = ListMacrosTask { lib: path }; | ||
62 | |||
63 | let res = list_macros(&task).unwrap(); | ||
64 | res.macros.into_iter().map(|(name, kind)| format!("{} [{:?}]", name, kind)).collect() | ||
65 | } | ||
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs index db6230aab..bc48a2e71 100644 --- a/crates/ra_syntax/src/ptr.rs +++ b/crates/ra_syntax/src/ptr.rs | |||
@@ -10,7 +10,7 @@ use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange}; | |||
10 | 10 | ||
11 | /// A pointer to a syntax node inside a file. It can be used to remember a | 11 | /// A pointer to a syntax node inside a file. It can be used to remember a |
12 | /// specific node across reparses of the same file. | 12 | /// specific node across reparses of the same file. |
13 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 13 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
14 | pub struct SyntaxNodePtr { | 14 | pub struct SyntaxNodePtr { |
15 | pub(crate) range: TextRange, | 15 | pub(crate) range: TextRange, |
16 | kind: SyntaxKind, | 16 | kind: SyntaxKind, |
@@ -21,7 +21,7 @@ impl SyntaxNodePtr { | |||
21 | SyntaxNodePtr { range: node.text_range(), kind: node.kind() } | 21 | SyntaxNodePtr { range: node.text_range(), kind: node.kind() } |
22 | } | 22 | } |
23 | 23 | ||
24 | pub fn to_node(self, root: &SyntaxNode) -> SyntaxNode { | 24 | pub fn to_node(&self, root: &SyntaxNode) -> SyntaxNode { |
25 | assert!(root.parent().is_none()); | 25 | assert!(root.parent().is_none()); |
26 | successors(Some(root.clone()), |node| { | 26 | successors(Some(root.clone()), |node| { |
27 | node.children().find(|it| self.range.is_subrange(&it.text_range())) | 27 | node.children().find(|it| self.range.is_subrange(&it.text_range())) |
@@ -30,11 +30,11 @@ impl SyntaxNodePtr { | |||
30 | .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self)) | 30 | .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self)) |
31 | } | 31 | } |
32 | 32 | ||
33 | pub fn range(self) -> TextRange { | 33 | pub fn range(&self) -> TextRange { |
34 | self.range | 34 | self.range |
35 | } | 35 | } |
36 | 36 | ||
37 | pub fn kind(self) -> SyntaxKind { | 37 | pub fn kind(&self) -> SyntaxKind { |
38 | self.kind | 38 | self.kind |
39 | } | 39 | } |
40 | 40 | ||
@@ -53,10 +53,9 @@ pub struct AstPtr<N: AstNode> { | |||
53 | _ty: PhantomData<fn() -> N>, | 53 | _ty: PhantomData<fn() -> N>, |
54 | } | 54 | } |
55 | 55 | ||
56 | impl<N: AstNode> Copy for AstPtr<N> {} | ||
57 | impl<N: AstNode> Clone for AstPtr<N> { | 56 | impl<N: AstNode> Clone for AstPtr<N> { |
58 | fn clone(&self) -> AstPtr<N> { | 57 | fn clone(&self) -> AstPtr<N> { |
59 | *self | 58 | AstPtr { raw: self.raw.clone(), _ty: PhantomData } |
60 | } | 59 | } |
61 | } | 60 | } |
62 | 61 | ||
@@ -79,13 +78,13 @@ impl<N: AstNode> AstPtr<N> { | |||
79 | AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData } | 78 | AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData } |
80 | } | 79 | } |
81 | 80 | ||
82 | pub fn to_node(self, root: &SyntaxNode) -> N { | 81 | pub fn to_node(&self, root: &SyntaxNode) -> N { |
83 | let syntax_node = self.raw.to_node(root); | 82 | let syntax_node = self.raw.to_node(root); |
84 | N::cast(syntax_node).unwrap() | 83 | N::cast(syntax_node).unwrap() |
85 | } | 84 | } |
86 | 85 | ||
87 | pub fn syntax_node_ptr(self) -> SyntaxNodePtr { | 86 | pub fn syntax_node_ptr(&self) -> SyntaxNodePtr { |
88 | self.raw | 87 | self.raw.clone() |
89 | } | 88 | } |
90 | 89 | ||
91 | pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> { | 90 | pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> { |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 69133e4e4..43062ea10 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -152,7 +152,9 @@ pub(crate) fn load( | |||
152 | &extern_source_roots, | 152 | &extern_source_roots, |
153 | proc_macro_client, | 153 | proc_macro_client, |
154 | &mut |path: &Path| { | 154 | &mut |path: &Path| { |
155 | let vfs_file = vfs.load(path); | 155 | // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs |
156 | let path = path.canonicalize().ok()?; | ||
157 | let vfs_file = vfs.load(&path); | ||
156 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); | 158 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); |
157 | vfs_file.map(vfs_file_to_id) | 159 | vfs_file.map(vfs_file_to_id) |
158 | }, | 160 | }, |
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 365f57d8c..6c42e1d76 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs | |||
@@ -139,7 +139,9 @@ impl WorldState { | |||
139 | // Create crate graph from all the workspaces | 139 | // Create crate graph from all the workspaces |
140 | let mut crate_graph = CrateGraph::default(); | 140 | let mut crate_graph = CrateGraph::default(); |
141 | let mut load = |path: &std::path::Path| { | 141 | let mut load = |path: &std::path::Path| { |
142 | let vfs_file = vfs.load(path); | 142 | // Some path from metadata will be non canonicalized, e.g. /foo/../bar/lib.rs |
143 | let path = path.canonicalize().ok()?; | ||
144 | let vfs_file = vfs.load(&path); | ||
143 | vfs_file.map(|f| FileId(f.0)) | 145 | vfs_file.map(|f| FileId(f.0)) |
144 | }; | 146 | }; |
145 | 147 | ||
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 21c1c9f23..35a05131c 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -66,23 +66,44 @@ export class Config { | |||
66 | return vscode.workspace.getConfiguration(this.rootSection); | 66 | return vscode.workspace.getConfiguration(this.rootSection); |
67 | } | 67 | } |
68 | 68 | ||
69 | get serverPath() { return this.cfg.get<null | string>("serverPath")!; } | 69 | /** |
70 | get channel() { return this.cfg.get<UpdatesChannel>("updates.channel")!; } | 70 | * Beware that postfix `!` operator erases both `null` and `undefined`. |
71 | get askBeforeDownload() { return this.cfg.get<boolean>("updates.askBeforeDownload")!; } | 71 | * This is why the following doesn't work as expected: |
72 | get traceExtension() { return this.cfg.get<boolean>("trace.extension")!; } | 72 | * |
73 | * ```ts | ||
74 | * const nullableNum = vscode | ||
75 | * .workspace | ||
76 | * .getConfiguration | ||
77 | * .getConfiguration("rust-analyer") | ||
78 | * .get<number | null>(path)!; | ||
79 | * | ||
80 | * // What happens is that type of `nullableNum` is `number` but not `null | number`: | ||
81 | * const fullFledgedNum: number = nullableNum; | ||
82 | * ``` | ||
83 | * So this getter handles this quirk by not requiring the caller to use postfix `!` | ||
84 | */ | ||
85 | private get<T>(path: string): T { | ||
86 | return this.cfg.get<T>(path)!; | ||
87 | } | ||
88 | |||
89 | get serverPath() { return this.get<null | string>("serverPath"); } | ||
90 | get channel() { return this.get<UpdatesChannel>("updates.channel"); } | ||
91 | get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); } | ||
92 | get traceExtension() { return this.get<boolean>("trace.extension"); } | ||
93 | |||
73 | 94 | ||
74 | get inlayHints() { | 95 | get inlayHints() { |
75 | return { | 96 | return { |
76 | typeHints: this.cfg.get<boolean>("inlayHints.typeHints")!, | 97 | typeHints: this.get<boolean>("inlayHints.typeHints"), |
77 | parameterHints: this.cfg.get<boolean>("inlayHints.parameterHints")!, | 98 | parameterHints: this.get<boolean>("inlayHints.parameterHints"), |
78 | chainingHints: this.cfg.get<boolean>("inlayHints.chainingHints")!, | 99 | chainingHints: this.get<boolean>("inlayHints.chainingHints"), |
79 | maxLength: this.cfg.get<null | number>("inlayHints.maxLength")!, | 100 | maxLength: this.get<null | number>("inlayHints.maxLength"), |
80 | }; | 101 | }; |
81 | } | 102 | } |
82 | 103 | ||
83 | get checkOnSave() { | 104 | get checkOnSave() { |
84 | return { | 105 | return { |
85 | command: this.cfg.get<string>("checkOnSave.command")!, | 106 | command: this.get<string>("checkOnSave.command"), |
86 | }; | 107 | }; |
87 | } | 108 | } |
88 | } | 109 | } |
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index 6a8bd942e..da74f03d2 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts | |||
@@ -229,13 +229,13 @@ interface InlaysDecorations { | |||
229 | } | 229 | } |
230 | 230 | ||
231 | interface RustSourceFile { | 231 | interface RustSourceFile { |
232 | /* | 232 | /** |
233 | * Source of the token to cancel in-flight inlay hints request if any. | 233 | * Source of the token to cancel in-flight inlay hints request if any. |
234 | */ | 234 | */ |
235 | inlaysRequest: null | vscode.CancellationTokenSource; | 235 | inlaysRequest: null | vscode.CancellationTokenSource; |
236 | /** | 236 | /** |
237 | * Last applied decorations. | 237 | * Last applied decorations. |
238 | */ | 238 | */ |
239 | cachedDecorations: null | InlaysDecorations; | 239 | cachedDecorations: null | InlaysDecorations; |
240 | 240 | ||
241 | document: RustDocument; | 241 | document: RustDocument; |