diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/assists/src/handlers/extract_assignment.rs | 103 | ||||
-rw-r--r-- | crates/cfg/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/completion/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/hir_def/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/hir_def/src/diagnostics.rs | 4 | ||||
-rw-r--r-- | crates/hir_def/src/path/lower.rs | 2 | ||||
-rw-r--r-- | crates/hir_expand/src/hygiene.rs | 151 | ||||
-rw-r--r-- | crates/hir_expand/src/lib.rs | 11 | ||||
-rw-r--r-- | crates/hir_ty/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/macros.rs | 31 | ||||
-rw-r--r-- | crates/ide/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ide_db/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/mbe/src/mbe_expander/matcher.rs | 2 | ||||
-rw-r--r-- | crates/mbe/src/mbe_expander/transcriber.rs | 20 | ||||
-rw-r--r-- | crates/mbe/src/parser.rs | 11 | ||||
-rw-r--r-- | crates/rust-analyzer/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ssr/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/syntax/Cargo.toml | 2 |
18 files changed, 154 insertions, 199 deletions
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/extract_assignment.rs index 281cf5d24..ae99598c0 100644 --- a/crates/assists/src/handlers/extract_assignment.rs +++ b/crates/assists/src/handlers/extract_assignment.rs | |||
@@ -1,4 +1,3 @@ | |||
1 | use hir::AsName; | ||
2 | use syntax::{ | 1 | use syntax::{ |
3 | ast::{self, edit::AstNodeEdit, make}, | 2 | ast::{self, edit::AstNodeEdit, make}, |
4 | AstNode, | 3 | AstNode, |
@@ -38,15 +37,23 @@ use crate::{ | |||
38 | // } | 37 | // } |
39 | // ``` | 38 | // ``` |
40 | pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 39 | pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
41 | let name = ctx.find_node_at_offset::<ast::NameRef>()?.as_name(); | 40 | let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; |
41 | let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { | ||
42 | assign_expr.lhs()? | ||
43 | } else { | ||
44 | return None; | ||
45 | }; | ||
42 | 46 | ||
43 | let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() { | 47 | let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() { |
44 | ( | 48 | ( |
45 | ast::Expr::cast(if_expr.syntax().to_owned())?, | 49 | ast::Expr::cast(if_expr.syntax().to_owned())?, |
46 | exprify_if(&if_expr, &name)?.indent(if_expr.indent_level()), | 50 | exprify_if(&if_expr, &ctx.sema, &name_expr)?.indent(if_expr.indent_level()), |
47 | ) | 51 | ) |
48 | } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() { | 52 | } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() { |
49 | (ast::Expr::cast(match_expr.syntax().to_owned())?, exprify_match(&match_expr, &name)?) | 53 | ( |
54 | ast::Expr::cast(match_expr.syntax().to_owned())?, | ||
55 | exprify_match(&match_expr, &ctx.sema, &name_expr)?, | ||
56 | ) | ||
50 | } else { | 57 | } else { |
51 | return None; | 58 | return None; |
52 | }; | 59 | }; |
@@ -58,18 +65,22 @@ pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
58 | "Extract assignment", | 65 | "Extract assignment", |
59 | old_stmt.syntax().text_range(), | 66 | old_stmt.syntax().text_range(), |
60 | move |edit| { | 67 | move |edit| { |
61 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name, expr_stmt)); | 68 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); |
62 | }, | 69 | }, |
63 | ) | 70 | ) |
64 | } | 71 | } |
65 | 72 | ||
66 | fn exprify_match(match_expr: &ast::MatchExpr, name: &hir::Name) -> Option<ast::Expr> { | 73 | fn exprify_match( |
74 | match_expr: &ast::MatchExpr, | ||
75 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
76 | name: &ast::Expr, | ||
77 | ) -> Option<ast::Expr> { | ||
67 | let new_arm_list = match_expr | 78 | let new_arm_list = match_expr |
68 | .match_arm_list()? | 79 | .match_arm_list()? |
69 | .arms() | 80 | .arms() |
70 | .map(|arm| { | 81 | .map(|arm| { |
71 | if let ast::Expr::BlockExpr(block) = arm.expr()? { | 82 | if let ast::Expr::BlockExpr(block) = arm.expr()? { |
72 | let new_block = exprify_block(&block, name)?.indent(block.indent_level()); | 83 | let new_block = exprify_block(&block, sema, name)?.indent(block.indent_level()); |
73 | Some(arm.replace_descendant(block, new_block)) | 84 | Some(arm.replace_descendant(block, new_block)) |
74 | } else { | 85 | } else { |
75 | None | 86 | None |
@@ -82,21 +93,31 @@ fn exprify_match(match_expr: &ast::MatchExpr, name: &hir::Name) -> Option<ast::E | |||
82 | Some(make::expr_match(match_expr.expr()?, new_arm_list)) | 93 | Some(make::expr_match(match_expr.expr()?, new_arm_list)) |
83 | } | 94 | } |
84 | 95 | ||
85 | fn exprify_if(statement: &ast::IfExpr, name: &hir::Name) -> Option<ast::Expr> { | 96 | fn exprify_if( |
86 | let then_branch = exprify_block(&statement.then_branch()?, name)?; | 97 | statement: &ast::IfExpr, |
98 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
99 | name: &ast::Expr, | ||
100 | ) -> Option<ast::Expr> { | ||
101 | let then_branch = exprify_block(&statement.then_branch()?, sema, name)?; | ||
87 | let else_branch = match statement.else_branch()? { | 102 | let else_branch = match statement.else_branch()? { |
88 | ast::ElseBranch::Block(ref block) => ast::ElseBranch::Block(exprify_block(block, name)?), | 103 | ast::ElseBranch::Block(ref block) => { |
104 | ast::ElseBranch::Block(exprify_block(block, sema, name)?) | ||
105 | } | ||
89 | ast::ElseBranch::IfExpr(expr) => { | 106 | ast::ElseBranch::IfExpr(expr) => { |
90 | mark::hit!(test_extract_assigment_chained_if); | 107 | mark::hit!(test_extract_assigment_chained_if); |
91 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( | 108 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( |
92 | exprify_if(&expr, name)?.syntax().to_owned(), | 109 | exprify_if(&expr, sema, name)?.syntax().to_owned(), |
93 | )?) | 110 | )?) |
94 | } | 111 | } |
95 | }; | 112 | }; |
96 | Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch))) | 113 | Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch))) |
97 | } | 114 | } |
98 | 115 | ||
99 | fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockExpr> { | 116 | fn exprify_block( |
117 | block: &ast::BlockExpr, | ||
118 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
119 | name: &ast::Expr, | ||
120 | ) -> Option<ast::BlockExpr> { | ||
100 | if block.expr().is_some() { | 121 | if block.expr().is_some() { |
101 | return None; | 122 | return None; |
102 | } | 123 | } |
@@ -106,8 +127,7 @@ fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockE | |||
106 | 127 | ||
107 | if let ast::Stmt::ExprStmt(stmt) = stmt { | 128 | if let ast::Stmt::ExprStmt(stmt) = stmt { |
108 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { | 129 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { |
109 | if expr.op_kind()? == ast::BinOp::Assignment | 130 | if expr.op_kind()? == ast::BinOp::Assignment && is_equivalent(sema, &expr.lhs()?, name) |
110 | && &expr.lhs()?.name_ref()?.as_name() == name | ||
111 | { | 131 | { |
112 | // The last statement in the block is an assignment to the name we want | 132 | // The last statement in the block is an assignment to the name we want |
113 | return Some(make::block_expr(stmts, Some(expr.rhs()?))); | 133 | return Some(make::block_expr(stmts, Some(expr.rhs()?))); |
@@ -117,6 +137,29 @@ fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockE | |||
117 | None | 137 | None |
118 | } | 138 | } |
119 | 139 | ||
140 | fn is_equivalent( | ||
141 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
142 | expr0: &ast::Expr, | ||
143 | expr1: &ast::Expr, | ||
144 | ) -> bool { | ||
145 | match (expr0, expr1) { | ||
146 | (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { | ||
147 | mark::hit!(test_extract_assignment_field_assignment); | ||
148 | sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) | ||
149 | } | ||
150 | (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { | ||
151 | let path0 = path0.path(); | ||
152 | let path1 = path1.path(); | ||
153 | if let (Some(path0), Some(path1)) = (path0, path1) { | ||
154 | sema.resolve_path(&path0) == sema.resolve_path(&path1) | ||
155 | } else { | ||
156 | false | ||
157 | } | ||
158 | } | ||
159 | _ => false, | ||
160 | } | ||
161 | } | ||
162 | |||
120 | #[cfg(test)] | 163 | #[cfg(test)] |
121 | mod tests { | 164 | mod tests { |
122 | use super::*; | 165 | use super::*; |
@@ -322,4 +365,36 @@ fn foo() { | |||
322 | }"#, | 365 | }"#, |
323 | ) | 366 | ) |
324 | } | 367 | } |
368 | |||
369 | #[test] | ||
370 | fn test_extract_assignment_field_assignment() { | ||
371 | mark::check!(test_extract_assignment_field_assignment); | ||
372 | check_assist( | ||
373 | extract_assigment, | ||
374 | r#" | ||
375 | struct A(usize); | ||
376 | |||
377 | fn foo() { | ||
378 | let mut a = A(1); | ||
379 | |||
380 | if true { | ||
381 | <|>a.0 = 2; | ||
382 | } else { | ||
383 | a.0 = 3; | ||
384 | } | ||
385 | }"#, | ||
386 | r#" | ||
387 | struct A(usize); | ||
388 | |||
389 | fn foo() { | ||
390 | let mut a = A(1); | ||
391 | |||
392 | a.0 = if true { | ||
393 | 2 | ||
394 | } else { | ||
395 | 3 | ||
396 | }; | ||
397 | }"#, | ||
398 | ) | ||
399 | } | ||
325 | } | 400 | } |
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml index c68e391c1..73247d130 100644 --- a/crates/cfg/Cargo.toml +++ b/crates/cfg/Cargo.toml | |||
@@ -17,4 +17,4 @@ tt = { path = "../tt", version = "0.0.0" } | |||
17 | [dev-dependencies] | 17 | [dev-dependencies] |
18 | mbe = { path = "../mbe" } | 18 | mbe = { path = "../mbe" } |
19 | syntax = { path = "../syntax" } | 19 | syntax = { path = "../syntax" } |
20 | expect-test = "1.0" | 20 | expect-test = "1.1" |
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml index 78e93e78e..99a1bdd54 100644 --- a/crates/completion/Cargo.toml +++ b/crates/completion/Cargo.toml | |||
@@ -28,4 +28,4 @@ test_utils = { path = "../test_utils", version = "0.0.0" } | |||
28 | hir = { path = "../hir", version = "0.0.0" } | 28 | hir = { path = "../hir", version = "0.0.0" } |
29 | 29 | ||
30 | [dev-dependencies] | 30 | [dev-dependencies] |
31 | expect-test = "1.0" | 31 | expect-test = "1.1" |
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index e8b581e2f..7ef966cd2 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -33,4 +33,4 @@ cfg = { path = "../cfg", version = "0.0.0" } | |||
33 | tt = { path = "../tt", version = "0.0.0" } | 33 | tt = { path = "../tt", version = "0.0.0" } |
34 | 34 | ||
35 | [dev-dependencies] | 35 | [dev-dependencies] |
36 | expect-test = "1.0" | 36 | expect-test = "1.1" |
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index c71266dc0..ab3f059ce 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs | |||
@@ -133,6 +133,10 @@ impl Diagnostic for InactiveCode { | |||
133 | // This diagnostic is shown when a procedural macro can not be found. This usually means that | 133 | // This diagnostic is shown when a procedural macro can not be found. This usually means that |
134 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | 134 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), |
135 | // but can also indicate project setup problems. | 135 | // but can also indicate project setup problems. |
136 | // | ||
137 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | ||
138 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | ||
139 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | ||
136 | #[derive(Debug, Clone, Eq, PartialEq)] | 140 | #[derive(Debug, Clone, Eq, PartialEq)] |
137 | pub struct UnresolvedProcMacro { | 141 | pub struct UnresolvedProcMacro { |
138 | pub file: HirFileId, | 142 | pub file: HirFileId, |
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 9518ac109..8a01e6eea 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs | |||
@@ -123,7 +123,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
123 | // We follow what it did anyway :) | 123 | // We follow what it did anyway :) |
124 | if segments.len() == 1 && kind == PathKind::Plain { | 124 | if segments.len() == 1 && kind == PathKind::Plain { |
125 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { | 125 | if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { |
126 | if let Some(crate_id) = hygiene.local_inner_macros(path) { | 126 | if let Some(crate_id) = hygiene.local_inner_macros() { |
127 | kind = PathKind::DollarCrate(crate_id); | 127 | kind = PathKind::DollarCrate(crate_id); |
128 | } | 128 | } |
129 | } | 129 | } |
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index 6042e15b2..7ab0a5e52 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -2,94 +2,30 @@ | |||
2 | //! | 2 | //! |
3 | //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at | 3 | //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at |
4 | //! this moment, this is horribly incomplete and handles only `$crate`. | 4 | //! this moment, this is horribly incomplete and handles only `$crate`. |
5 | use std::sync::Arc; | ||
6 | |||
7 | use arena::{Arena, Idx}; | ||
8 | use base_db::CrateId; | 5 | use base_db::CrateId; |
9 | use either::Either; | 6 | use either::Either; |
10 | use mbe::Origin; | 7 | use syntax::ast; |
11 | use syntax::{ast, AstNode}; | ||
12 | 8 | ||
13 | use crate::{ | 9 | use crate::{ |
14 | db::AstDatabase, | 10 | db::AstDatabase, |
15 | name::{AsName, Name}, | 11 | name::{AsName, Name}, |
16 | ExpansionInfo, HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, | 12 | HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind, |
17 | }; | 13 | }; |
18 | 14 | ||
19 | #[derive(Clone, Debug)] | 15 | #[derive(Clone, Debug)] |
20 | pub struct Hygiene { | 16 | pub struct Hygiene { |
21 | frames: Option<Arc<HygieneFrames>>, | 17 | // This is what `$crate` expands to |
22 | } | 18 | def_crate: Option<CrateId>, |
23 | |||
24 | impl Hygiene { | ||
25 | pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { | ||
26 | Hygiene { frames: Some(Arc::new(HygieneFrames::new(db, file_id.clone()))) } | ||
27 | } | ||
28 | |||
29 | pub fn new_unhygienic() -> Hygiene { | ||
30 | Hygiene { frames: None } | ||
31 | } | ||
32 | |||
33 | // FIXME: this should just return name | ||
34 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { | ||
35 | if let Some(frames) = &self.frames { | ||
36 | if name_ref.text() == "$crate" { | ||
37 | if let Some(krate) = frames.root_crate(&name_ref) { | ||
38 | return Either::Right(krate); | ||
39 | } | ||
40 | } | ||
41 | } | ||
42 | |||
43 | Either::Left(name_ref.as_name()) | ||
44 | } | ||
45 | |||
46 | pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> { | ||
47 | let frames = self.frames.as_ref()?; | ||
48 | |||
49 | let mut token = path.syntax().first_token()?; | ||
50 | let mut current = frames.first(); | ||
51 | |||
52 | while let Some((frame, data)) = | ||
53 | current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?))) | ||
54 | { | ||
55 | let (mapped, origin) = data; | ||
56 | if origin == Origin::Def { | ||
57 | return if frame.local_inner { frame.krate } else { None }; | ||
58 | } | ||
59 | current = Some(&frames.0[frame.call_site?]); | ||
60 | token = mapped.value; | ||
61 | } | ||
62 | None | ||
63 | } | ||
64 | } | ||
65 | |||
66 | #[derive(Default, Debug)] | ||
67 | struct HygieneFrames(Arena<HygieneFrame>); | ||
68 | |||
69 | #[derive(Clone, Debug)] | ||
70 | struct HygieneFrame { | ||
71 | expansion: Option<ExpansionInfo>, | ||
72 | 19 | ||
73 | // Indicate this is a local inner macro | 20 | // Indicate this is a local inner macro |
74 | local_inner: bool, | 21 | local_inner: bool, |
75 | krate: Option<CrateId>, | ||
76 | |||
77 | call_site: Option<Idx<HygieneFrame>>, | ||
78 | def_site: Option<Idx<HygieneFrame>>, | ||
79 | } | 22 | } |
80 | 23 | ||
81 | impl HygieneFrames { | 24 | impl Hygiene { |
82 | fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self { | 25 | pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene { |
83 | let mut frames = HygieneFrames::default(); | 26 | let (def_crate, local_inner) = match file_id.0 { |
84 | frames.add(db, file_id); | ||
85 | frames | ||
86 | } | ||
87 | |||
88 | fn add(&mut self, db: &dyn AstDatabase, file_id: HirFileId) -> Option<Idx<HygieneFrame>> { | ||
89 | let (krate, local_inner) = match file_id.0 { | ||
90 | HirFileIdRepr::FileId(_) => (None, false), | 27 | HirFileIdRepr::FileId(_) => (None, false), |
91 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { | 28 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { |
92 | MacroCallId::EagerMacro(_id) => (None, false), | ||
93 | MacroCallId::LazyMacro(id) => { | 29 | MacroCallId::LazyMacro(id) => { |
94 | let loc = db.lookup_intern_macro(id); | 30 | let loc = db.lookup_intern_macro(id); |
95 | match loc.def.kind { | 31 | match loc.def.kind { |
@@ -100,68 +36,31 @@ impl HygieneFrames { | |||
100 | MacroDefKind::ProcMacro(_) => (None, false), | 36 | MacroDefKind::ProcMacro(_) => (None, false), |
101 | } | 37 | } |
102 | } | 38 | } |
39 | MacroCallId::EagerMacro(_id) => (None, false), | ||
103 | }, | 40 | }, |
104 | }; | 41 | }; |
105 | 42 | Hygiene { def_crate, local_inner } | |
106 | let expansion = file_id.expansion_info(db); | ||
107 | let expansion = match expansion { | ||
108 | None => { | ||
109 | return Some(self.0.alloc(HygieneFrame { | ||
110 | expansion: None, | ||
111 | local_inner, | ||
112 | krate, | ||
113 | call_site: None, | ||
114 | def_site: None, | ||
115 | })); | ||
116 | } | ||
117 | Some(it) => it, | ||
118 | }; | ||
119 | |||
120 | let def_site = expansion.def.clone(); | ||
121 | let call_site = expansion.arg.file_id; | ||
122 | let idx = self.0.alloc(HygieneFrame { | ||
123 | expansion: Some(expansion), | ||
124 | local_inner, | ||
125 | krate, | ||
126 | call_site: None, | ||
127 | def_site: None, | ||
128 | }); | ||
129 | |||
130 | self.0[idx].call_site = self.add(db, call_site); | ||
131 | self.0[idx].def_site = def_site.and_then(|it| self.add(db, it.file_id)); | ||
132 | |||
133 | Some(idx) | ||
134 | } | 43 | } |
135 | 44 | ||
136 | fn first(&self) -> Option<&HygieneFrame> { | 45 | pub fn new_unhygienic() -> Hygiene { |
137 | self.0.iter().next().map(|it| it.1) | 46 | Hygiene { def_crate: None, local_inner: false } |
138 | } | 47 | } |
139 | 48 | ||
140 | fn root_crate(&self, name_ref: &ast::NameRef) -> Option<CrateId> { | 49 | // FIXME: this should just return name |
141 | let mut token = name_ref.syntax().first_token()?; | 50 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { |
142 | let first = self.first()?; | 51 | if let Some(def_crate) = self.def_crate { |
143 | let mut result = first.krate; | 52 | if name_ref.text() == "$crate" { |
144 | let mut current = Some(first); | 53 | return Either::Right(def_crate); |
145 | 54 | } | |
146 | while let Some((frame, (mapped, origin))) = | ||
147 | current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?))) | ||
148 | { | ||
149 | result = frame.krate; | ||
150 | |||
151 | let site = match origin { | ||
152 | Origin::Def => frame.def_site, | ||
153 | Origin::Call => frame.call_site, | ||
154 | }; | ||
155 | |||
156 | let site = match site { | ||
157 | None => break, | ||
158 | Some(it) => it, | ||
159 | }; | ||
160 | |||
161 | current = Some(&self.0[site]); | ||
162 | token = mapped.value; | ||
163 | } | 55 | } |
56 | Either::Left(name_ref.as_name()) | ||
57 | } | ||
164 | 58 | ||
165 | result | 59 | pub fn local_inner_macros(&self) -> Option<CrateId> { |
60 | if self.local_inner { | ||
61 | self.def_crate | ||
62 | } else { | ||
63 | None | ||
64 | } | ||
166 | } | 65 | } |
167 | } | 66 | } |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 5b6734a5f..3fa1b1d77 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -340,8 +340,11 @@ impl ExpansionInfo { | |||
340 | Some(self.expanded.with_value(token)) | 340 | Some(self.expanded.with_value(token)) |
341 | } | 341 | } |
342 | 342 | ||
343 | pub fn map_token_up(&self, token: &SyntaxToken) -> Option<(InFile<SyntaxToken>, Origin)> { | 343 | pub fn map_token_up( |
344 | let token_id = self.exp_map.token_by_range(token.text_range())?; | 344 | &self, |
345 | token: InFile<&SyntaxToken>, | ||
346 | ) -> Option<(InFile<SyntaxToken>, Origin)> { | ||
347 | let token_id = self.exp_map.token_by_range(token.value.text_range())?; | ||
345 | 348 | ||
346 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); | 349 | let (token_id, origin) = self.macro_def.0.map_id_up(token_id); |
347 | let (token_map, tt) = match origin { | 350 | let (token_map, tt) = match origin { |
@@ -356,7 +359,7 @@ impl ExpansionInfo { | |||
356 | ), | 359 | ), |
357 | }; | 360 | }; |
358 | 361 | ||
359 | let range = token_map.range_by_token(token_id)?.by_kind(token.kind())?; | 362 | let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?; |
360 | let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) | 363 | let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start()) |
361 | .into_token()?; | 364 | .into_token()?; |
362 | Some((tt.with_value(token), origin)) | 365 | Some((tt.with_value(token), origin)) |
@@ -492,7 +495,7 @@ fn ascend_call_token( | |||
492 | expansion: &ExpansionInfo, | 495 | expansion: &ExpansionInfo, |
493 | token: InFile<SyntaxToken>, | 496 | token: InFile<SyntaxToken>, |
494 | ) -> Option<InFile<SyntaxToken>> { | 497 | ) -> Option<InFile<SyntaxToken>> { |
495 | let (mapped, origin) = expansion.map_token_up(&token.value)?; | 498 | let (mapped, origin) = expansion.map_token_up(token.as_ref())?; |
496 | if origin != Origin::Call { | 499 | if origin != Origin::Call { |
497 | return None; | 500 | return None; |
498 | } | 501 | } |
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 2dfccd191..3d1778590 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -31,7 +31,7 @@ syntax = { path = "../syntax", version = "0.0.0" } | |||
31 | test_utils = { path = "../test_utils", version = "0.0.0" } | 31 | test_utils = { path = "../test_utils", version = "0.0.0" } |
32 | 32 | ||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | expect-test = "1.0" | 34 | expect-test = "1.1" |
35 | tracing = "0.1" | 35 | tracing = "0.1" |
36 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } | 36 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } |
37 | tracing-tree = { version = "0.1.4" } | 37 | tracing-tree = { version = "0.1.4" } |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index c64f0b5b5..1953da7be 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -371,37 +371,6 @@ expand!(); | |||
371 | } | 371 | } |
372 | 372 | ||
373 | #[test] | 373 | #[test] |
374 | fn infer_macro_with_dollar_crate_in_def_site() { | ||
375 | check_types( | ||
376 | r#" | ||
377 | //- /main.rs crate:main deps:foo | ||
378 | use foo::expand; | ||
379 | |||
380 | macro_rules! list { | ||
381 | ($($tt:tt)*) => { $($tt)* } | ||
382 | } | ||
383 | |||
384 | fn test() { | ||
385 | let r = expand!(); | ||
386 | r; | ||
387 | //^ u128 | ||
388 | } | ||
389 | |||
390 | //- /lib.rs crate:foo | ||
391 | #[macro_export] | ||
392 | macro_rules! expand { | ||
393 | () => { list!($crate::m!()) }; | ||
394 | } | ||
395 | |||
396 | #[macro_export] | ||
397 | macro_rules! m { | ||
398 | () => { 0u128 }; | ||
399 | } | ||
400 | "#, | ||
401 | ); | ||
402 | } | ||
403 | |||
404 | #[test] | ||
405 | fn infer_type_value_non_legacy_macro_use_as() { | 374 | fn infer_type_value_non_legacy_macro_use_as() { |
406 | check_infer( | 375 | check_infer( |
407 | r#" | 376 | r#" |
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index f1544dbe0..bb28cca4d 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -36,4 +36,4 @@ completion = { path = "../completion", version = "0.0.0" } | |||
36 | hir = { path = "../hir", version = "0.0.0" } | 36 | hir = { path = "../hir", version = "0.0.0" } |
37 | 37 | ||
38 | [dev-dependencies] | 38 | [dev-dependencies] |
39 | expect-test = "1.0" | 39 | expect-test = "1.1" |
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml index ebe53c8ee..d3d3dc688 100644 --- a/crates/ide_db/Cargo.toml +++ b/crates/ide_db/Cargo.toml | |||
@@ -32,4 +32,4 @@ test_utils = { path = "../test_utils", version = "0.0.0" } | |||
32 | hir = { path = "../hir", version = "0.0.0" } | 32 | hir = { path = "../hir", version = "0.0.0" } |
33 | 33 | ||
34 | [dev-dependencies] | 34 | [dev-dependencies] |
35 | expect-test = "1.0" | 35 | expect-test = "1.1" |
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs index 385b46601..ab5f87c48 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/mbe_expander/matcher.rs | |||
@@ -150,7 +150,7 @@ fn match_subtree( | |||
150 | res.add_err(err!("leftover tokens")); | 150 | res.add_err(err!("leftover tokens")); |
151 | } | 151 | } |
152 | } | 152 | } |
153 | Op::Var { name, kind, .. } => { | 153 | Op::Var { name, kind } => { |
154 | let kind = match kind { | 154 | let kind = match kind { |
155 | Some(k) => k, | 155 | Some(k) => k, |
156 | None => { | 156 | None => { |
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs index 57f3f104d..720531237 100644 --- a/crates/mbe/src/mbe_expander/transcriber.rs +++ b/crates/mbe/src/mbe_expander/transcriber.rs | |||
@@ -100,8 +100,8 @@ fn expand_subtree( | |||
100 | err = err.or(e); | 100 | err = err.or(e); |
101 | arena.push(tt.into()); | 101 | arena.push(tt.into()); |
102 | } | 102 | } |
103 | Op::Var { name, id, .. } => { | 103 | Op::Var { name, .. } => { |
104 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name, *id); | 104 | let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name); |
105 | err = err.or(e); | 105 | err = err.or(e); |
106 | push_fragment(arena, fragment); | 106 | push_fragment(arena, fragment); |
107 | } | 107 | } |
@@ -118,10 +118,12 @@ fn expand_subtree( | |||
118 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } | 118 | ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err } |
119 | } | 119 | } |
120 | 120 | ||
121 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> { | 121 | fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> { |
122 | if v == "crate" { | 122 | if v == "crate" { |
123 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. | 123 | // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path. |
124 | let tt = tt::Leaf::from(tt::Ident { text: "$crate".into(), id }).into(); | 124 | let tt = |
125 | tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() }) | ||
126 | .into(); | ||
125 | ExpandResult::ok(Fragment::Tokens(tt)) | 127 | ExpandResult::ok(Fragment::Tokens(tt)) |
126 | } else if !ctx.bindings.contains(v) { | 128 | } else if !ctx.bindings.contains(v) { |
127 | // Note that it is possible to have a `$var` inside a macro which is not bound. | 129 | // Note that it is possible to have a `$var` inside a macro which is not bound. |
@@ -140,8 +142,14 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult | |||
140 | let tt = tt::Subtree { | 142 | let tt = tt::Subtree { |
141 | delimiter: None, | 143 | delimiter: None, |
142 | token_trees: vec![ | 144 | token_trees: vec![ |
143 | tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(), | 145 | tt::Leaf::from(tt::Punct { |
144 | tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(), | 146 | char: '$', |
147 | spacing: tt::Spacing::Alone, | ||
148 | id: tt::TokenId::unspecified(), | ||
149 | }) | ||
150 | .into(), | ||
151 | tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) | ||
152 | .into(), | ||
145 | ], | 153 | ], |
146 | } | 154 | } |
147 | .into(); | 155 | .into(); |
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index 77cc739b6..2f3ebc831 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs | |||
@@ -8,7 +8,7 @@ use crate::{tt_iter::TtIter, ExpandError, MetaTemplate}; | |||
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub(crate) enum Op { | 10 | pub(crate) enum Op { |
11 | Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId }, | 11 | Var { name: SmolStr, kind: Option<SmolStr> }, |
12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, | 12 | Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> }, |
13 | Leaf(tt::Leaf), | 13 | Leaf(tt::Leaf), |
14 | Subtree(MetaTemplate), | 14 | Subtree(MetaTemplate), |
@@ -106,21 +106,18 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul | |||
106 | } | 106 | } |
107 | let name = UNDERSCORE.clone(); | 107 | let name = UNDERSCORE.clone(); |
108 | let kind = eat_fragment_kind(src, mode)?; | 108 | let kind = eat_fragment_kind(src, mode)?; |
109 | let id = punct.id; | 109 | Op::Var { name, kind } |
110 | Op::Var { name, kind, id } | ||
111 | } | 110 | } |
112 | tt::Leaf::Ident(ident) => { | 111 | tt::Leaf::Ident(ident) => { |
113 | let name = ident.text.clone(); | 112 | let name = ident.text.clone(); |
114 | let kind = eat_fragment_kind(src, mode)?; | 113 | let kind = eat_fragment_kind(src, mode)?; |
115 | let id = ident.id; | 114 | Op::Var { name, kind } |
116 | Op::Var { name, kind, id } | ||
117 | } | 115 | } |
118 | tt::Leaf::Literal(lit) => { | 116 | tt::Leaf::Literal(lit) => { |
119 | if is_boolean_literal(&lit) { | 117 | if is_boolean_literal(&lit) { |
120 | let name = lit.text.clone(); | 118 | let name = lit.text.clone(); |
121 | let kind = eat_fragment_kind(src, mode)?; | 119 | let kind = eat_fragment_kind(src, mode)?; |
122 | let id = lit.id; | 120 | Op::Var { name, kind } |
123 | Op::Var { name, kind, id } | ||
124 | } else { | 121 | } else { |
125 | bail!("bad var 2"); | 122 | bail!("bad var 2"); |
126 | } | 123 | } |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 0a63593fb..af7b86ead 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -62,7 +62,7 @@ proc_macro_srv = { path = "../proc_macro_srv", version = "0.0.0" } | |||
62 | winapi = "0.3.8" | 62 | winapi = "0.3.8" |
63 | 63 | ||
64 | [dev-dependencies] | 64 | [dev-dependencies] |
65 | expect-test = "1.0" | 65 | expect-test = "1.1" |
66 | test_utils = { path = "../test_utils" } | 66 | test_utils = { path = "../test_utils" } |
67 | mbe = { path = "../mbe" } | 67 | mbe = { path = "../mbe" } |
68 | tt = { path = "../tt" } | 68 | tt = { path = "../tt" } |
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml index 339eda86a..cc8136d22 100644 --- a/crates/ssr/Cargo.toml +++ b/crates/ssr/Cargo.toml | |||
@@ -21,4 +21,4 @@ hir = { path = "../hir", version = "0.0.0" } | |||
21 | test_utils = { path = "../test_utils", version = "0.0.0" } | 21 | test_utils = { path = "../test_utils", version = "0.0.0" } |
22 | 22 | ||
23 | [dev-dependencies] | 23 | [dev-dependencies] |
24 | expect-test = "1.0" | 24 | expect-test = "1.1" |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 5d8389ade..181077944 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -33,4 +33,4 @@ profile = { path = "../profile", version = "0.0.0" } | |||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | walkdir = "2.3.1" | 34 | walkdir = "2.3.1" |
35 | rayon = "1" | 35 | rayon = "1" |
36 | expect-test = "1.0" | 36 | expect-test = "1.1" |