diff options
Diffstat (limited to 'crates')
257 files changed, 3843 insertions, 1859 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index c45262efa..189cad7d0 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_db::FileRange; | 4 | use ra_db::FileRange; |
3 | use ra_fmt::{leading_indent, reindent}; | 5 | use ra_fmt::{leading_indent, reindent}; |
4 | use ra_syntax::{ | 6 | use ra_syntax::{ |
5 | algo::{find_covering_element, find_node_at_offset}, | 7 | algo::{self, find_covering_element, find_node_at_offset}, |
6 | AstNode, SourceFile, SyntaxElement, SyntaxNode, SyntaxToken, TextRange, TextUnit, | 8 | AstNode, SourceFile, SyntaxElement, SyntaxNode, SyntaxToken, TextRange, TextUnit, |
7 | TokenAtOffset, | 9 | TokenAtOffset, |
8 | }; | 10 | }; |
@@ -177,6 +179,10 @@ impl AssistBuilder { | |||
177 | &mut self.edit | 179 | &mut self.edit |
178 | } | 180 | } |
179 | 181 | ||
182 | pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) { | ||
183 | algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit) | ||
184 | } | ||
185 | |||
180 | fn build(self) -> AssistAction { | 186 | fn build(self) -> AssistAction { |
181 | AssistAction { | 187 | AssistAction { |
182 | edit: self.edit.finish(), | 188 | edit: self.edit.finish(), |
diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs index 9c88644df..77ecc33c9 100644 --- a/crates/ra_assists/src/assists/add_derive.rs +++ b/crates/ra_assists/src/assists/add_derive.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast::{self, AstNode, AttrsOwner}, | 5 | ast::{self, AstNode, AttrsOwner}, |
@@ -13,7 +15,7 @@ pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> | |||
13 | ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { | 15 | ctx.add_action(AssistId("add_derive"), "add `#[derive]`", |edit| { |
14 | let derive_attr = nominal | 16 | let derive_attr = nominal |
15 | .attrs() | 17 | .attrs() |
16 | .filter_map(|x| x.as_call()) | 18 | .filter_map(|x| x.as_simple_call()) |
17 | .filter(|(name, _arg)| name == "derive") | 19 | .filter(|(name, _arg)| name == "derive") |
18 | .map(|(_name, arg)| arg) | 20 | .map(|(_name, arg)| arg) |
19 | .next(); | 21 | .next(); |
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index 78f0f7f28..8c83dc987 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::{db::HirDatabase, HirDisplay, Ty}; | 3 | use hir::{db::HirDatabase, HirDisplay, Ty}; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast::{self, AstNode, LetStmt, NameOwner}, | 5 | ast::{self, AstNode, LetStmt, NameOwner}, |
diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs index 4b61f4031..94801fbc9 100644 --- a/crates/ra_assists/src/assists/add_impl.rs +++ b/crates/ra_assists/src/assists/add_impl.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use format_buf::format; | 3 | use format_buf::format; |
2 | use hir::db::HirDatabase; | 4 | use hir::db::HirDatabase; |
3 | use join_to_string::join; | 5 | use join_to_string::join; |
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index 23da1e65f..565b96fb5 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs | |||
@@ -1,10 +1,12 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::{db::HirDatabase, HasSource}; | 3 | use hir::{db::HirDatabase, HasSource}; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast::{self, make, AstNode, NameOwner}, | 5 | ast::{self, edit, make, AstNode, NameOwner}, |
4 | SmolStr, | 6 | SmolStr, |
5 | }; | 7 | }; |
6 | 8 | ||
7 | use crate::{ast_editor::AstEditor, Assist, AssistCtx, AssistId}; | 9 | use crate::{Assist, AssistCtx, AssistId}; |
8 | 10 | ||
9 | #[derive(PartialEq)] | 11 | #[derive(PartialEq)] |
10 | enum AddMissingImplMembersMode { | 12 | enum AddMissingImplMembersMode { |
@@ -75,37 +77,32 @@ fn add_missing_impl_members_inner( | |||
75 | 77 | ||
76 | ctx.add_action(AssistId(assist_id), label, |edit| { | 78 | ctx.add_action(AssistId(assist_id), label, |edit| { |
77 | let n_existing_items = impl_item_list.impl_items().count(); | 79 | let n_existing_items = impl_item_list.impl_items().count(); |
78 | let items = missing_items.into_iter().map(|it| match it { | 80 | let items = missing_items |
79 | ast::ImplItem::FnDef(def) => strip_docstring(add_body(def).into()), | 81 | .into_iter() |
80 | _ => strip_docstring(it), | 82 | .map(|it| match it { |
81 | }); | 83 | ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)), |
82 | let mut ast_editor = AstEditor::new(impl_item_list); | 84 | _ => it, |
83 | 85 | }) | |
84 | ast_editor.append_items(items); | 86 | .map(|it| edit::strip_attrs_and_docs(&it)); |
85 | 87 | let new_impl_item_list = impl_item_list.append_items(items); | |
86 | let first_new_item = ast_editor.ast().impl_items().nth(n_existing_items).unwrap(); | 88 | let cursor_position = { |
87 | let cursor_position = first_new_item.syntax().text_range().start(); | 89 | let first_new_item = new_impl_item_list.impl_items().nth(n_existing_items).unwrap(); |
88 | ast_editor.into_text_edit(edit.text_edit_builder()); | 90 | first_new_item.syntax().text_range().start() |
89 | 91 | }; | |
92 | |||
93 | edit.replace_ast(impl_item_list, new_impl_item_list); | ||
90 | edit.set_cursor(cursor_position); | 94 | edit.set_cursor(cursor_position); |
91 | }); | 95 | }); |
92 | 96 | ||
93 | ctx.build() | 97 | ctx.build() |
94 | } | 98 | } |
95 | 99 | ||
96 | fn strip_docstring(item: ast::ImplItem) -> ast::ImplItem { | ||
97 | let mut ast_editor = AstEditor::new(item); | ||
98 | ast_editor.strip_attrs_and_docs(); | ||
99 | ast_editor.ast().to_owned() | ||
100 | } | ||
101 | |||
102 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | 100 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { |
103 | let mut ast_editor = AstEditor::new(fn_def.clone()); | ||
104 | if fn_def.body().is_none() { | 101 | if fn_def.body().is_none() { |
105 | let body = make::block_from_expr(make::expr_unimplemented()); | 102 | fn_def.with_body(make::block_from_expr(make::expr_unimplemented())) |
106 | ast_editor.set_body(&body); | 103 | } else { |
104 | fn_def | ||
107 | } | 105 | } |
108 | ast_editor.ast().to_owned() | ||
109 | } | 106 | } |
110 | 107 | ||
111 | /// Given an `ast::ImplBlock`, resolves the target trait (the one being | 108 | /// Given an `ast::ImplBlock`, resolves the target trait (the one being |
@@ -332,5 +329,4 @@ impl Foo for S { | |||
332 | }", | 329 | }", |
333 | ) | 330 | ) |
334 | } | 331 | } |
335 | |||
336 | } | 332 | } |
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs new file mode 100644 index 000000000..5f2b0dd18 --- /dev/null +++ b/crates/ra_assists/src/assists/apply_demorgan.rs | |||
@@ -0,0 +1,102 @@ | |||
1 | //! This contains the functions associated with the demorgan assist. | ||
2 | //! This assist transforms boolean expressions of the form `!a || !b` into | ||
3 | //! `!(a && b)`. | ||
4 | use hir::db::HirDatabase; | ||
5 | use ra_syntax::ast::{self, AstNode}; | ||
6 | use ra_syntax::SyntaxNode; | ||
7 | |||
8 | use crate::{Assist, AssistCtx, AssistId}; | ||
9 | |||
10 | /// Assist for applying demorgan's law | ||
11 | /// | ||
12 | /// This transforms expressions of the form `!l || !r` into `!(l && r)`. | ||
13 | /// This also works with `&&`. This assist can only be applied with the cursor | ||
14 | /// on either `||` or `&&`, with both operands being a negation of some kind. | ||
15 | /// This means something of the form `!x` or `x != y`. | ||
16 | pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
17 | let expr = ctx.node_at_offset::<ast::BinExpr>()?; | ||
18 | let op = expr.op_kind()?; | ||
19 | let op_range = expr.op_token()?.text_range(); | ||
20 | let opposite_op = opposite_logic_op(op)?; | ||
21 | let cursor_in_range = ctx.frange.range.is_subrange(&op_range); | ||
22 | if !cursor_in_range { | ||
23 | return None; | ||
24 | } | ||
25 | let lhs = expr.lhs()?.syntax().clone(); | ||
26 | let lhs_range = lhs.text_range(); | ||
27 | let rhs = expr.rhs()?.syntax().clone(); | ||
28 | let rhs_range = rhs.text_range(); | ||
29 | let not_lhs = undo_negation(lhs)?; | ||
30 | let not_rhs = undo_negation(rhs)?; | ||
31 | |||
32 | ctx.add_action(AssistId("apply_demorgan"), "apply demorgan's law", |edit| { | ||
33 | edit.target(op_range); | ||
34 | edit.replace(op_range, opposite_op); | ||
35 | edit.replace(lhs_range, format!("!({}", not_lhs)); | ||
36 | edit.replace(rhs_range, format!("{})", not_rhs)); | ||
37 | }); | ||
38 | ctx.build() | ||
39 | } | ||
40 | |||
41 | // Return the opposite text for a given logical operator, if it makes sense | ||
42 | fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> { | ||
43 | match kind { | ||
44 | ast::BinOp::BooleanOr => Some("&&"), | ||
45 | ast::BinOp::BooleanAnd => Some("||"), | ||
46 | _ => None, | ||
47 | } | ||
48 | } | ||
49 | |||
50 | // This function tries to undo unary negation, or inequality | ||
51 | fn undo_negation(node: SyntaxNode) -> Option<String> { | ||
52 | match ast::Expr::cast(node)? { | ||
53 | ast::Expr::BinExpr(bin) => match bin.op_kind()? { | ||
54 | ast::BinOp::NegatedEqualityTest => { | ||
55 | let lhs = bin.lhs()?.syntax().text(); | ||
56 | let rhs = bin.rhs()?.syntax().text(); | ||
57 | Some(format!("{} == {}", lhs, rhs)) | ||
58 | } | ||
59 | _ => None, | ||
60 | }, | ||
61 | ast::Expr::PrefixExpr(pe) => match pe.op_kind()? { | ||
62 | ast::PrefixOp::Not => { | ||
63 | let child = pe.expr()?.syntax().text(); | ||
64 | Some(String::from(child)) | ||
65 | } | ||
66 | _ => None, | ||
67 | }, | ||
68 | _ => None, | ||
69 | } | ||
70 | } | ||
71 | |||
72 | #[cfg(test)] | ||
73 | mod tests { | ||
74 | use super::*; | ||
75 | |||
76 | use crate::helpers::{check_assist, check_assist_not_applicable}; | ||
77 | |||
78 | #[test] | ||
79 | fn demorgan_turns_and_into_or() { | ||
80 | check_assist(apply_demorgan, "fn f() { !x &&<|> !x }", "fn f() { !(x ||<|> x) }") | ||
81 | } | ||
82 | |||
83 | #[test] | ||
84 | fn demorgan_turns_or_into_and() { | ||
85 | check_assist(apply_demorgan, "fn f() { !x ||<|> !x }", "fn f() { !(x &&<|> x) }") | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn demorgan_removes_inequality() { | ||
90 | check_assist(apply_demorgan, "fn f() { x != x ||<|> !x }", "fn f() { !(x == x &&<|> x) }") | ||
91 | } | ||
92 | |||
93 | #[test] | ||
94 | fn demorgan_doesnt_apply_with_cursor_not_on_op() { | ||
95 | check_assist_not_applicable(apply_demorgan, "fn f() { <|> !x || !x }") | ||
96 | } | ||
97 | |||
98 | #[test] | ||
99 | fn demorgan_doesnt_apply_when_operands_arent_negated_already() { | ||
100 | check_assist_not_applicable(apply_demorgan, "fn f() { x ||<|> x }") | ||
101 | } | ||
102 | } | ||
diff --git a/crates/ra_assists/src/assists/auto_import.rs b/crates/ra_assists/src/assists/auto_import.rs index 5aae98546..02c58e7c6 100644 --- a/crates/ra_assists/src/assists/auto_import.rs +++ b/crates/ra_assists/src/assists/auto_import.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::{self, db::HirDatabase}; | 3 | use hir::{self, db::HirDatabase}; |
2 | use ra_text_edit::TextEditBuilder; | 4 | use ra_text_edit::TextEditBuilder; |
3 | 5 | ||
@@ -448,7 +450,6 @@ fn make_assist_add_in_tree_list( | |||
448 | fmt_segments_raw(target, &mut buf); | 450 | fmt_segments_raw(target, &mut buf); |
449 | edit.insert(offset, buf); | 451 | edit.insert(offset, buf); |
450 | } else { | 452 | } else { |
451 | |||
452 | } | 453 | } |
453 | } | 454 | } |
454 | 455 | ||
@@ -512,7 +513,7 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | |||
512 | hir::PathKind::Plain => {} | 513 | hir::PathKind::Plain => {} |
513 | hir::PathKind::Self_ => ps.push("self".into()), | 514 | hir::PathKind::Self_ => ps.push("self".into()), |
514 | hir::PathKind::Super => ps.push("super".into()), | 515 | hir::PathKind::Super => ps.push("super".into()), |
515 | hir::PathKind::Type(_) => return None, | 516 | hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None, |
516 | } | 517 | } |
517 | for s in path.segments.iter() { | 518 | for s in path.segments.iter() { |
518 | ps.push(s.name.to_string().into()); | 519 | ps.push(s.name.to_string().into()); |
diff --git a/crates/ra_assists/src/assists/change_visibility.rs b/crates/ra_assists/src/assists/change_visibility.rs index 60c74debc..df92c6b67 100644 --- a/crates/ra_assists/src/assists/change_visibility.rs +++ b/crates/ra_assists/src/assists/change_visibility.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast::{self, NameOwner, VisibilityOwner}, | 5 | ast::{self, NameOwner, VisibilityOwner}, |
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index db82db89a..7335cce09 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::iter; | 3 | use std::iter; |
2 | 4 | ||
3 | use hir::{db::HirDatabase, Adt, HasSource}; | 5 | use hir::{db::HirDatabase, Adt, HasSource}; |
diff --git a/crates/ra_assists/src/assists/flip_binexpr.rs b/crates/ra_assists/src/assists/flip_binexpr.rs index b55b36a8e..c51035282 100644 --- a/crates/ra_assists/src/assists/flip_binexpr.rs +++ b/crates/ra_assists/src/assists/flip_binexpr.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::ast::{AstNode, BinExpr, BinOp}; | 4 | use ra_syntax::ast::{AstNode, BinExpr, BinOp}; |
3 | 5 | ||
diff --git a/crates/ra_assists/src/assists/flip_comma.rs b/crates/ra_assists/src/assists/flip_comma.rs index 5ee7561bc..e31cc5e7d 100644 --- a/crates/ra_assists/src/assists/flip_comma.rs +++ b/crates/ra_assists/src/assists/flip_comma.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::{algo::non_trivia_sibling, Direction, T}; | 4 | use ra_syntax::{algo::non_trivia_sibling, Direction, T}; |
3 | 5 | ||
diff --git a/crates/ra_assists/src/assists/inline_local_variable.rs b/crates/ra_assists/src/assists/inline_local_variable.rs index eedb29199..9bd64decc 100644 --- a/crates/ra_assists/src/assists/inline_local_variable.rs +++ b/crates/ra_assists/src/assists/inline_local_variable.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast::{self, AstNode, AstToken}, | 5 | ast::{self, AstNode, AstToken}, |
diff --git a/crates/ra_assists/src/assists/introduce_variable.rs b/crates/ra_assists/src/assists/introduce_variable.rs index 470ffe120..43378c4b0 100644 --- a/crates/ra_assists/src/assists/introduce_variable.rs +++ b/crates/ra_assists/src/assists/introduce_variable.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use format_buf::format; | 3 | use format_buf::format; |
2 | use hir::db::HirDatabase; | 4 | use hir::db::HirDatabase; |
3 | use ra_syntax::{ | 5 | use ra_syntax::{ |
diff --git a/crates/ra_assists/src/assists/merge_match_arms.rs b/crates/ra_assists/src/assists/merge_match_arms.rs index 3b6a99895..17baa98f9 100644 --- a/crates/ra_assists/src/assists/merge_match_arms.rs +++ b/crates/ra_assists/src/assists/merge_match_arms.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit}; | 3 | use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit}; |
2 | use hir::db::HirDatabase; | 4 | use hir::db::HirDatabase; |
3 | use ra_syntax::ast::{AstNode, MatchArm}; | 5 | use ra_syntax::ast::{AstNode, MatchArm}; |
diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs index fd4bdc55c..f791d22b0 100644 --- a/crates/ra_assists/src/assists/move_bounds.rs +++ b/crates/ra_assists/src/assists/move_bounds.rs | |||
@@ -1,11 +1,13 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast::{self, make, AstNode, NameOwner, TypeBoundsOwner}, | 5 | ast::{self, edit, make, AstNode, NameOwner, TypeBoundsOwner}, |
4 | SyntaxElement, | 6 | SyntaxElement, |
5 | SyntaxKind::*, | 7 | SyntaxKind::*, |
6 | }; | 8 | }; |
7 | 9 | ||
8 | use crate::{ast_editor::AstEditor, Assist, AssistCtx, AssistId}; | 10 | use crate::{Assist, AssistCtx, AssistId}; |
9 | 11 | ||
10 | pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 12 | pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
11 | let type_param_list = ctx.node_at_offset::<ast::TypeParamList>()?; | 13 | let type_param_list = ctx.node_at_offset::<ast::TypeParamList>()?; |
@@ -39,14 +41,12 @@ pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) | |||
39 | .type_params() | 41 | .type_params() |
40 | .filter(|it| it.type_bound_list().is_some()) | 42 | .filter(|it| it.type_bound_list().is_some()) |
41 | .map(|type_param| { | 43 | .map(|type_param| { |
42 | let without_bounds = | 44 | let without_bounds = type_param.remove_bounds(); |
43 | AstEditor::new(type_param.clone()).remove_bounds().ast().clone(); | ||
44 | (type_param, without_bounds) | 45 | (type_param, without_bounds) |
45 | }); | 46 | }); |
46 | 47 | ||
47 | let mut ast_editor = AstEditor::new(type_param_list.clone()); | 48 | let new_type_param_list = edit::replace_descendants(&type_param_list, new_params); |
48 | ast_editor.replace_descendants(new_params); | 49 | edit.replace_ast(type_param_list.clone(), new_type_param_list); |
49 | ast_editor.into_text_edit(edit.text_edit_builder()); | ||
50 | 50 | ||
51 | let where_clause = { | 51 | let where_clause = { |
52 | let predicates = type_param_list.type_params().filter_map(build_predicate); | 52 | let predicates = type_param_list.type_params().filter_map(build_predicate); |
diff --git a/crates/ra_assists/src/assists/move_guard.rs b/crates/ra_assists/src/assists/move_guard.rs index 699221e33..51aea6334 100644 --- a/crates/ra_assists/src/assists/move_guard.rs +++ b/crates/ra_assists/src/assists/move_guard.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast, | 5 | ast, |
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs index 200aaa59a..2d2e31e51 100644 --- a/crates/ra_assists/src/assists/raw_string.rs +++ b/crates/ra_assists/src/assists/raw_string.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use hir::db::HirDatabase; | 3 | use hir::db::HirDatabase; |
2 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; | 4 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; |
3 | use rustc_lexer; | 5 | use rustc_lexer; |
diff --git a/crates/ra_assists/src/assists/remove_dbg.rs b/crates/ra_assists/src/assists/remove_dbg.rs index 870133fda..1a7e2b305 100644 --- a/crates/ra_assists/src/assists/remove_dbg.rs +++ b/crates/ra_assists/src/assists/remove_dbg.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use crate::{Assist, AssistCtx, AssistId}; | 3 | use crate::{Assist, AssistCtx, AssistId}; |
2 | use hir::db::HirDatabase; | 4 | use hir::db::HirDatabase; |
3 | use ra_syntax::{ | 5 | use ra_syntax::{ |
diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs index 401835c57..749ff338a 100644 --- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use format_buf::format; | 3 | use format_buf::format; |
2 | use hir::db::HirDatabase; | 4 | use hir::db::HirDatabase; |
3 | use ra_fmt::extract_trivial_expression; | 5 | use ra_fmt::extract_trivial_expression; |
diff --git a/crates/ra_assists/src/assists/split_import.rs b/crates/ra_assists/src/assists/split_import.rs index 2c1edddb9..fe3e64af5 100644 --- a/crates/ra_assists/src/assists/split_import.rs +++ b/crates/ra_assists/src/assists/split_import.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::iter::successors; | 3 | use std::iter::successors; |
2 | 4 | ||
3 | use hir::db::HirDatabase; | 5 | use hir::db::HirDatabase; |
@@ -49,13 +51,13 @@ mod tests { | |||
49 | fn split_import_works_with_trees() { | 51 | fn split_import_works_with_trees() { |
50 | check_assist( | 52 | check_assist( |
51 | split_import, | 53 | split_import, |
52 | "use algo:<|>:visitor::{Visitor, visit}", | 54 | "use crate:<|>:db::{RootDatabase, FileSymbol}", |
53 | "use algo::{<|>visitor::{Visitor, visit}}", | 55 | "use crate::{<|>db::{RootDatabase, FileSymbol}}", |
54 | ) | 56 | ) |
55 | } | 57 | } |
56 | 58 | ||
57 | #[test] | 59 | #[test] |
58 | fn split_import_target() { | 60 | fn split_import_target() { |
59 | check_assist_target(split_import, "use algo::<|>visitor::{Visitor, visit}", "::"); | 61 | check_assist_target(split_import, "use crate::<|>db::{RootDatabase, FileSymbol}", "::"); |
60 | } | 62 | } |
61 | } | 63 | } |
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs deleted file mode 100644 index 2a685f26e..000000000 --- a/crates/ra_assists/src/ast_editor.rs +++ /dev/null | |||
@@ -1,315 +0,0 @@ | |||
1 | use std::{iter, ops::RangeInclusive}; | ||
2 | |||
3 | use arrayvec::ArrayVec; | ||
4 | use rustc_hash::FxHashMap; | ||
5 | |||
6 | use ra_fmt::leading_indent; | ||
7 | use ra_syntax::{ | ||
8 | algo, | ||
9 | ast::{self, TypeBoundsOwner}, | ||
10 | AstNode, Direction, InsertPosition, SyntaxElement, | ||
11 | SyntaxKind::*, | ||
12 | T, | ||
13 | }; | ||
14 | use ra_text_edit::TextEditBuilder; | ||
15 | |||
16 | pub struct AstEditor<N: AstNode> { | ||
17 | original_ast: N, | ||
18 | ast: N, | ||
19 | } | ||
20 | |||
21 | impl<N: AstNode> AstEditor<N> { | ||
22 | pub fn new(node: N) -> AstEditor<N> | ||
23 | where | ||
24 | N: Clone, | ||
25 | { | ||
26 | AstEditor { original_ast: node.clone(), ast: node } | ||
27 | } | ||
28 | |||
29 | pub fn into_text_edit(self, builder: &mut TextEditBuilder) { | ||
30 | for (from, to) in algo::diff(&self.original_ast.syntax(), self.ast().syntax()) { | ||
31 | builder.replace(from.text_range(), to.to_string()) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | pub fn ast(&self) -> &N { | ||
36 | &self.ast | ||
37 | } | ||
38 | |||
39 | pub fn replace_descendants<T: AstNode>( | ||
40 | &mut self, | ||
41 | replacement_map: impl Iterator<Item = (T, T)>, | ||
42 | ) -> &mut Self { | ||
43 | let map = replacement_map | ||
44 | .map(|(from, to)| (from.syntax().clone().into(), to.syntax().clone().into())) | ||
45 | .collect::<FxHashMap<_, _>>(); | ||
46 | let new_syntax = algo::replace_descendants(self.ast.syntax(), &map); | ||
47 | self.ast = N::cast(new_syntax).unwrap(); | ||
48 | self | ||
49 | } | ||
50 | |||
51 | #[must_use] | ||
52 | fn insert_children( | ||
53 | &self, | ||
54 | position: InsertPosition<SyntaxElement>, | ||
55 | mut to_insert: impl Iterator<Item = SyntaxElement>, | ||
56 | ) -> N { | ||
57 | let new_syntax = algo::insert_children(self.ast().syntax(), position, &mut to_insert); | ||
58 | N::cast(new_syntax).unwrap() | ||
59 | } | ||
60 | |||
61 | #[must_use] | ||
62 | fn replace_children( | ||
63 | &self, | ||
64 | to_delete: RangeInclusive<SyntaxElement>, | ||
65 | mut to_insert: impl Iterator<Item = SyntaxElement>, | ||
66 | ) -> N { | ||
67 | let new_syntax = algo::replace_children(self.ast().syntax(), to_delete, &mut to_insert); | ||
68 | N::cast(new_syntax).unwrap() | ||
69 | } | ||
70 | |||
71 | fn do_make_multiline(&mut self) { | ||
72 | let l_curly = | ||
73 | match self.ast().syntax().children_with_tokens().find(|it| it.kind() == T!['{']) { | ||
74 | Some(it) => it, | ||
75 | None => return, | ||
76 | }; | ||
77 | let sibling = match l_curly.next_sibling_or_token() { | ||
78 | Some(it) => it, | ||
79 | None => return, | ||
80 | }; | ||
81 | let existing_ws = match sibling.as_token() { | ||
82 | None => None, | ||
83 | Some(tok) if tok.kind() != WHITESPACE => None, | ||
84 | Some(ws) => { | ||
85 | if ws.text().contains('\n') { | ||
86 | return; | ||
87 | } | ||
88 | Some(ws.clone()) | ||
89 | } | ||
90 | }; | ||
91 | |||
92 | let indent = leading_indent(self.ast().syntax()).unwrap_or("".into()); | ||
93 | let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); | ||
94 | let to_insert = iter::once(ws.ws().into()); | ||
95 | self.ast = match existing_ws { | ||
96 | None => self.insert_children(InsertPosition::After(l_curly), to_insert), | ||
97 | Some(ws) => { | ||
98 | self.replace_children(RangeInclusive::new(ws.clone().into(), ws.into()), to_insert) | ||
99 | } | ||
100 | }; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | impl AstEditor<ast::RecordFieldList> { | ||
105 | pub fn append_field(&mut self, field: &ast::RecordField) { | ||
106 | self.insert_field(InsertPosition::Last, field) | ||
107 | } | ||
108 | |||
109 | pub fn insert_field( | ||
110 | &mut self, | ||
111 | position: InsertPosition<&'_ ast::RecordField>, | ||
112 | field: &ast::RecordField, | ||
113 | ) { | ||
114 | let is_multiline = self.ast().syntax().text().contains_char('\n'); | ||
115 | let ws; | ||
116 | let space = if is_multiline { | ||
117 | ws = tokens::WsBuilder::new(&format!( | ||
118 | "\n{} ", | ||
119 | leading_indent(self.ast().syntax()).unwrap_or("".into()) | ||
120 | )); | ||
121 | ws.ws() | ||
122 | } else { | ||
123 | tokens::single_space() | ||
124 | }; | ||
125 | |||
126 | let mut to_insert: ArrayVec<[SyntaxElement; 4]> = ArrayVec::new(); | ||
127 | to_insert.push(space.into()); | ||
128 | to_insert.push(field.syntax().clone().into()); | ||
129 | to_insert.push(tokens::comma().into()); | ||
130 | |||
131 | macro_rules! after_l_curly { | ||
132 | () => {{ | ||
133 | let anchor = match self.l_curly() { | ||
134 | Some(it) => it, | ||
135 | None => return, | ||
136 | }; | ||
137 | InsertPosition::After(anchor) | ||
138 | }}; | ||
139 | } | ||
140 | |||
141 | macro_rules! after_field { | ||
142 | ($anchor:expr) => { | ||
143 | if let Some(comma) = $anchor | ||
144 | .syntax() | ||
145 | .siblings_with_tokens(Direction::Next) | ||
146 | .find(|it| it.kind() == T![,]) | ||
147 | { | ||
148 | InsertPosition::After(comma) | ||
149 | } else { | ||
150 | to_insert.insert(0, tokens::comma().into()); | ||
151 | InsertPosition::After($anchor.syntax().clone().into()) | ||
152 | } | ||
153 | }; | ||
154 | }; | ||
155 | |||
156 | let position = match position { | ||
157 | InsertPosition::First => after_l_curly!(), | ||
158 | InsertPosition::Last => { | ||
159 | if !is_multiline { | ||
160 | // don't insert comma before curly | ||
161 | to_insert.pop(); | ||
162 | } | ||
163 | match self.ast().fields().last() { | ||
164 | Some(it) => after_field!(it), | ||
165 | None => after_l_curly!(), | ||
166 | } | ||
167 | } | ||
168 | InsertPosition::Before(anchor) => { | ||
169 | InsertPosition::Before(anchor.syntax().clone().into()) | ||
170 | } | ||
171 | InsertPosition::After(anchor) => after_field!(anchor), | ||
172 | }; | ||
173 | |||
174 | self.ast = self.insert_children(position, to_insert.iter().cloned()); | ||
175 | } | ||
176 | |||
177 | fn l_curly(&self) -> Option<SyntaxElement> { | ||
178 | self.ast().syntax().children_with_tokens().find(|it| it.kind() == T!['{']) | ||
179 | } | ||
180 | } | ||
181 | |||
182 | impl AstEditor<ast::ItemList> { | ||
183 | pub fn append_items(&mut self, items: impl Iterator<Item = ast::ImplItem>) { | ||
184 | if !self.ast().syntax().text().contains_char('\n') { | ||
185 | self.do_make_multiline(); | ||
186 | } | ||
187 | items.for_each(|it| self.append_item(it)); | ||
188 | } | ||
189 | |||
190 | pub fn append_item(&mut self, item: ast::ImplItem) { | ||
191 | let (indent, position) = match self.ast().impl_items().last() { | ||
192 | Some(it) => ( | ||
193 | leading_indent(it.syntax()).unwrap_or_default().to_string(), | ||
194 | InsertPosition::After(it.syntax().clone().into()), | ||
195 | ), | ||
196 | None => match self.l_curly() { | ||
197 | Some(it) => ( | ||
198 | " ".to_string() + &leading_indent(self.ast().syntax()).unwrap_or_default(), | ||
199 | InsertPosition::After(it), | ||
200 | ), | ||
201 | None => return, | ||
202 | }, | ||
203 | }; | ||
204 | let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); | ||
205 | let to_insert: ArrayVec<[SyntaxElement; 2]> = | ||
206 | [ws.ws().into(), item.syntax().clone().into()].into(); | ||
207 | self.ast = self.insert_children(position, to_insert.into_iter()); | ||
208 | } | ||
209 | |||
210 | fn l_curly(&self) -> Option<SyntaxElement> { | ||
211 | self.ast().syntax().children_with_tokens().find(|it| it.kind() == T!['{']) | ||
212 | } | ||
213 | } | ||
214 | |||
215 | impl AstEditor<ast::ImplItem> { | ||
216 | pub fn strip_attrs_and_docs(&mut self) { | ||
217 | while let Some(start) = self | ||
218 | .ast() | ||
219 | .syntax() | ||
220 | .children_with_tokens() | ||
221 | .find(|it| it.kind() == ATTR || it.kind() == COMMENT) | ||
222 | { | ||
223 | let end = match &start.next_sibling_or_token() { | ||
224 | Some(el) if el.kind() == WHITESPACE => el.clone(), | ||
225 | Some(_) | None => start.clone(), | ||
226 | }; | ||
227 | self.ast = self.replace_children(RangeInclusive::new(start, end), iter::empty()); | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | |||
232 | impl AstEditor<ast::FnDef> { | ||
233 | pub fn set_body(&mut self, body: &ast::Block) { | ||
234 | let mut to_insert: ArrayVec<[SyntaxElement; 2]> = ArrayVec::new(); | ||
235 | let old_body_or_semi: SyntaxElement = if let Some(old_body) = self.ast().body() { | ||
236 | old_body.syntax().clone().into() | ||
237 | } else if let Some(semi) = self.ast().semicolon_token() { | ||
238 | to_insert.push(tokens::single_space().into()); | ||
239 | semi.into() | ||
240 | } else { | ||
241 | to_insert.push(tokens::single_space().into()); | ||
242 | to_insert.push(body.syntax().clone().into()); | ||
243 | self.ast = self.insert_children(InsertPosition::Last, to_insert.into_iter()); | ||
244 | return; | ||
245 | }; | ||
246 | to_insert.push(body.syntax().clone().into()); | ||
247 | let replace_range = RangeInclusive::new(old_body_or_semi.clone(), old_body_or_semi); | ||
248 | self.ast = self.replace_children(replace_range, to_insert.into_iter()) | ||
249 | } | ||
250 | } | ||
251 | |||
252 | impl AstEditor<ast::TypeParam> { | ||
253 | pub fn remove_bounds(&mut self) -> &mut Self { | ||
254 | let colon = match self.ast.colon_token() { | ||
255 | Some(it) => it, | ||
256 | None => return self, | ||
257 | }; | ||
258 | let end = match self.ast.type_bound_list() { | ||
259 | Some(it) => it.syntax().clone().into(), | ||
260 | None => colon.clone().into(), | ||
261 | }; | ||
262 | self.ast = self.replace_children(RangeInclusive::new(colon.into(), end), iter::empty()); | ||
263 | self | ||
264 | } | ||
265 | } | ||
266 | |||
267 | mod tokens { | ||
268 | use once_cell::sync::Lazy; | ||
269 | use ra_syntax::{AstNode, Parse, SourceFile, SyntaxKind::*, SyntaxToken, T}; | ||
270 | |||
271 | static SOURCE_FILE: Lazy<Parse<SourceFile>> = Lazy::new(|| SourceFile::parse(",\n; ;")); | ||
272 | |||
273 | pub(crate) fn comma() -> SyntaxToken { | ||
274 | SOURCE_FILE | ||
275 | .tree() | ||
276 | .syntax() | ||
277 | .descendants_with_tokens() | ||
278 | .filter_map(|it| it.into_token()) | ||
279 | .find(|it| it.kind() == T![,]) | ||
280 | .unwrap() | ||
281 | } | ||
282 | |||
283 | pub(crate) fn single_space() -> SyntaxToken { | ||
284 | SOURCE_FILE | ||
285 | .tree() | ||
286 | .syntax() | ||
287 | .descendants_with_tokens() | ||
288 | .filter_map(|it| it.into_token()) | ||
289 | .find(|it| it.kind() == WHITESPACE && it.text().as_str() == " ") | ||
290 | .unwrap() | ||
291 | } | ||
292 | |||
293 | #[allow(unused)] | ||
294 | pub(crate) fn single_newline() -> SyntaxToken { | ||
295 | SOURCE_FILE | ||
296 | .tree() | ||
297 | .syntax() | ||
298 | .descendants_with_tokens() | ||
299 | .filter_map(|it| it.into_token()) | ||
300 | .find(|it| it.kind() == WHITESPACE && it.text().as_str() == "\n") | ||
301 | .unwrap() | ||
302 | } | ||
303 | |||
304 | pub(crate) struct WsBuilder(SourceFile); | ||
305 | |||
306 | impl WsBuilder { | ||
307 | pub(crate) fn new(text: &str) -> WsBuilder { | ||
308 | WsBuilder(SourceFile::parse(text).ok().unwrap()) | ||
309 | } | ||
310 | pub(crate) fn ws(&self) -> SyntaxToken { | ||
311 | self.0.syntax().first_child_or_token().unwrap().into_token().unwrap() | ||
312 | } | ||
313 | } | ||
314 | |||
315 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 3ca3320f7..d2376c475 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -7,7 +7,6 @@ | |||
7 | 7 | ||
8 | mod assist_ctx; | 8 | mod assist_ctx; |
9 | mod marks; | 9 | mod marks; |
10 | pub mod ast_editor; | ||
11 | 10 | ||
12 | use hir::db::HirDatabase; | 11 | use hir::db::HirDatabase; |
13 | use itertools::Itertools; | 12 | use itertools::Itertools; |
@@ -93,6 +92,7 @@ mod assists { | |||
93 | mod add_derive; | 92 | mod add_derive; |
94 | mod add_explicit_type; | 93 | mod add_explicit_type; |
95 | mod add_impl; | 94 | mod add_impl; |
95 | mod apply_demorgan; | ||
96 | mod flip_comma; | 96 | mod flip_comma; |
97 | mod flip_binexpr; | 97 | mod flip_binexpr; |
98 | mod change_visibility; | 98 | mod change_visibility; |
@@ -114,6 +114,7 @@ mod assists { | |||
114 | add_derive::add_derive, | 114 | add_derive::add_derive, |
115 | add_explicit_type::add_explicit_type, | 115 | add_explicit_type::add_explicit_type, |
116 | add_impl::add_impl, | 116 | add_impl::add_impl, |
117 | apply_demorgan::apply_demorgan, | ||
117 | change_visibility::change_visibility, | 118 | change_visibility::change_visibility, |
118 | fill_match_arms::fill_match_arms, | 119 | fill_match_arms::fill_match_arms, |
119 | merge_match_arms::merge_match_arms, | 120 | merge_match_arms::merge_match_arms, |
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs index a29f9f658..c20e4db9e 100644 --- a/crates/ra_assists/src/marks.rs +++ b/crates/ra_assists/src/marks.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! See test_utils/src/marks.rs | ||
2 | |||
1 | test_utils::marks!( | 3 | test_utils::marks!( |
2 | introduce_var_in_comment_is_not_applicable | 4 | introduce_var_in_comment_is_not_applicable |
3 | test_introduce_var_expr_stmt | 5 | test_introduce_var_expr_stmt |
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs index ffc9e16bb..a5fc2a23e 100644 --- a/crates/ra_batch/src/lib.rs +++ b/crates/ra_batch/src/lib.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{collections::HashSet, error::Error, path::Path}; | 3 | use std::{collections::HashSet, error::Error, path::Path}; |
2 | 4 | ||
3 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
@@ -5,7 +7,7 @@ use rustc_hash::FxHashMap; | |||
5 | use crossbeam_channel::{unbounded, Receiver}; | 7 | use crossbeam_channel::{unbounded, Receiver}; |
6 | use ra_db::{CrateGraph, FileId, SourceRootId}; | 8 | use ra_db::{CrateGraph, FileId, SourceRootId}; |
7 | use ra_ide_api::{AnalysisChange, AnalysisHost, FeatureFlags}; | 9 | use ra_ide_api::{AnalysisChange, AnalysisHost, FeatureFlags}; |
8 | use ra_project_model::{PackageRoot, ProjectWorkspace}; | 10 | use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace}; |
9 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; | 11 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; |
10 | use ra_vfs_glob::RustPackageFilterBuilder; | 12 | use ra_vfs_glob::RustPackageFilterBuilder; |
11 | 13 | ||
@@ -39,11 +41,17 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, | |||
39 | sender, | 41 | sender, |
40 | Watch(false), | 42 | Watch(false), |
41 | ); | 43 | ); |
42 | let (crate_graph, _crate_names) = ws.to_crate_graph(&mut |path: &Path| { | 44 | |
43 | let vfs_file = vfs.load(path); | 45 | // FIXME: cfg options? |
44 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); | 46 | let default_cfg_options = |
45 | vfs_file.map(vfs_file_to_id) | 47 | get_rustc_cfg_options().atom("test".into()).atom("debug_assertion".into()); |
46 | }); | 48 | |
49 | let (crate_graph, _crate_names) = | ||
50 | ws.to_crate_graph(&default_cfg_options, &mut |path: &Path| { | ||
51 | let vfs_file = vfs.load(path); | ||
52 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); | ||
53 | vfs_file.map(vfs_file_to_id) | ||
54 | }); | ||
47 | log::debug!("crate graph: {:?}", crate_graph); | 55 | log::debug!("crate graph: {:?}", crate_graph); |
48 | 56 | ||
49 | let source_roots = roots | 57 | let source_roots = roots |
diff --git a/crates/ra_cfg/Cargo.toml b/crates/ra_cfg/Cargo.toml new file mode 100644 index 000000000..b28affc3a --- /dev/null +++ b/crates/ra_cfg/Cargo.toml | |||
@@ -0,0 +1,14 @@ | |||
1 | [package] | ||
2 | edition = "2018" | ||
3 | name = "ra_cfg" | ||
4 | version = "0.1.0" | ||
5 | authors = ["rust-analyzer developers"] | ||
6 | |||
7 | [dependencies] | ||
8 | rustc-hash = "1.0.1" | ||
9 | |||
10 | ra_syntax = { path = "../ra_syntax" } | ||
11 | tt = { path = "../ra_tt", package = "ra_tt" } | ||
12 | |||
13 | [dev-dependencies] | ||
14 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | ||
diff --git a/crates/ra_cfg/src/cfg_expr.rs b/crates/ra_cfg/src/cfg_expr.rs new file mode 100644 index 000000000..39d71851c --- /dev/null +++ b/crates/ra_cfg/src/cfg_expr.rs | |||
@@ -0,0 +1,132 @@ | |||
1 | //! The condition expression used in `#[cfg(..)]` attributes. | ||
2 | //! | ||
3 | //! See: https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation | ||
4 | |||
5 | use std::slice::Iter as SliceIter; | ||
6 | |||
7 | use ra_syntax::SmolStr; | ||
8 | use tt::{Leaf, Subtree, TokenTree}; | ||
9 | |||
10 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
11 | pub enum CfgExpr { | ||
12 | Invalid, | ||
13 | Atom(SmolStr), | ||
14 | KeyValue { key: SmolStr, value: SmolStr }, | ||
15 | All(Vec<CfgExpr>), | ||
16 | Any(Vec<CfgExpr>), | ||
17 | Not(Box<CfgExpr>), | ||
18 | } | ||
19 | |||
20 | impl CfgExpr { | ||
21 | /// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates. | ||
22 | pub fn fold(&self, query: &dyn Fn(&SmolStr, Option<&SmolStr>) -> bool) -> Option<bool> { | ||
23 | match self { | ||
24 | CfgExpr::Invalid => None, | ||
25 | CfgExpr::Atom(name) => Some(query(name, None)), | ||
26 | CfgExpr::KeyValue { key, value } => Some(query(key, Some(value))), | ||
27 | CfgExpr::All(preds) => { | ||
28 | preds.iter().try_fold(true, |s, pred| Some(s && pred.fold(query)?)) | ||
29 | } | ||
30 | CfgExpr::Any(preds) => { | ||
31 | preds.iter().try_fold(false, |s, pred| Some(s || pred.fold(query)?)) | ||
32 | } | ||
33 | CfgExpr::Not(pred) => pred.fold(query).map(|s| !s), | ||
34 | } | ||
35 | } | ||
36 | } | ||
37 | |||
38 | pub fn parse_cfg(tt: &Subtree) -> CfgExpr { | ||
39 | next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid) | ||
40 | } | ||
41 | |||
42 | fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { | ||
43 | let name = match it.next() { | ||
44 | None => return None, | ||
45 | Some(TokenTree::Leaf(Leaf::Ident(ident))) => ident.text.clone(), | ||
46 | Some(_) => return Some(CfgExpr::Invalid), | ||
47 | }; | ||
48 | |||
49 | // Peek | ||
50 | let ret = match it.as_slice().first() { | ||
51 | Some(TokenTree::Leaf(Leaf::Punct(punct))) if punct.char == '=' => { | ||
52 | match it.as_slice().get(1) { | ||
53 | Some(TokenTree::Leaf(Leaf::Literal(literal))) => { | ||
54 | it.next(); | ||
55 | it.next(); | ||
56 | // FIXME: escape? raw string? | ||
57 | let value = | ||
58 | SmolStr::new(literal.text.trim_start_matches('"').trim_end_matches('"')); | ||
59 | CfgExpr::KeyValue { key: name, value } | ||
60 | } | ||
61 | _ => return Some(CfgExpr::Invalid), | ||
62 | } | ||
63 | } | ||
64 | Some(TokenTree::Subtree(subtree)) => { | ||
65 | it.next(); | ||
66 | let mut sub_it = subtree.token_trees.iter(); | ||
67 | let mut subs = std::iter::from_fn(|| next_cfg_expr(&mut sub_it)).collect(); | ||
68 | match name.as_str() { | ||
69 | "all" => CfgExpr::All(subs), | ||
70 | "any" => CfgExpr::Any(subs), | ||
71 | "not" => CfgExpr::Not(Box::new(subs.pop().unwrap_or(CfgExpr::Invalid))), | ||
72 | _ => CfgExpr::Invalid, | ||
73 | } | ||
74 | } | ||
75 | _ => CfgExpr::Atom(name), | ||
76 | }; | ||
77 | |||
78 | // Eat comma separator | ||
79 | if let Some(TokenTree::Leaf(Leaf::Punct(punct))) = it.as_slice().first() { | ||
80 | if punct.char == ',' { | ||
81 | it.next(); | ||
82 | } | ||
83 | } | ||
84 | Some(ret) | ||
85 | } | ||
86 | |||
87 | #[cfg(test)] | ||
88 | mod tests { | ||
89 | use super::*; | ||
90 | |||
91 | use mbe::ast_to_token_tree; | ||
92 | use ra_syntax::ast::{self, AstNode}; | ||
93 | |||
94 | fn assert_parse_result(input: &str, expected: CfgExpr) { | ||
95 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | ||
96 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
97 | let (tt, _) = ast_to_token_tree(&tt).unwrap(); | ||
98 | assert_eq!(parse_cfg(&tt), expected); | ||
99 | } | ||
100 | |||
101 | #[test] | ||
102 | fn test_cfg_expr_parser() { | ||
103 | assert_parse_result("#![cfg(foo)]", CfgExpr::Atom("foo".into())); | ||
104 | assert_parse_result("#![cfg(foo,)]", CfgExpr::Atom("foo".into())); | ||
105 | assert_parse_result( | ||
106 | "#![cfg(not(foo))]", | ||
107 | CfgExpr::Not(Box::new(CfgExpr::Atom("foo".into()))), | ||
108 | ); | ||
109 | assert_parse_result("#![cfg(foo(bar))]", CfgExpr::Invalid); | ||
110 | |||
111 | // Only take the first | ||
112 | assert_parse_result(r#"#![cfg(foo, bar = "baz")]"#, CfgExpr::Atom("foo".into())); | ||
113 | |||
114 | assert_parse_result( | ||
115 | r#"#![cfg(all(foo, bar = "baz"))]"#, | ||
116 | CfgExpr::All(vec![ | ||
117 | CfgExpr::Atom("foo".into()), | ||
118 | CfgExpr::KeyValue { key: "bar".into(), value: "baz".into() }, | ||
119 | ]), | ||
120 | ); | ||
121 | |||
122 | assert_parse_result( | ||
123 | r#"#![cfg(any(not(), all(), , bar = "baz",))]"#, | ||
124 | CfgExpr::Any(vec![ | ||
125 | CfgExpr::Not(Box::new(CfgExpr::Invalid)), | ||
126 | CfgExpr::All(vec![]), | ||
127 | CfgExpr::Invalid, | ||
128 | CfgExpr::KeyValue { key: "bar".into(), value: "baz".into() }, | ||
129 | ]), | ||
130 | ); | ||
131 | } | ||
132 | } | ||
diff --git a/crates/ra_cfg/src/lib.rs b/crates/ra_cfg/src/lib.rs new file mode 100644 index 000000000..e1c92fbba --- /dev/null +++ b/crates/ra_cfg/src/lib.rs | |||
@@ -0,0 +1,61 @@ | |||
1 | //! ra_cfg defines conditional compiling options, `cfg` attibute parser and evaluator | ||
2 | use std::iter::IntoIterator; | ||
3 | |||
4 | use ra_syntax::SmolStr; | ||
5 | use rustc_hash::FxHashSet; | ||
6 | |||
7 | mod cfg_expr; | ||
8 | |||
9 | pub use cfg_expr::{parse_cfg, CfgExpr}; | ||
10 | |||
11 | /// Configuration options used for conditional compilition on items with `cfg` attributes. | ||
12 | /// We have two kind of options in different namespaces: atomic options like `unix`, and | ||
13 | /// key-value options like `target_arch="x86"`. | ||
14 | /// | ||
15 | /// Note that for key-value options, one key can have multiple values (but not none). | ||
16 | /// `feature` is an example. We have both `feature="foo"` and `feature="bar"` if features | ||
17 | /// `foo` and `bar` are both enabled. And here, we store key-value options as a set of tuple | ||
18 | /// of key and value in `key_values`. | ||
19 | /// | ||
20 | /// See: https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options | ||
21 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | ||
22 | pub struct CfgOptions { | ||
23 | atoms: FxHashSet<SmolStr>, | ||
24 | key_values: FxHashSet<(SmolStr, SmolStr)>, | ||
25 | } | ||
26 | |||
27 | impl CfgOptions { | ||
28 | pub fn check(&self, cfg: &CfgExpr) -> Option<bool> { | ||
29 | cfg.fold(&|key, value| match value { | ||
30 | None => self.atoms.contains(key), | ||
31 | Some(value) => self.key_values.contains(&(key.clone(), value.clone())), | ||
32 | }) | ||
33 | } | ||
34 | |||
35 | pub fn is_cfg_enabled(&self, attr: &tt::Subtree) -> Option<bool> { | ||
36 | self.check(&parse_cfg(attr)) | ||
37 | } | ||
38 | |||
39 | pub fn atom(mut self, name: SmolStr) -> CfgOptions { | ||
40 | self.atoms.insert(name); | ||
41 | self | ||
42 | } | ||
43 | |||
44 | pub fn key_value(mut self, key: SmolStr, value: SmolStr) -> CfgOptions { | ||
45 | self.key_values.insert((key, value)); | ||
46 | self | ||
47 | } | ||
48 | |||
49 | /// Shortcut to set features | ||
50 | pub fn features(mut self, iter: impl IntoIterator<Item = SmolStr>) -> CfgOptions { | ||
51 | for feat in iter { | ||
52 | self = self.key_value("feature".into(), feat); | ||
53 | } | ||
54 | self | ||
55 | } | ||
56 | |||
57 | pub fn remove_atom(mut self, name: &SmolStr) -> CfgOptions { | ||
58 | self.atoms.remove(name); | ||
59 | self | ||
60 | } | ||
61 | } | ||
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index d42ac3ad4..67e727a88 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml | |||
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"] | |||
6 | publish = false | 6 | publish = false |
7 | 7 | ||
8 | [dependencies] | 8 | [dependencies] |
9 | pico-args = "0.2.0" | 9 | pico-args = "0.3.0" |
10 | flexi_logger = "0.14.0" | 10 | flexi_logger = "0.14.0" |
11 | indicatif = "0.11.0" | 11 | indicatif = "0.11.0" |
12 | 12 | ||
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs index 01b96ec58..727f1e62b 100644 --- a/crates/ra_cli/src/analysis_bench.rs +++ b/crates/ra_cli/src/analysis_bench.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{ | 3 | use std::{ |
2 | path::{Path, PathBuf}, | 4 | path::{Path, PathBuf}, |
3 | sync::Arc, | 5 | sync::Arc, |
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs index 6b1e44a2c..a8a110bd9 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_cli/src/analysis_stats.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; | 3 | use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; |
2 | 4 | ||
3 | use ra_db::SourceDatabase; | 5 | use ra_db::SourceDatabase; |
diff --git a/crates/ra_cli/src/help.rs b/crates/ra_cli/src/help.rs index 2a74b8733..d3c4c7d0b 100644 --- a/crates/ra_cli/src/help.rs +++ b/crates/ra_cli/src/help.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | pub const GLOBAL_HELP: &str = "ra-cli | 3 | pub const GLOBAL_HELP: &str = "ra-cli |
2 | 4 | ||
3 | USAGE: | 5 | USAGE: |
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index 8b91ba3e9..2405eb4f4 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | mod analysis_stats; | 3 | mod analysis_stats; |
2 | mod analysis_bench; | 4 | mod analysis_bench; |
3 | mod help; | 5 | mod help; |
@@ -93,7 +95,7 @@ fn main() -> Result<()> { | |||
93 | (true, true) => Err("Invalid flags: -q conflicts with -v")?, | 95 | (true, true) => Err("Invalid flags: -q conflicts with -v")?, |
94 | }; | 96 | }; |
95 | let memory_usage = matches.contains("--memory-usage"); | 97 | let memory_usage = matches.contains("--memory-usage"); |
96 | let only: Option<String> = matches.value_from_str(["-o", "--only"])?; | 98 | let only: Option<String> = matches.opt_value_from_str(["-o", "--only"])?; |
97 | let path = { | 99 | let path = { |
98 | let mut trailing = matches.free()?; | 100 | let mut trailing = matches.free()?; |
99 | if trailing.len() != 1 { | 101 | if trailing.len() != 1 { |
@@ -115,9 +117,9 @@ fn main() -> Result<()> { | |||
115 | return Ok(()); | 117 | return Ok(()); |
116 | } | 118 | } |
117 | let verbose = matches.contains(["-v", "--verbose"]); | 119 | let verbose = matches.contains(["-v", "--verbose"]); |
118 | let path: String = matches.value_from_str("--path")?.unwrap_or_default(); | 120 | let path: String = matches.opt_value_from_str("--path")?.unwrap_or_default(); |
119 | let highlight_path = matches.value_from_str("--highlight")?; | 121 | let highlight_path = matches.opt_value_from_str("--highlight")?; |
120 | let complete_path = matches.value_from_str("--complete")?; | 122 | let complete_path = matches.opt_value_from_str("--complete")?; |
121 | if highlight_path.is_some() && complete_path.is_some() { | 123 | if highlight_path.is_some() && complete_path.is_some() { |
122 | panic!("either --highlight or --complete must be set, not both") | 124 | panic!("either --highlight or --complete must be set, not both") |
123 | } | 125 | } |
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml index 2fac07bc5..c141f1a88 100644 --- a/crates/ra_db/Cargo.toml +++ b/crates/ra_db/Cargo.toml | |||
@@ -10,4 +10,5 @@ relative-path = "0.4.0" | |||
10 | rustc-hash = "1.0" | 10 | rustc-hash = "1.0" |
11 | 11 | ||
12 | ra_syntax = { path = "../ra_syntax" } | 12 | ra_syntax = { path = "../ra_syntax" } |
13 | ra_cfg = { path = "../ra_cfg" } | ||
13 | ra_prof = { path = "../ra_prof" } | 14 | ra_prof = { path = "../ra_prof" } |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index a1ace61b6..23148096c 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -1,13 +1,15 @@ | |||
1 | /// This module specifies the input to rust-analyzer. In some sense, this is | 1 | //! This module specifies the input to rust-analyzer. In some sense, this is |
2 | /// **the** most important module, because all other fancy stuff is strictly | 2 | //! **the** most important module, because all other fancy stuff is strictly |
3 | /// derived from this input. | 3 | //! derived from this input. |
4 | /// | 4 | //! |
5 | /// Note that neither this module, nor any other part of the analyzer's core do | 5 | //! Note that neither this module, nor any other part of the analyzer's core do |
6 | /// actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how | 6 | //! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how |
7 | /// actual IO is done and lowered to input. | 7 | //! actual IO is done and lowered to input. |
8 | |||
8 | use relative_path::{RelativePath, RelativePathBuf}; | 9 | use relative_path::{RelativePath, RelativePathBuf}; |
9 | use rustc_hash::FxHashMap; | 10 | use rustc_hash::FxHashMap; |
10 | 11 | ||
12 | use ra_cfg::CfgOptions; | ||
11 | use ra_syntax::SmolStr; | 13 | use ra_syntax::SmolStr; |
12 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
13 | 15 | ||
@@ -108,11 +110,12 @@ struct CrateData { | |||
108 | file_id: FileId, | 110 | file_id: FileId, |
109 | edition: Edition, | 111 | edition: Edition, |
110 | dependencies: Vec<Dependency>, | 112 | dependencies: Vec<Dependency>, |
113 | cfg_options: CfgOptions, | ||
111 | } | 114 | } |
112 | 115 | ||
113 | impl CrateData { | 116 | impl CrateData { |
114 | fn new(file_id: FileId, edition: Edition) -> CrateData { | 117 | fn new(file_id: FileId, edition: Edition, cfg_options: CfgOptions) -> CrateData { |
115 | CrateData { file_id, edition, dependencies: Vec::new() } | 118 | CrateData { file_id, edition, dependencies: Vec::new(), cfg_options } |
116 | } | 119 | } |
117 | 120 | ||
118 | fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { | 121 | fn add_dep(&mut self, name: SmolStr, crate_id: CrateId) { |
@@ -133,13 +136,22 @@ impl Dependency { | |||
133 | } | 136 | } |
134 | 137 | ||
135 | impl CrateGraph { | 138 | impl CrateGraph { |
136 | pub fn add_crate_root(&mut self, file_id: FileId, edition: Edition) -> CrateId { | 139 | pub fn add_crate_root( |
140 | &mut self, | ||
141 | file_id: FileId, | ||
142 | edition: Edition, | ||
143 | cfg_options: CfgOptions, | ||
144 | ) -> CrateId { | ||
137 | let crate_id = CrateId(self.arena.len() as u32); | 145 | let crate_id = CrateId(self.arena.len() as u32); |
138 | let prev = self.arena.insert(crate_id, CrateData::new(file_id, edition)); | 146 | let prev = self.arena.insert(crate_id, CrateData::new(file_id, edition, cfg_options)); |
139 | assert!(prev.is_none()); | 147 | assert!(prev.is_none()); |
140 | crate_id | 148 | crate_id |
141 | } | 149 | } |
142 | 150 | ||
151 | pub fn cfg_options(&self, crate_id: CrateId) -> &CfgOptions { | ||
152 | &self.arena[&crate_id].cfg_options | ||
153 | } | ||
154 | |||
143 | pub fn add_dep( | 155 | pub fn add_dep( |
144 | &mut self, | 156 | &mut self, |
145 | from: CrateId, | 157 | from: CrateId, |
@@ -220,14 +232,14 @@ impl CrateGraph { | |||
220 | 232 | ||
221 | #[cfg(test)] | 233 | #[cfg(test)] |
222 | mod tests { | 234 | mod tests { |
223 | use super::{CrateGraph, Edition::Edition2018, FileId, SmolStr}; | 235 | use super::{CfgOptions, CrateGraph, Edition::Edition2018, FileId, SmolStr}; |
224 | 236 | ||
225 | #[test] | 237 | #[test] |
226 | fn it_should_panic_because_of_cycle_dependencies() { | 238 | fn it_should_panic_because_of_cycle_dependencies() { |
227 | let mut graph = CrateGraph::default(); | 239 | let mut graph = CrateGraph::default(); |
228 | let crate1 = graph.add_crate_root(FileId(1u32), Edition2018); | 240 | let crate1 = graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default()); |
229 | let crate2 = graph.add_crate_root(FileId(2u32), Edition2018); | 241 | let crate2 = graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default()); |
230 | let crate3 = graph.add_crate_root(FileId(3u32), Edition2018); | 242 | let crate3 = graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default()); |
231 | assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); | 243 | assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); |
232 | assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); | 244 | assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); |
233 | assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err()); | 245 | assert!(graph.add_dep(crate3, SmolStr::new("crate1"), crate1).is_err()); |
@@ -236,9 +248,9 @@ mod tests { | |||
236 | #[test] | 248 | #[test] |
237 | fn it_works() { | 249 | fn it_works() { |
238 | let mut graph = CrateGraph::default(); | 250 | let mut graph = CrateGraph::default(); |
239 | let crate1 = graph.add_crate_root(FileId(1u32), Edition2018); | 251 | let crate1 = graph.add_crate_root(FileId(1u32), Edition2018, CfgOptions::default()); |
240 | let crate2 = graph.add_crate_root(FileId(2u32), Edition2018); | 252 | let crate2 = graph.add_crate_root(FileId(2u32), Edition2018, CfgOptions::default()); |
241 | let crate3 = graph.add_crate_root(FileId(3u32), Edition2018); | 253 | let crate3 = graph.add_crate_root(FileId(3u32), Edition2018, CfgOptions::default()); |
242 | assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); | 254 | assert!(graph.add_dep(crate1, SmolStr::new("crate2"), crate2).is_ok()); |
243 | assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); | 255 | assert!(graph.add_dep(crate2, SmolStr::new("crate3"), crate3).is_ok()); |
244 | } | 256 | } |
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index c54791b7a..603daed37 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -32,11 +32,10 @@ pub trait CheckCanceled { | |||
32 | 32 | ||
33 | fn catch_canceled<F, T>(&self, f: F) -> Result<T, Canceled> | 33 | fn catch_canceled<F, T>(&self, f: F) -> Result<T, Canceled> |
34 | where | 34 | where |
35 | Self: Sized, | 35 | Self: Sized + panic::RefUnwindSafe, |
36 | F: FnOnce(&Self) -> T + panic::UnwindSafe, | 36 | F: FnOnce(&Self) -> T + panic::UnwindSafe, |
37 | { | 37 | { |
38 | let this = panic::AssertUnwindSafe(self); | 38 | panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() { |
39 | panic::catch_unwind(|| f(*this)).map_err(|err| match err.downcast::<Canceled>() { | ||
40 | Ok(canceled) => *canceled, | 39 | Ok(canceled) => *canceled, |
41 | Err(payload) => panic::resume_unwind(payload), | 40 | Err(payload) => panic::resume_unwind(payload), |
42 | }) | 41 | }) |
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index d9bed4dda..cc117f84d 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -15,6 +15,7 @@ once_cell = "1.0.1" | |||
15 | 15 | ||
16 | ra_syntax = { path = "../ra_syntax" } | 16 | ra_syntax = { path = "../ra_syntax" } |
17 | ra_arena = { path = "../ra_arena" } | 17 | ra_arena = { path = "../ra_arena" } |
18 | ra_cfg = { path = "../ra_cfg" } | ||
18 | ra_db = { path = "../ra_db" } | 19 | ra_db = { path = "../ra_db" } |
19 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | 20 | mbe = { path = "../ra_mbe", package = "ra_mbe" } |
20 | tt = { path = "../ra_tt", package = "ra_tt" } | 21 | tt = { path = "../ra_tt", package = "ra_tt" } |
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index fbb4ff4d8..99d286215 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs | |||
@@ -133,7 +133,7 @@ impl VariantData { | |||
133 | .fields() | 133 | .fields() |
134 | .enumerate() | 134 | .enumerate() |
135 | .map(|(i, fd)| StructFieldData { | 135 | .map(|(i, fd)| StructFieldData { |
136 | name: Name::tuple_field_name(i), | 136 | name: Name::new_tuple_field(i), |
137 | type_ref: TypeRef::from_ast_opt(fd.type_ref()), | 137 | type_ref: TypeRef::from_ast_opt(fd.type_ref()), |
138 | }) | 138 | }) |
139 | .collect(); | 139 | .collect(); |
diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir/src/attr.rs new file mode 100644 index 000000000..f67e80bfd --- /dev/null +++ b/crates/ra_hir/src/attr.rs | |||
@@ -0,0 +1,80 @@ | |||
1 | //! A higher level attributes based on TokenTree, with also some shortcuts. | ||
2 | |||
3 | use std::sync::Arc; | ||
4 | |||
5 | use mbe::ast_to_token_tree; | ||
6 | use ra_cfg::CfgOptions; | ||
7 | use ra_syntax::{ | ||
8 | ast::{self, AstNode, AttrsOwner}, | ||
9 | SmolStr, | ||
10 | }; | ||
11 | use tt::Subtree; | ||
12 | |||
13 | use crate::{db::AstDatabase, path::Path, HirFileId, Source}; | ||
14 | |||
15 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
16 | pub(crate) struct Attr { | ||
17 | pub(crate) path: Path, | ||
18 | pub(crate) input: Option<AttrInput>, | ||
19 | } | ||
20 | |||
21 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
22 | pub enum AttrInput { | ||
23 | Literal(SmolStr), | ||
24 | TokenTree(Subtree), | ||
25 | } | ||
26 | |||
27 | impl Attr { | ||
28 | pub(crate) fn from_src( | ||
29 | Source { file_id, ast }: Source<ast::Attr>, | ||
30 | db: &impl AstDatabase, | ||
31 | ) -> Option<Attr> { | ||
32 | let path = Path::from_src(Source { file_id, ast: ast.path()? }, db)?; | ||
33 | let input = match ast.input() { | ||
34 | None => None, | ||
35 | Some(ast::AttrInput::Literal(lit)) => { | ||
36 | // FIXME: escape? raw string? | ||
37 | let value = lit.syntax().first_token()?.text().trim_matches('"').into(); | ||
38 | Some(AttrInput::Literal(value)) | ||
39 | } | ||
40 | Some(ast::AttrInput::TokenTree(tt)) => { | ||
41 | Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) | ||
42 | } | ||
43 | }; | ||
44 | |||
45 | Some(Attr { path, input }) | ||
46 | } | ||
47 | |||
48 | pub(crate) fn from_attrs_owner( | ||
49 | file_id: HirFileId, | ||
50 | owner: &dyn AttrsOwner, | ||
51 | db: &impl AstDatabase, | ||
52 | ) -> Option<Arc<[Attr]>> { | ||
53 | let mut attrs = owner.attrs().peekable(); | ||
54 | if attrs.peek().is_none() { | ||
55 | // Avoid heap allocation | ||
56 | return None; | ||
57 | } | ||
58 | Some(attrs.flat_map(|ast| Attr::from_src(Source { file_id, ast }, db)).collect()) | ||
59 | } | ||
60 | |||
61 | pub(crate) fn is_simple_atom(&self, name: &str) -> bool { | ||
62 | // FIXME: Avoid cloning | ||
63 | self.path.as_ident().map_or(false, |s| s.to_string() == name) | ||
64 | } | ||
65 | |||
66 | pub(crate) fn as_cfg(&self) -> Option<&Subtree> { | ||
67 | if self.is_simple_atom("cfg") { | ||
68 | match &self.input { | ||
69 | Some(AttrInput::TokenTree(subtree)) => Some(subtree), | ||
70 | _ => None, | ||
71 | } | ||
72 | } else { | ||
73 | None | ||
74 | } | ||
75 | } | ||
76 | |||
77 | pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Option<bool> { | ||
78 | cfg_options.is_cfg_enabled(self.as_cfg()?) | ||
79 | } | ||
80 | } | ||
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 20413cb3d..e3a7e8e3c 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | pub(crate) mod src; | 3 | pub(crate) mod src; |
2 | pub(crate) mod docs; | 4 | pub(crate) mod docs; |
3 | 5 | ||
@@ -339,10 +341,14 @@ pub struct Struct { | |||
339 | } | 341 | } |
340 | 342 | ||
341 | impl Struct { | 343 | impl Struct { |
342 | pub fn module(self, db: &impl HirDatabase) -> Module { | 344 | pub fn module(self, db: &impl DefDatabase) -> Module { |
343 | self.id.module(db) | 345 | self.id.module(db) |
344 | } | 346 | } |
345 | 347 | ||
348 | pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { | ||
349 | self.module(db).krate(db) | ||
350 | } | ||
351 | |||
346 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { | 352 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { |
347 | db.struct_data(self).name.clone() | 353 | db.struct_data(self).name.clone() |
348 | } | 354 | } |
@@ -423,10 +429,14 @@ pub struct Enum { | |||
423 | } | 429 | } |
424 | 430 | ||
425 | impl Enum { | 431 | impl Enum { |
426 | pub fn module(self, db: &impl HirDatabase) -> Module { | 432 | pub fn module(self, db: &impl DefDatabase) -> Module { |
427 | self.id.module(db) | 433 | self.id.module(db) |
428 | } | 434 | } |
429 | 435 | ||
436 | pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { | ||
437 | self.module(db).krate(db) | ||
438 | } | ||
439 | |||
430 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { | 440 | pub fn name(self, db: &impl DefDatabase) -> Option<Name> { |
431 | db.enum_data(self).name.clone() | 441 | db.enum_data(self).name.clone() |
432 | } | 442 | } |
@@ -514,7 +524,7 @@ impl Adt { | |||
514 | } | 524 | } |
515 | } | 525 | } |
516 | 526 | ||
517 | pub(crate) fn krate(self, db: &impl HirDatabase) -> Option<Crate> { | 527 | pub fn krate(self, db: &impl HirDatabase) -> Option<Crate> { |
518 | match self { | 528 | match self { |
519 | Adt::Struct(s) => s.module(db), | 529 | Adt::Struct(s) => s.module(db), |
520 | Adt::Union(s) => s.module(db), | 530 | Adt::Union(s) => s.module(db), |
diff --git a/crates/ra_hir/src/code_model/docs.rs b/crates/ra_hir/src/code_model/docs.rs index 99edc5814..9675e397f 100644 --- a/crates/ra_hir/src/code_model/docs.rs +++ b/crates/ra_hir/src/code_model/docs.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::sync::Arc; | 3 | use std::sync::Arc; |
2 | 4 | ||
3 | use ra_syntax::ast; | 5 | use ra_syntax::ast; |
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index c0cb27b47..fdae26906 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use ra_syntax::{ | 3 | use ra_syntax::{ |
2 | ast::{self, AstNode}, | 4 | ast::{self, AstNode}, |
3 | SyntaxNode, | 5 | SyntaxNode, |
@@ -119,7 +121,7 @@ impl HasSource for TypeAlias { | |||
119 | impl HasSource for MacroDef { | 121 | impl HasSource for MacroDef { |
120 | type Ast = ast::MacroCall; | 122 | type Ast = ast::MacroCall; |
121 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::MacroCall> { | 123 | fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<ast::MacroCall> { |
122 | Source { file_id: self.id.0.file_id(), ast: self.id.0.to_node(db) } | 124 | Source { file_id: self.id.ast_id.file_id(), ast: self.id.ast_id.to_node(db) } |
123 | } | 125 | } |
124 | } | 126 | } |
125 | 127 | ||
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index deed1c62f..73d7d6fb6 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::sync::Arc; | 3 | use std::sync::Arc; |
2 | 4 | ||
3 | use ra_db::{salsa, SourceDatabase}; | 5 | use ra_db::{salsa, SourceDatabase}; |
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 60da33695..9acdaf8ed 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{any::Any, fmt}; | 3 | use std::{any::Any, fmt}; |
2 | 4 | ||
3 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; | 5 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; |
diff --git a/crates/ra_hir/src/either.rs b/crates/ra_hir/src/either.rs index 439e6ec87..83583ef8b 100644 --- a/crates/ra_hir/src/either.rs +++ b/crates/ra_hir/src/either.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | 3 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
2 | pub enum Either<A, B> { | 4 | pub enum Either<A, B> { |
3 | A(A), | 5 | A(A), |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index b1bec2a68..d238741ba 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | pub(crate) mod lower; | 3 | pub(crate) mod lower; |
2 | pub(crate) mod scope; | 4 | pub(crate) mod scope; |
3 | pub(crate) mod validation; | 5 | pub(crate) mod validation; |
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs index 61535d24f..50ea429ea 100644 --- a/crates/ra_hir/src/expr/lower.rs +++ b/crates/ra_hir/src/expr/lower.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use ra_arena::Arena; | 3 | use ra_arena::Arena; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast::{ | 5 | ast::{ |
@@ -272,8 +274,11 @@ where | |||
272 | self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) | 274 | self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr) |
273 | } | 275 | } |
274 | ast::Expr::PathExpr(e) => { | 276 | ast::Expr::PathExpr(e) => { |
275 | let path = | 277 | let path = e |
276 | e.path().and_then(Path::from_ast).map(Expr::Path).unwrap_or(Expr::Missing); | 278 | .path() |
279 | .and_then(|path| self.parse_path(path)) | ||
280 | .map(Expr::Path) | ||
281 | .unwrap_or(Expr::Missing); | ||
277 | self.alloc_expr(path, syntax_ptr) | 282 | self.alloc_expr(path, syntax_ptr) |
278 | } | 283 | } |
279 | ast::Expr::ContinueExpr(_e) => { | 284 | ast::Expr::ContinueExpr(_e) => { |
@@ -295,7 +300,7 @@ where | |||
295 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) | 300 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) |
296 | } | 301 | } |
297 | ast::Expr::RecordLit(e) => { | 302 | ast::Expr::RecordLit(e) => { |
298 | let path = e.path().and_then(Path::from_ast); | 303 | let path = e.path().and_then(|path| self.parse_path(path)); |
299 | let mut field_ptrs = Vec::new(); | 304 | let mut field_ptrs = Vec::new(); |
300 | let record_lit = if let Some(nfl) = e.record_field_list() { | 305 | let record_lit = if let Some(nfl) = e.record_field_list() { |
301 | let fields = nfl | 306 | let fields = nfl |
@@ -459,7 +464,7 @@ where | |||
459 | .ast_id(&e) | 464 | .ast_id(&e) |
460 | .with_file_id(self.current_file_id); | 465 | .with_file_id(self.current_file_id); |
461 | 466 | ||
462 | if let Some(path) = e.path().and_then(Path::from_ast) { | 467 | if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { |
463 | if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { | 468 | if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { |
464 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db); | 469 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db); |
465 | let file_id = call_id.as_file(MacroFileKind::Expr); | 470 | let file_id = call_id.as_file(MacroFileKind::Expr); |
@@ -529,7 +534,7 @@ where | |||
529 | Pat::Bind { name, mode: annotation, subpat } | 534 | Pat::Bind { name, mode: annotation, subpat } |
530 | } | 535 | } |
531 | ast::Pat::TupleStructPat(p) => { | 536 | ast::Pat::TupleStructPat(p) => { |
532 | let path = p.path().and_then(Path::from_ast); | 537 | let path = p.path().and_then(|path| self.parse_path(path)); |
533 | let args = p.args().map(|p| self.collect_pat(p)).collect(); | 538 | let args = p.args().map(|p| self.collect_pat(p)).collect(); |
534 | Pat::TupleStruct { path, args } | 539 | Pat::TupleStruct { path, args } |
535 | } | 540 | } |
@@ -539,7 +544,7 @@ where | |||
539 | Pat::Ref { pat, mutability } | 544 | Pat::Ref { pat, mutability } |
540 | } | 545 | } |
541 | ast::Pat::PathPat(p) => { | 546 | ast::Pat::PathPat(p) => { |
542 | let path = p.path().and_then(Path::from_ast); | 547 | let path = p.path().and_then(|path| self.parse_path(path)); |
543 | path.map(Pat::Path).unwrap_or(Pat::Missing) | 548 | path.map(Pat::Path).unwrap_or(Pat::Missing) |
544 | } | 549 | } |
545 | ast::Pat::TuplePat(p) => { | 550 | ast::Pat::TuplePat(p) => { |
@@ -548,7 +553,7 @@ where | |||
548 | } | 553 | } |
549 | ast::Pat::PlaceholderPat(_) => Pat::Wild, | 554 | ast::Pat::PlaceholderPat(_) => Pat::Wild, |
550 | ast::Pat::RecordPat(p) => { | 555 | ast::Pat::RecordPat(p) => { |
551 | let path = p.path().and_then(Path::from_ast); | 556 | let path = p.path().and_then(|path| self.parse_path(path)); |
552 | let record_field_pat_list = | 557 | let record_field_pat_list = |
553 | p.record_field_pat_list().expect("every struct should have a field list"); | 558 | p.record_field_pat_list().expect("every struct should have a field list"); |
554 | let mut fields: Vec<_> = record_field_pat_list | 559 | let mut fields: Vec<_> = record_field_pat_list |
@@ -589,6 +594,10 @@ where | |||
589 | self.missing_pat() | 594 | self.missing_pat() |
590 | } | 595 | } |
591 | } | 596 | } |
597 | |||
598 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | ||
599 | Path::from_src(Source { ast: path, file_id: self.current_file_id }, self.db) | ||
600 | } | ||
592 | } | 601 | } |
593 | 602 | ||
594 | impl From<ast::BinOp> for BinaryOp { | 603 | impl From<ast::BinOp> for BinaryOp { |
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index de0983a7e..5496822e7 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::sync::Arc; | 3 | use std::sync::Arc; |
2 | 4 | ||
3 | use ra_arena::{impl_arena_id, Arena, RawId}; | 5 | use ra_arena::{impl_arena_id, Arena, RawId}; |
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index f06e5ec07..1aa853c3e 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::sync::Arc; | 3 | use std::sync::Arc; |
2 | 4 | ||
3 | use ra_syntax::ast; | 5 | use ra_syntax::ast; |
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 7b6d9b240..a012f33f7 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use ra_db::{FileId, FilePosition}; | 3 | use ra_db::{FileId, FilePosition}; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | algo::find_node_at_offset, | 5 | algo::find_node_at_offset, |
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 6865d34ba..4ce7551c3 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -132,6 +132,7 @@ impl GenericParams { | |||
132 | fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { | 132 | fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { |
133 | for (idx, type_param) in params.type_params().enumerate() { | 133 | for (idx, type_param) in params.type_params().enumerate() { |
134 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | 134 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); |
135 | // FIXME: Use `Path::from_src` | ||
135 | let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast); | 136 | let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast); |
136 | 137 | ||
137 | let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; | 138 | let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; |
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 9ea4e695d..a3b65cc79 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{ | 3 | use std::{ |
2 | hash::{Hash, Hasher}, | 4 | hash::{Hash, Hasher}, |
3 | sync::Arc, | 5 | sync::Arc, |
@@ -10,7 +12,7 @@ use ra_syntax::{ast, AstNode, Parse, SyntaxNode}; | |||
10 | 12 | ||
11 | use crate::{ | 13 | use crate::{ |
12 | db::{AstDatabase, DefDatabase, InternDatabase}, | 14 | db::{AstDatabase, DefDatabase, InternDatabase}, |
13 | AstId, FileAstId, Module, Source, | 15 | AstId, Crate, FileAstId, Module, Source, |
14 | }; | 16 | }; |
15 | 17 | ||
16 | /// hir makes heavy use of ids: integer (u32) handlers to various things. You | 18 | /// hir makes heavy use of ids: integer (u32) handlers to various things. You |
@@ -58,6 +60,17 @@ impl HirFileId { | |||
58 | } | 60 | } |
59 | } | 61 | } |
60 | 62 | ||
63 | /// Get the crate which the macro lives in, if it is a macro file. | ||
64 | pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> { | ||
65 | match self.0 { | ||
66 | HirFileIdRepr::File(_) => None, | ||
67 | HirFileIdRepr::Macro(macro_file) => { | ||
68 | let loc = macro_file.macro_call_id.loc(db); | ||
69 | Some(loc.def.krate) | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
61 | pub(crate) fn parse_or_expand_query( | 74 | pub(crate) fn parse_or_expand_query( |
62 | db: &impl AstDatabase, | 75 | db: &impl AstDatabase, |
63 | file_id: HirFileId, | 76 | file_id: HirFileId, |
@@ -121,10 +134,13 @@ impl From<FileId> for HirFileId { | |||
121 | } | 134 | } |
122 | 135 | ||
123 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 136 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
124 | pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>); | 137 | pub struct MacroDefId { |
138 | pub(crate) ast_id: AstId<ast::MacroCall>, | ||
139 | pub(crate) krate: Crate, | ||
140 | } | ||
125 | 141 | ||
126 | pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> { | 142 | pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> { |
127 | let macro_call = id.0.to_node(db); | 143 | let macro_call = id.ast_id.to_node(db); |
128 | let arg = macro_call.token_tree()?; | 144 | let arg = macro_call.token_tree()?; |
129 | let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { | 145 | let (tt, _) = mbe::ast_to_token_tree(&arg).or_else(|| { |
130 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | 146 | log::warn!("fail on macro_def to token tree: {:#?}", arg); |
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index d830202bd..55dfc393b 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs | |||
@@ -1,13 +1,17 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
2 | use std::sync::Arc; | 4 | use std::sync::Arc; |
3 | 5 | ||
4 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 6 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; |
7 | use ra_cfg::CfgOptions; | ||
5 | use ra_syntax::{ | 8 | use ra_syntax::{ |
6 | ast::{self, AstNode}, | 9 | ast::{self, AstNode}, |
7 | AstPtr, | 10 | AstPtr, |
8 | }; | 11 | }; |
9 | 12 | ||
10 | use crate::{ | 13 | use crate::{ |
14 | attr::Attr, | ||
11 | code_model::{Module, ModuleSource}, | 15 | code_model::{Module, ModuleSource}, |
12 | db::{AstDatabase, DefDatabase, HirDatabase}, | 16 | db::{AstDatabase, DefDatabase, HirDatabase}, |
13 | generics::HasGenericParams, | 17 | generics::HasGenericParams, |
@@ -174,6 +178,7 @@ pub struct ModuleImplBlocks { | |||
174 | impl ModuleImplBlocks { | 178 | impl ModuleImplBlocks { |
175 | fn collect( | 179 | fn collect( |
176 | db: &(impl DefDatabase + AstDatabase), | 180 | db: &(impl DefDatabase + AstDatabase), |
181 | cfg_options: &CfgOptions, | ||
177 | module: Module, | 182 | module: Module, |
178 | source_map: &mut ImplSourceMap, | 183 | source_map: &mut ImplSourceMap, |
179 | ) -> Self { | 184 | ) -> Self { |
@@ -186,11 +191,11 @@ impl ModuleImplBlocks { | |||
186 | let src = m.module.definition_source(db); | 191 | let src = m.module.definition_source(db); |
187 | match &src.ast { | 192 | match &src.ast { |
188 | ModuleSource::SourceFile(node) => { | 193 | ModuleSource::SourceFile(node) => { |
189 | m.collect_from_item_owner(db, source_map, node, src.file_id) | 194 | m.collect_from_item_owner(db, cfg_options, source_map, node, src.file_id) |
190 | } | 195 | } |
191 | ModuleSource::Module(node) => { | 196 | ModuleSource::Module(node) => { |
192 | let item_list = node.item_list().expect("inline module should have item list"); | 197 | let item_list = node.item_list().expect("inline module should have item list"); |
193 | m.collect_from_item_owner(db, source_map, &item_list, src.file_id) | 198 | m.collect_from_item_owner(db, cfg_options, source_map, &item_list, src.file_id) |
194 | } | 199 | } |
195 | }; | 200 | }; |
196 | m | 201 | m |
@@ -199,6 +204,7 @@ impl ModuleImplBlocks { | |||
199 | fn collect_from_item_owner( | 204 | fn collect_from_item_owner( |
200 | &mut self, | 205 | &mut self, |
201 | db: &(impl DefDatabase + AstDatabase), | 206 | db: &(impl DefDatabase + AstDatabase), |
207 | cfg_options: &CfgOptions, | ||
202 | source_map: &mut ImplSourceMap, | 208 | source_map: &mut ImplSourceMap, |
203 | owner: &dyn ast::ModuleItemOwner, | 209 | owner: &dyn ast::ModuleItemOwner, |
204 | file_id: HirFileId, | 210 | file_id: HirFileId, |
@@ -206,6 +212,13 @@ impl ModuleImplBlocks { | |||
206 | for item in owner.items_with_macros() { | 212 | for item in owner.items_with_macros() { |
207 | match item { | 213 | match item { |
208 | ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { | 214 | ast::ItemOrMacro::Item(ast::ModuleItem::ImplBlock(impl_block_ast)) => { |
215 | let attrs = Attr::from_attrs_owner(file_id, &impl_block_ast, db); | ||
216 | if attrs.map_or(false, |attrs| { | ||
217 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
218 | }) { | ||
219 | continue; | ||
220 | } | ||
221 | |||
209 | let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); | 222 | let impl_block = ImplData::from_ast(db, file_id, self.module, &impl_block_ast); |
210 | let id = self.impls.alloc(impl_block); | 223 | let id = self.impls.alloc(impl_block); |
211 | for &impl_item in &self.impls[id].items { | 224 | for &impl_item in &self.impls[id].items { |
@@ -216,9 +229,19 @@ impl ModuleImplBlocks { | |||
216 | } | 229 | } |
217 | ast::ItemOrMacro::Item(_) => (), | 230 | ast::ItemOrMacro::Item(_) => (), |
218 | ast::ItemOrMacro::Macro(macro_call) => { | 231 | ast::ItemOrMacro::Macro(macro_call) => { |
232 | let attrs = Attr::from_attrs_owner(file_id, ¯o_call, db); | ||
233 | if attrs.map_or(false, |attrs| { | ||
234 | attrs.iter().any(|attr| attr.is_cfg_enabled(cfg_options) == Some(false)) | ||
235 | }) { | ||
236 | continue; | ||
237 | } | ||
238 | |||
219 | //FIXME: we should really cut down on the boilerplate required to process a macro | 239 | //FIXME: we should really cut down on the boilerplate required to process a macro |
220 | let ast_id = db.ast_id_map(file_id).ast_id(¯o_call).with_file_id(file_id); | 240 | let ast_id = db.ast_id_map(file_id).ast_id(¯o_call).with_file_id(file_id); |
221 | if let Some(path) = macro_call.path().and_then(Path::from_ast) { | 241 | if let Some(path) = macro_call |
242 | .path() | ||
243 | .and_then(|path| Path::from_src(Source { ast: path, file_id }, db)) | ||
244 | { | ||
222 | if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) | 245 | if let Some(def) = self.module.resolver(db).resolve_path_as_macro(db, &path) |
223 | { | 246 | { |
224 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); | 247 | let call_id = MacroCallLoc { def: def.id, ast_id }.id(db); |
@@ -226,7 +249,13 @@ impl ModuleImplBlocks { | |||
226 | if let Some(item_list) = | 249 | if let Some(item_list) = |
227 | db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) | 250 | db.parse_or_expand(file_id).and_then(ast::MacroItems::cast) |
228 | { | 251 | { |
229 | self.collect_from_item_owner(db, source_map, &item_list, file_id) | 252 | self.collect_from_item_owner( |
253 | db, | ||
254 | cfg_options, | ||
255 | source_map, | ||
256 | &item_list, | ||
257 | file_id, | ||
258 | ) | ||
230 | } | 259 | } |
231 | } | 260 | } |
232 | } | 261 | } |
@@ -241,8 +270,10 @@ pub(crate) fn impls_in_module_with_source_map_query( | |||
241 | module: Module, | 270 | module: Module, |
242 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { | 271 | ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) { |
243 | let mut source_map = ImplSourceMap::default(); | 272 | let mut source_map = ImplSourceMap::default(); |
273 | let crate_graph = db.crate_graph(); | ||
274 | let cfg_options = crate_graph.cfg_options(module.krate.crate_id()); | ||
244 | 275 | ||
245 | let result = ModuleImplBlocks::collect(db, module, &mut source_map); | 276 | let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map); |
246 | (Arc::new(result), Arc::new(source_map)) | 277 | (Arc::new(result), Arc::new(source_map)) |
247 | } | 278 | } |
248 | 279 | ||
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs index bcce314d8..6c4e8ffbd 100644 --- a/crates/ra_hir/src/lang_item.rs +++ b/crates/ra_hir/src/lang_item.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
2 | use std::sync::Arc; | 4 | use std::sync::Arc; |
3 | 5 | ||
@@ -151,7 +153,7 @@ impl LangItems { | |||
151 | 153 | ||
152 | fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> { | 154 | fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> { |
153 | node.attrs() | 155 | node.attrs() |
154 | .filter_map(|a| a.as_key_value()) | 156 | .filter_map(|a| a.as_simple_key_value()) |
155 | .filter(|(key, _)| key == "lang") | 157 | .filter(|(key, _)| key == "lang") |
156 | .map(|(_, val)| val) | 158 | .map(|(_, val)| val) |
157 | .nth(0) | 159 | .nth(0) |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index a9de9fb6b..4340e9d34 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -1,5 +1,3 @@ | |||
1 | #![recursion_limit = "512"] | ||
2 | |||
3 | //! HIR (previously known as descriptors) provides a high-level object oriented | 1 | //! HIR (previously known as descriptors) provides a high-level object oriented |
4 | //! access to Rust code. | 2 | //! access to Rust code. |
5 | //! | 3 | //! |
@@ -7,6 +5,8 @@ | |||
7 | //! to a particular crate instance. That is, it has cfg flags and features | 5 | //! to a particular crate instance. That is, it has cfg flags and features |
8 | //! applied. So, the relation between syntax and HIR is many-to-one. | 6 | //! applied. So, the relation between syntax and HIR is many-to-one. |
9 | 7 | ||
8 | #![recursion_limit = "512"] | ||
9 | |||
10 | macro_rules! impl_froms { | 10 | macro_rules! impl_froms { |
11 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { | 11 | ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { |
12 | $( | 12 | $( |
@@ -44,6 +44,7 @@ mod traits; | |||
44 | mod type_alias; | 44 | mod type_alias; |
45 | mod type_ref; | 45 | mod type_ref; |
46 | mod ty; | 46 | mod ty; |
47 | mod attr; | ||
47 | mod impl_block; | 48 | mod impl_block; |
48 | mod expr; | 49 | mod expr; |
49 | mod lang_item; | 50 | mod lang_item; |
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index b2111be05..79af24b20 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! See test_utils/src/marks.rs | ||
2 | |||
1 | test_utils::marks!( | 3 | test_utils::marks!( |
2 | bogus_paths | 4 | bogus_paths |
3 | name_res_works_for_broken_modules | 5 | name_res_works_for_broken_modules |
@@ -9,9 +11,10 @@ test_utils::marks!( | |||
9 | glob_across_crates | 11 | glob_across_crates |
10 | std_prelude | 12 | std_prelude |
11 | match_ergonomics_ref | 13 | match_ergonomics_ref |
12 | trait_resolution_on_fn_type | ||
13 | infer_while_let | 14 | infer_while_let |
14 | macro_rules_from_other_crates_are_visible_with_macro_use | 15 | macro_rules_from_other_crates_are_visible_with_macro_use |
15 | prelude_is_macro_use | 16 | prelude_is_macro_use |
16 | coerce_merge_fail_fallback | 17 | coerce_merge_fail_fallback |
18 | macro_dollar_crate_self | ||
19 | macro_dollar_crate_other | ||
17 | ); | 20 | ); |
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index cb405091e..f750986b8 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{panic, sync::Arc}; | 3 | use std::{panic, sync::Arc}; |
2 | 4 | ||
3 | use parking_lot::Mutex; | 5 | use parking_lot::Mutex; |
6 | use ra_cfg::CfgOptions; | ||
4 | use ra_db::{ | 7 | use ra_db::{ |
5 | salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot, | 8 | salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot, |
6 | SourceRootId, | 9 | SourceRootId, |
@@ -72,13 +75,13 @@ impl MockDatabase { | |||
72 | pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { | 75 | pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { |
73 | let mut ids = FxHashMap::default(); | 76 | let mut ids = FxHashMap::default(); |
74 | let mut crate_graph = CrateGraph::default(); | 77 | let mut crate_graph = CrateGraph::default(); |
75 | for (crate_name, (crate_root, edition, _)) in graph.0.iter() { | 78 | for (crate_name, (crate_root, edition, cfg_options, _)) in graph.0.iter() { |
76 | let crate_root = self.file_id_of(&crate_root); | 79 | let crate_root = self.file_id_of(&crate_root); |
77 | let crate_id = crate_graph.add_crate_root(crate_root, *edition); | 80 | let crate_id = crate_graph.add_crate_root(crate_root, *edition, cfg_options.clone()); |
78 | Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone()); | 81 | Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone()); |
79 | ids.insert(crate_name, crate_id); | 82 | ids.insert(crate_name, crate_id); |
80 | } | 83 | } |
81 | for (crate_name, (_, _, deps)) in graph.0.iter() { | 84 | for (crate_name, (_, _, _, deps)) in graph.0.iter() { |
82 | let from = ids[crate_name]; | 85 | let from = ids[crate_name]; |
83 | for dep in deps { | 86 | for dep in deps { |
84 | let to = ids[dep]; | 87 | let to = ids[dep]; |
@@ -182,7 +185,7 @@ impl MockDatabase { | |||
182 | 185 | ||
183 | if is_crate_root { | 186 | if is_crate_root { |
184 | let mut crate_graph = CrateGraph::default(); | 187 | let mut crate_graph = CrateGraph::default(); |
185 | crate_graph.add_crate_root(file_id, Edition::Edition2018); | 188 | crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); |
186 | self.set_crate_graph(Arc::new(crate_graph)); | 189 | self.set_crate_graph(Arc::new(crate_graph)); |
187 | } | 190 | } |
188 | file_id | 191 | file_id |
@@ -266,19 +269,27 @@ impl MockDatabase { | |||
266 | } | 269 | } |
267 | 270 | ||
268 | #[derive(Default)] | 271 | #[derive(Default)] |
269 | pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, Vec<String>))>); | 272 | pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, CfgOptions, Vec<String>))>); |
270 | 273 | ||
271 | #[macro_export] | 274 | #[macro_export] |
272 | macro_rules! crate_graph { | 275 | macro_rules! crate_graph { |
273 | ($($crate_name:literal: ($crate_path:literal, $($edition:literal,)? [$($dep:literal),*]),)*) => {{ | 276 | ($( |
277 | $crate_name:literal: ( | ||
278 | $crate_path:literal, | ||
279 | $($edition:literal,)? | ||
280 | [$($dep:literal),*] | ||
281 | $(,$cfg:expr)? | ||
282 | ), | ||
283 | )*) => {{ | ||
274 | let mut res = $crate::mock::CrateGraphFixture::default(); | 284 | let mut res = $crate::mock::CrateGraphFixture::default(); |
275 | $( | 285 | $( |
276 | #[allow(unused_mut, unused_assignments)] | 286 | #[allow(unused_mut, unused_assignments)] |
277 | let mut edition = ra_db::Edition::Edition2018; | 287 | let mut edition = ra_db::Edition::Edition2018; |
278 | $(edition = ra_db::Edition::from_string($edition);)? | 288 | $(edition = ra_db::Edition::from_string($edition);)? |
289 | let cfg_options = { ::ra_cfg::CfgOptions::default() $(; $cfg)? }; | ||
279 | res.0.push(( | 290 | res.0.push(( |
280 | $crate_name.to_string(), | 291 | $crate_name.to_string(), |
281 | ($crate_path.to_string(), edition, vec![$($dep.to_string()),*]) | 292 | ($crate_path.to_string(), edition, cfg_options, vec![$($dep.to_string()),*]) |
282 | )); | 293 | )); |
283 | )* | 294 | )* |
284 | res | 295 | res |
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index 1bf993ffb..1e0b8c350 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::fmt; | 3 | use std::fmt; |
2 | 4 | ||
3 | use ra_syntax::{ast, SmolStr}; | 5 | use ra_syntax::{ast, SmolStr}; |
@@ -5,20 +7,21 @@ use ra_syntax::{ast, SmolStr}; | |||
5 | /// `Name` is a wrapper around string, which is used in hir for both references | 7 | /// `Name` is a wrapper around string, which is used in hir for both references |
6 | /// and declarations. In theory, names should also carry hygiene info, but we are | 8 | /// and declarations. In theory, names should also carry hygiene info, but we are |
7 | /// not there yet! | 9 | /// not there yet! |
8 | #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] | 10 | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
9 | pub struct Name { | 11 | pub struct Name(Repr); |
10 | text: SmolStr, | ||
11 | } | ||
12 | 12 | ||
13 | impl fmt::Display for Name { | 13 | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] |
14 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 14 | enum Repr { |
15 | fmt::Display::fmt(&self.text, f) | 15 | Text(SmolStr), |
16 | } | 16 | TupleField(usize), |
17 | } | 17 | } |
18 | 18 | ||
19 | impl fmt::Debug for Name { | 19 | impl fmt::Display for Name { |
20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
21 | fmt::Debug::fmt(&self.text, f) | 21 | match &self.0 { |
22 | Repr::Text(text) => fmt::Display::fmt(&text, f), | ||
23 | Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), | ||
24 | } | ||
22 | } | 25 | } |
23 | } | 26 | } |
24 | 27 | ||
@@ -26,29 +29,38 @@ impl Name { | |||
26 | /// Note: this is private to make creating name from random string hard. | 29 | /// Note: this is private to make creating name from random string hard. |
27 | /// Hopefully, this should allow us to integrate hygiene cleaner in the | 30 | /// Hopefully, this should allow us to integrate hygiene cleaner in the |
28 | /// future, and to switch to interned representation of names. | 31 | /// future, and to switch to interned representation of names. |
29 | const fn new(text: SmolStr) -> Name { | 32 | const fn new_text(text: SmolStr) -> Name { |
30 | Name { text } | 33 | Name(Repr::Text(text)) |
31 | } | 34 | } |
32 | 35 | ||
33 | pub(crate) fn missing() -> Name { | 36 | pub(crate) fn new_tuple_field(idx: usize) -> Name { |
34 | Name::new("[missing name]".into()) | 37 | Name(Repr::TupleField(idx)) |
38 | } | ||
39 | |||
40 | /// Shortcut to create inline plain text name | ||
41 | const fn new_inline_ascii(len: usize, text: &[u8]) -> Name { | ||
42 | Name::new_text(SmolStr::new_inline_from_ascii(len, text)) | ||
35 | } | 43 | } |
36 | 44 | ||
37 | pub(crate) fn tuple_field_name(idx: usize) -> Name { | 45 | /// Resolve a name from the text of token. |
38 | Name::new(idx.to_string().into()) | 46 | fn resolve(raw_text: &SmolStr) -> Name { |
47 | let raw_start = "r#"; | ||
48 | if raw_text.as_str().starts_with(raw_start) { | ||
49 | Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) | ||
50 | } else { | ||
51 | Name::new_text(raw_text.clone()) | ||
52 | } | ||
39 | } | 53 | } |
40 | 54 | ||
41 | // There's should be no way to extract a string out of `Name`: `Name` in the | 55 | pub(crate) fn missing() -> Name { |
42 | // future, `Name` will include hygiene information, and you can't encode | 56 | Name::new_text("[missing name]".into()) |
43 | // hygiene into a String. | 57 | } |
44 | // | 58 | |
45 | // If you need to compare something with `Name`, compare `Name`s directly. | 59 | pub(crate) fn as_tuple_index(&self) -> Option<usize> { |
46 | // | 60 | match self.0 { |
47 | // If you need to render `Name` for the user, use the `Display` impl, but be | 61 | Repr::TupleField(idx) => Some(idx), |
48 | // aware that it strips hygiene info. | 62 | _ => None, |
49 | #[deprecated(note = "use to_string instead")] | 63 | } |
50 | pub fn as_smolstr(&self) -> &SmolStr { | ||
51 | &self.text | ||
52 | } | 64 | } |
53 | } | 65 | } |
54 | 66 | ||
@@ -58,15 +70,16 @@ pub(crate) trait AsName { | |||
58 | 70 | ||
59 | impl AsName for ast::NameRef { | 71 | impl AsName for ast::NameRef { |
60 | fn as_name(&self) -> Name { | 72 | fn as_name(&self) -> Name { |
61 | let name = resolve_name(self.text()); | 73 | match self.as_tuple_field() { |
62 | Name::new(name) | 74 | Some(idx) => Name::new_tuple_field(idx), |
75 | None => Name::resolve(self.text()), | ||
76 | } | ||
63 | } | 77 | } |
64 | } | 78 | } |
65 | 79 | ||
66 | impl AsName for ast::Name { | 80 | impl AsName for ast::Name { |
67 | fn as_name(&self) -> Name { | 81 | fn as_name(&self) -> Name { |
68 | let name = resolve_name(self.text()); | 82 | Name::resolve(self.text()) |
69 | Name::new(name) | ||
70 | } | 83 | } |
71 | } | 84 | } |
72 | 85 | ||
@@ -74,66 +87,56 @@ impl AsName for ast::FieldKind { | |||
74 | fn as_name(&self) -> Name { | 87 | fn as_name(&self) -> Name { |
75 | match self { | 88 | match self { |
76 | ast::FieldKind::Name(nr) => nr.as_name(), | 89 | ast::FieldKind::Name(nr) => nr.as_name(), |
77 | ast::FieldKind::Index(idx) => Name::new(idx.text().clone()), | 90 | ast::FieldKind::Index(idx) => Name::new_tuple_field(idx.text().parse().unwrap()), |
78 | } | 91 | } |
79 | } | 92 | } |
80 | } | 93 | } |
81 | 94 | ||
82 | impl AsName for ra_db::Dependency { | 95 | impl AsName for ra_db::Dependency { |
83 | fn as_name(&self) -> Name { | 96 | fn as_name(&self) -> Name { |
84 | Name::new(self.name.clone()) | 97 | Name::new_text(self.name.clone()) |
85 | } | 98 | } |
86 | } | 99 | } |
87 | 100 | ||
88 | // Primitives | 101 | // Primitives |
89 | pub(crate) const ISIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"isize")); | 102 | pub(crate) const ISIZE: Name = Name::new_inline_ascii(5, b"isize"); |
90 | pub(crate) const I8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"i8")); | 103 | pub(crate) const I8: Name = Name::new_inline_ascii(2, b"i8"); |
91 | pub(crate) const I16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i16")); | 104 | pub(crate) const I16: Name = Name::new_inline_ascii(3, b"i16"); |
92 | pub(crate) const I32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i32")); | 105 | pub(crate) const I32: Name = Name::new_inline_ascii(3, b"i32"); |
93 | pub(crate) const I64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i64")); | 106 | pub(crate) const I64: Name = Name::new_inline_ascii(3, b"i64"); |
94 | pub(crate) const I128: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"i128")); | 107 | pub(crate) const I128: Name = Name::new_inline_ascii(4, b"i128"); |
95 | pub(crate) const USIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"usize")); | 108 | pub(crate) const USIZE: Name = Name::new_inline_ascii(5, b"usize"); |
96 | pub(crate) const U8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"u8")); | 109 | pub(crate) const U8: Name = Name::new_inline_ascii(2, b"u8"); |
97 | pub(crate) const U16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u16")); | 110 | pub(crate) const U16: Name = Name::new_inline_ascii(3, b"u16"); |
98 | pub(crate) const U32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u32")); | 111 | pub(crate) const U32: Name = Name::new_inline_ascii(3, b"u32"); |
99 | pub(crate) const U64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u64")); | 112 | pub(crate) const U64: Name = Name::new_inline_ascii(3, b"u64"); |
100 | pub(crate) const U128: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"u128")); | 113 | pub(crate) const U128: Name = Name::new_inline_ascii(4, b"u128"); |
101 | pub(crate) const F32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f32")); | 114 | pub(crate) const F32: Name = Name::new_inline_ascii(3, b"f32"); |
102 | pub(crate) const F64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f64")); | 115 | pub(crate) const F64: Name = Name::new_inline_ascii(3, b"f64"); |
103 | pub(crate) const BOOL: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"bool")); | 116 | pub(crate) const BOOL: Name = Name::new_inline_ascii(4, b"bool"); |
104 | pub(crate) const CHAR: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"char")); | 117 | pub(crate) const CHAR: Name = Name::new_inline_ascii(4, b"char"); |
105 | pub(crate) const STR: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"str")); | 118 | pub(crate) const STR: Name = Name::new_inline_ascii(3, b"str"); |
106 | 119 | ||
107 | // Special names | 120 | // Special names |
108 | pub(crate) const SELF_PARAM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"self")); | 121 | pub(crate) const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self"); |
109 | pub(crate) const SELF_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Self")); | 122 | pub(crate) const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self"); |
110 | pub(crate) const MACRO_RULES: Name = Name::new(SmolStr::new_inline_from_ascii(11, b"macro_rules")); | 123 | pub(crate) const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules"); |
111 | 124 | ||
112 | // Components of known path (value or mod name) | 125 | // Components of known path (value or mod name) |
113 | pub(crate) const STD: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"std")); | 126 | pub(crate) const STD: Name = Name::new_inline_ascii(3, b"std"); |
114 | pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter")); | 127 | pub(crate) const ITER: Name = Name::new_inline_ascii(4, b"iter"); |
115 | pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops")); | 128 | pub(crate) const OPS: Name = Name::new_inline_ascii(3, b"ops"); |
116 | pub(crate) const FUTURE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); | 129 | pub(crate) const FUTURE: Name = Name::new_inline_ascii(6, b"future"); |
117 | pub(crate) const RESULT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); | 130 | pub(crate) const RESULT: Name = Name::new_inline_ascii(6, b"result"); |
118 | pub(crate) const BOXED: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed")); | 131 | pub(crate) const BOXED: Name = Name::new_inline_ascii(5, b"boxed"); |
119 | 132 | ||
120 | // Components of known path (type name) | 133 | // Components of known path (type name) |
121 | pub(crate) const INTO_ITERATOR_TYPE: Name = | 134 | pub(crate) const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator"); |
122 | Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); | 135 | pub(crate) const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item"); |
123 | pub(crate) const ITEM_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); | 136 | pub(crate) const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try"); |
124 | pub(crate) const TRY_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")); | 137 | pub(crate) const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok"); |
125 | pub(crate) const OK_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); | 138 | pub(crate) const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future"); |
126 | pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); | 139 | pub(crate) const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); |
127 | pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); | 140 | pub(crate) const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); |
128 | pub(crate) const OUTPUT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); | 141 | pub(crate) const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); |
129 | pub(crate) const TARGET_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); | 142 | pub(crate) const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); |
130 | pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box")); | ||
131 | |||
132 | fn resolve_name(text: &SmolStr) -> SmolStr { | ||
133 | let raw_start = "r#"; | ||
134 | if text.as_str().starts_with(raw_start) { | ||
135 | SmolStr::new(&text[raw_start.len()..]) | ||
136 | } else { | ||
137 | text.clone() | ||
138 | } | ||
139 | } | ||
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index b808a0c36..67adcfa28 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -332,6 +332,20 @@ impl CrateDefMap { | |||
332 | ) -> ResolvePathResult { | 332 | ) -> ResolvePathResult { |
333 | let mut segments = path.segments.iter().enumerate(); | 333 | let mut segments = path.segments.iter().enumerate(); |
334 | let mut curr_per_ns: PerNs = match path.kind { | 334 | let mut curr_per_ns: PerNs = match path.kind { |
335 | PathKind::DollarCrate(krate) => { | ||
336 | if krate == self.krate { | ||
337 | tested_by!(macro_dollar_crate_self); | ||
338 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) | ||
339 | } else { | ||
340 | match krate.root_module(db) { | ||
341 | Some(module) => { | ||
342 | tested_by!(macro_dollar_crate_other); | ||
343 | PerNs::types(module.into()) | ||
344 | } | ||
345 | None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), | ||
346 | } | ||
347 | } | ||
348 | } | ||
335 | PathKind::Crate => { | 349 | PathKind::Crate => { |
336 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) | 350 | PerNs::types(Module { krate: self.krate, module_id: self.root }.into()) |
337 | } | 351 | } |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index ef7dc6ebe..cef2dc9d2 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -1,3 +1,6 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use ra_cfg::CfgOptions; | ||
1 | use ra_db::FileId; | 4 | use ra_db::FileId; |
2 | use ra_syntax::{ast, SmolStr}; | 5 | use ra_syntax::{ast, SmolStr}; |
3 | use rustc_hash::FxHashMap; | 6 | use rustc_hash::FxHashMap; |
@@ -33,6 +36,9 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
33 | } | 36 | } |
34 | } | 37 | } |
35 | 38 | ||
39 | let crate_graph = db.crate_graph(); | ||
40 | let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id()); | ||
41 | |||
36 | let mut collector = DefCollector { | 42 | let mut collector = DefCollector { |
37 | db, | 43 | db, |
38 | def_map, | 44 | def_map, |
@@ -40,6 +46,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C | |||
40 | unresolved_imports: Vec::new(), | 46 | unresolved_imports: Vec::new(), |
41 | unexpanded_macros: Vec::new(), | 47 | unexpanded_macros: Vec::new(), |
42 | macro_stack_monitor: MacroStackMonitor::default(), | 48 | macro_stack_monitor: MacroStackMonitor::default(), |
49 | cfg_options, | ||
43 | }; | 50 | }; |
44 | collector.collect(); | 51 | collector.collect(); |
45 | collector.finish() | 52 | collector.finish() |
@@ -74,8 +81,8 @@ impl MacroStackMonitor { | |||
74 | } | 81 | } |
75 | 82 | ||
76 | /// Walks the tree of module recursively | 83 | /// Walks the tree of module recursively |
77 | struct DefCollector<DB> { | 84 | struct DefCollector<'a, DB> { |
78 | db: DB, | 85 | db: &'a DB, |
79 | def_map: CrateDefMap, | 86 | def_map: CrateDefMap, |
80 | glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, | 87 | glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, |
81 | unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, | 88 | unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, |
@@ -84,9 +91,11 @@ struct DefCollector<DB> { | |||
84 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly | 91 | /// Some macro use `$tt:tt which mean we have to handle the macro perfectly |
85 | /// To prevent stack overflow, we add a deep counter here for prevent that. | 92 | /// To prevent stack overflow, we add a deep counter here for prevent that. |
86 | macro_stack_monitor: MacroStackMonitor, | 93 | macro_stack_monitor: MacroStackMonitor, |
94 | |||
95 | cfg_options: &'a CfgOptions, | ||
87 | } | 96 | } |
88 | 97 | ||
89 | impl<'a, DB> DefCollector<&'a DB> | 98 | impl<DB> DefCollector<'_, DB> |
90 | where | 99 | where |
91 | DB: DefDatabase, | 100 | DB: DefDatabase, |
92 | { | 101 | { |
@@ -504,7 +513,7 @@ struct ModCollector<'a, D> { | |||
504 | parent_module: Option<ParentModule<'a>>, | 513 | parent_module: Option<ParentModule<'a>>, |
505 | } | 514 | } |
506 | 515 | ||
507 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> | 516 | impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>> |
508 | where | 517 | where |
509 | DB: DefDatabase, | 518 | DB: DefDatabase, |
510 | { | 519 | { |
@@ -521,24 +530,27 @@ where | |||
521 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | 530 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting |
522 | // any other items. | 531 | // any other items. |
523 | for item in items { | 532 | for item in items { |
524 | if let raw::RawItem::Import(import_id) = *item { | 533 | if self.is_cfg_enabled(&item.attrs) { |
525 | let import = self.raw_items[import_id].clone(); | 534 | if let raw::RawItemKind::Import(import_id) = item.kind { |
526 | if import.is_extern_crate && import.is_macro_use { | 535 | let import = self.raw_items[import_id].clone(); |
527 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); | 536 | if import.is_extern_crate && import.is_macro_use { |
537 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); | ||
538 | } | ||
528 | } | 539 | } |
529 | } | 540 | } |
530 | } | 541 | } |
531 | 542 | ||
532 | for item in items { | 543 | for item in items { |
533 | match *item { | 544 | if self.is_cfg_enabled(&item.attrs) { |
534 | raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), | 545 | match item.kind { |
535 | raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push(( | 546 | raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]), |
536 | self.module_id, | 547 | raw::RawItemKind::Import(import_id) => self |
537 | import_id, | 548 | .def_collector |
538 | self.raw_items[import_id].clone(), | 549 | .unresolved_imports |
539 | )), | 550 | .push((self.module_id, import_id, self.raw_items[import_id].clone())), |
540 | raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), | 551 | raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), |
541 | raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), | 552 | raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), |
553 | } | ||
542 | } | 554 | } |
543 | } | 555 | } |
544 | } | 556 | } |
@@ -662,7 +674,10 @@ where | |||
662 | // Case 1: macro rules, define a macro in crate-global mutable scope | 674 | // Case 1: macro rules, define a macro in crate-global mutable scope |
663 | if is_macro_rules(&mac.path) { | 675 | if is_macro_rules(&mac.path) { |
664 | if let Some(name) = &mac.name { | 676 | if let Some(name) = &mac.name { |
665 | let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); | 677 | let macro_id = MacroDefId { |
678 | ast_id: mac.ast_id.with_file_id(self.file_id), | ||
679 | krate: self.def_collector.def_map.krate, | ||
680 | }; | ||
666 | let macro_ = MacroDef { id: macro_id }; | 681 | let macro_ = MacroDef { id: macro_id }; |
667 | self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); | 682 | self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); |
668 | } | 683 | } |
@@ -698,6 +713,14 @@ where | |||
698 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); | 713 | self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); |
699 | } | 714 | } |
700 | } | 715 | } |
716 | |||
717 | fn is_cfg_enabled(&self, attrs: &raw::Attrs) -> bool { | ||
718 | attrs.as_ref().map_or(true, |attrs| { | ||
719 | attrs | ||
720 | .iter() | ||
721 | .all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false)) | ||
722 | }) | ||
723 | } | ||
701 | } | 724 | } |
702 | 725 | ||
703 | fn is_macro_rules(path: &Path) -> bool { | 726 | fn is_macro_rules(path: &Path) -> bool { |
@@ -725,6 +748,7 @@ mod tests { | |||
725 | unresolved_imports: Vec::new(), | 748 | unresolved_imports: Vec::new(), |
726 | unexpanded_macros: Vec::new(), | 749 | unexpanded_macros: Vec::new(), |
727 | macro_stack_monitor: monitor, | 750 | macro_stack_monitor: monitor, |
751 | cfg_options: &CfgOptions::default(), | ||
728 | }; | 752 | }; |
729 | collector.collect(); | 753 | collector.collect(); |
730 | collector.finish() | 754 | collector.finish() |
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs index 964da2794..0da6789de 100644 --- a/crates/ra_hir/src/nameres/per_ns.rs +++ b/crates/ra_hir/src/nameres/per_ns.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use crate::{MacroDef, ModuleDef}; | 3 | use crate::{MacroDef, ModuleDef}; |
2 | 4 | ||
3 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | 5 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 29aaddbf1..623b343c4 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{ops::Index, sync::Arc}; | 3 | use std::{ops::Index, sync::Arc}; |
2 | 4 | ||
3 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; | 5 | use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; |
@@ -8,8 +10,9 @@ use ra_syntax::{ | |||
8 | use test_utils::tested_by; | 10 | use test_utils::tested_by; |
9 | 11 | ||
10 | use crate::{ | 12 | use crate::{ |
13 | attr::Attr, | ||
11 | db::{AstDatabase, DefDatabase}, | 14 | db::{AstDatabase, DefDatabase}, |
12 | AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, | 15 | AsName, AstIdMap, Either, FileAstId, HirFileId, ModuleSource, Name, Path, Source, |
13 | }; | 16 | }; |
14 | 17 | ||
15 | /// `RawItems` is a set of top-level items in a file (except for impls). | 18 | /// `RawItems` is a set of top-level items in a file (except for impls). |
@@ -71,6 +74,8 @@ impl RawItems { | |||
71 | raw_items: RawItems::default(), | 74 | raw_items: RawItems::default(), |
72 | source_ast_id_map: db.ast_id_map(file_id), | 75 | source_ast_id_map: db.ast_id_map(file_id), |
73 | source_map: ImportSourceMap::default(), | 76 | source_map: ImportSourceMap::default(), |
77 | file_id, | ||
78 | db, | ||
74 | }; | 79 | }; |
75 | if let Some(node) = db.parse_or_expand(file_id) { | 80 | if let Some(node) = db.parse_or_expand(file_id) { |
76 | if let Some(source_file) = ast::SourceFile::cast(node.clone()) { | 81 | if let Some(source_file) = ast::SourceFile::cast(node.clone()) { |
@@ -115,8 +120,17 @@ impl Index<Macro> for RawItems { | |||
115 | } | 120 | } |
116 | } | 121 | } |
117 | 122 | ||
123 | // Avoid heap allocation on items without attributes. | ||
124 | pub(super) type Attrs = Option<Arc<[Attr]>>; | ||
125 | |||
126 | #[derive(Debug, PartialEq, Eq, Clone)] | ||
127 | pub(super) struct RawItem { | ||
128 | pub(super) attrs: Attrs, | ||
129 | pub(super) kind: RawItemKind, | ||
130 | } | ||
131 | |||
118 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 132 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
119 | pub(super) enum RawItem { | 133 | pub(super) enum RawItemKind { |
120 | Module(Module), | 134 | Module(Module), |
121 | Import(ImportId), | 135 | Import(ImportId), |
122 | Def(Def), | 136 | Def(Def), |
@@ -192,13 +206,15 @@ pub(super) struct MacroData { | |||
192 | pub(super) export: bool, | 206 | pub(super) export: bool, |
193 | } | 207 | } |
194 | 208 | ||
195 | struct RawItemsCollector { | 209 | struct RawItemsCollector<DB> { |
196 | raw_items: RawItems, | 210 | raw_items: RawItems, |
197 | source_ast_id_map: Arc<AstIdMap>, | 211 | source_ast_id_map: Arc<AstIdMap>, |
198 | source_map: ImportSourceMap, | 212 | source_map: ImportSourceMap, |
213 | file_id: HirFileId, | ||
214 | db: DB, | ||
199 | } | 215 | } |
200 | 216 | ||
201 | impl RawItemsCollector { | 217 | impl<DB: AstDatabase> RawItemsCollector<&DB> { |
202 | fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) { | 218 | fn process_module(&mut self, current_module: Option<Module>, body: impl ast::ModuleItemOwner) { |
203 | for item_or_macro in body.items_with_macros() { | 219 | for item_or_macro in body.items_with_macros() { |
204 | match item_or_macro { | 220 | match item_or_macro { |
@@ -209,6 +225,7 @@ impl RawItemsCollector { | |||
209 | } | 225 | } |
210 | 226 | ||
211 | fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) { | 227 | fn add_item(&mut self, current_module: Option<Module>, item: ast::ModuleItem) { |
228 | let attrs = self.parse_attrs(&item); | ||
212 | let (kind, name) = match item { | 229 | let (kind, name) = match item { |
213 | ast::ModuleItem::Module(module) => { | 230 | ast::ModuleItem::Module(module) => { |
214 | self.add_module(current_module, module); | 231 | self.add_module(current_module, module); |
@@ -257,7 +274,7 @@ impl RawItemsCollector { | |||
257 | if let Some(name) = name { | 274 | if let Some(name) = name { |
258 | let name = name.as_name(); | 275 | let name = name.as_name(); |
259 | let def = self.raw_items.defs.alloc(DefData { name, kind }); | 276 | let def = self.raw_items.defs.alloc(DefData { name, kind }); |
260 | self.push_item(current_module, RawItem::Def(def)) | 277 | self.push_item(current_module, attrs, RawItemKind::Def(def)); |
261 | } | 278 | } |
262 | } | 279 | } |
263 | 280 | ||
@@ -266,8 +283,10 @@ impl RawItemsCollector { | |||
266 | Some(it) => it.as_name(), | 283 | Some(it) => it.as_name(), |
267 | None => return, | 284 | None => return, |
268 | }; | 285 | }; |
286 | let attrs = self.parse_attrs(&module); | ||
269 | 287 | ||
270 | let ast_id = self.source_ast_id_map.ast_id(&module); | 288 | let ast_id = self.source_ast_id_map.ast_id(&module); |
289 | // FIXME: cfg_attr | ||
271 | let is_macro_use = module.has_atom_attr("macro_use"); | 290 | let is_macro_use = module.has_atom_attr("macro_use"); |
272 | if module.has_semi() { | 291 | if module.has_semi() { |
273 | let attr_path = extract_mod_path_attribute(&module); | 292 | let attr_path = extract_mod_path_attribute(&module); |
@@ -277,7 +296,7 @@ impl RawItemsCollector { | |||
277 | attr_path, | 296 | attr_path, |
278 | is_macro_use, | 297 | is_macro_use, |
279 | }); | 298 | }); |
280 | self.push_item(current_module, RawItem::Module(item)); | 299 | self.push_item(current_module, attrs, RawItemKind::Module(item)); |
281 | return; | 300 | return; |
282 | } | 301 | } |
283 | 302 | ||
@@ -291,26 +310,37 @@ impl RawItemsCollector { | |||
291 | is_macro_use, | 310 | is_macro_use, |
292 | }); | 311 | }); |
293 | self.process_module(Some(item), item_list); | 312 | self.process_module(Some(item), item_list); |
294 | self.push_item(current_module, RawItem::Module(item)); | 313 | self.push_item(current_module, attrs, RawItemKind::Module(item)); |
295 | return; | 314 | return; |
296 | } | 315 | } |
297 | tested_by!(name_res_works_for_broken_modules); | 316 | tested_by!(name_res_works_for_broken_modules); |
298 | } | 317 | } |
299 | 318 | ||
300 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { | 319 | fn add_use_item(&mut self, current_module: Option<Module>, use_item: ast::UseItem) { |
320 | // FIXME: cfg_attr | ||
301 | let is_prelude = use_item.has_atom_attr("prelude_import"); | 321 | let is_prelude = use_item.has_atom_attr("prelude_import"); |
302 | 322 | let attrs = self.parse_attrs(&use_item); | |
303 | Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { | 323 | |
304 | let import_data = ImportData { | 324 | Path::expand_use_item( |
305 | path, | 325 | Source { ast: use_item, file_id: self.file_id }, |
306 | alias, | 326 | self.db, |
307 | is_glob, | 327 | |path, use_tree, is_glob, alias| { |
308 | is_prelude, | 328 | let import_data = ImportData { |
309 | is_extern_crate: false, | 329 | path, |
310 | is_macro_use: false, | 330 | alias, |
311 | }; | 331 | is_glob, |
312 | self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); | 332 | is_prelude, |
313 | }) | 333 | is_extern_crate: false, |
334 | is_macro_use: false, | ||
335 | }; | ||
336 | self.push_import( | ||
337 | current_module, | ||
338 | attrs.clone(), | ||
339 | import_data, | ||
340 | Either::A(AstPtr::new(use_tree)), | ||
341 | ); | ||
342 | }, | ||
343 | ) | ||
314 | } | 344 | } |
315 | 345 | ||
316 | fn add_extern_crate_item( | 346 | fn add_extern_crate_item( |
@@ -321,6 +351,8 @@ impl RawItemsCollector { | |||
321 | if let Some(name_ref) = extern_crate.name_ref() { | 351 | if let Some(name_ref) = extern_crate.name_ref() { |
322 | let path = Path::from_name_ref(&name_ref); | 352 | let path = Path::from_name_ref(&name_ref); |
323 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); | 353 | let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); |
354 | let attrs = self.parse_attrs(&extern_crate); | ||
355 | // FIXME: cfg_attr | ||
324 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | 356 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); |
325 | let import_data = ImportData { | 357 | let import_data = ImportData { |
326 | path, | 358 | path, |
@@ -330,37 +362,47 @@ impl RawItemsCollector { | |||
330 | is_extern_crate: true, | 362 | is_extern_crate: true, |
331 | is_macro_use, | 363 | is_macro_use, |
332 | }; | 364 | }; |
333 | self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); | 365 | self.push_import( |
366 | current_module, | ||
367 | attrs, | ||
368 | import_data, | ||
369 | Either::B(AstPtr::new(&extern_crate)), | ||
370 | ); | ||
334 | } | 371 | } |
335 | } | 372 | } |
336 | 373 | ||
337 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { | 374 | fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { |
338 | let path = match m.path().and_then(Path::from_ast) { | 375 | let attrs = self.parse_attrs(&m); |
376 | let path = match m | ||
377 | .path() | ||
378 | .and_then(|path| Path::from_src(Source { ast: path, file_id: self.file_id }, self.db)) | ||
379 | { | ||
339 | Some(it) => it, | 380 | Some(it) => it, |
340 | _ => return, | 381 | _ => return, |
341 | }; | 382 | }; |
342 | 383 | ||
343 | let name = m.name().map(|it| it.as_name()); | 384 | let name = m.name().map(|it| it.as_name()); |
344 | let ast_id = self.source_ast_id_map.ast_id(&m); | 385 | let ast_id = self.source_ast_id_map.ast_id(&m); |
345 | let export = m.has_atom_attr("macro_export") | 386 | // FIXME: cfg_attr |
346 | || m.attrs().filter_map(|x| x.as_call()).any(|(name, _)| name == "macro_export"); | 387 | let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export"); |
347 | 388 | ||
348 | let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); | 389 | let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export }); |
349 | self.push_item(current_module, RawItem::Macro(m)); | 390 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); |
350 | } | 391 | } |
351 | 392 | ||
352 | fn push_import( | 393 | fn push_import( |
353 | &mut self, | 394 | &mut self, |
354 | current_module: Option<Module>, | 395 | current_module: Option<Module>, |
396 | attrs: Attrs, | ||
355 | data: ImportData, | 397 | data: ImportData, |
356 | source: ImportSourcePtr, | 398 | source: ImportSourcePtr, |
357 | ) { | 399 | ) { |
358 | let import = self.raw_items.imports.alloc(data); | 400 | let import = self.raw_items.imports.alloc(data); |
359 | self.source_map.insert(import, source); | 401 | self.source_map.insert(import, source); |
360 | self.push_item(current_module, RawItem::Import(import)) | 402 | self.push_item(current_module, attrs, RawItemKind::Import(import)) |
361 | } | 403 | } |
362 | 404 | ||
363 | fn push_item(&mut self, current_module: Option<Module>, item: RawItem) { | 405 | fn push_item(&mut self, current_module: Option<Module>, attrs: Attrs, kind: RawItemKind) { |
364 | match current_module { | 406 | match current_module { |
365 | Some(module) => match &mut self.raw_items.modules[module] { | 407 | Some(module) => match &mut self.raw_items.modules[module] { |
366 | ModuleData::Definition { items, .. } => items, | 408 | ModuleData::Definition { items, .. } => items, |
@@ -368,13 +410,17 @@ impl RawItemsCollector { | |||
368 | }, | 410 | }, |
369 | None => &mut self.raw_items.items, | 411 | None => &mut self.raw_items.items, |
370 | } | 412 | } |
371 | .push(item) | 413 | .push(RawItem { attrs, kind }) |
414 | } | ||
415 | |||
416 | fn parse_attrs(&self, item: &impl ast::AttrsOwner) -> Attrs { | ||
417 | Attr::from_attrs_owner(self.file_id, item, self.db) | ||
372 | } | 418 | } |
373 | } | 419 | } |
374 | 420 | ||
375 | fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> { | 421 | fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> { |
376 | module.attrs().into_iter().find_map(|attr| { | 422 | module.attrs().into_iter().find_map(|attr| { |
377 | attr.as_key_value().and_then(|(name, value)| { | 423 | attr.as_simple_key_value().and_then(|(name, value)| { |
378 | let is_path = name == "path"; | 424 | let is_path = name == "path"; |
379 | if is_path { | 425 | if is_path { |
380 | Some(value) | 426 | Some(value) |
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index bc4b47b70..34dd79574 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs | |||
@@ -7,6 +7,7 @@ mod mod_resolution; | |||
7 | use std::sync::Arc; | 7 | use std::sync::Arc; |
8 | 8 | ||
9 | use insta::assert_snapshot; | 9 | use insta::assert_snapshot; |
10 | use ra_cfg::CfgOptions; | ||
10 | use ra_db::SourceDatabase; | 11 | use ra_db::SourceDatabase; |
11 | use test_utils::covers; | 12 | use test_utils::covers; |
12 | 13 | ||
@@ -507,3 +508,72 @@ fn values_dont_shadow_extern_crates() { | |||
507 | ⋮foo: v | 508 | ⋮foo: v |
508 | "###); | 509 | "###); |
509 | } | 510 | } |
511 | |||
512 | #[test] | ||
513 | fn cfg_not_test() { | ||
514 | let map = def_map_with_crate_graph( | ||
515 | r#" | ||
516 | //- /main.rs | ||
517 | use {Foo, Bar, Baz}; | ||
518 | //- /lib.rs | ||
519 | #[prelude_import] | ||
520 | pub use self::prelude::*; | ||
521 | mod prelude { | ||
522 | #[cfg(test)] | ||
523 | pub struct Foo; | ||
524 | #[cfg(not(test))] | ||
525 | pub struct Bar; | ||
526 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] | ||
527 | pub struct Baz; | ||
528 | } | ||
529 | "#, | ||
530 | crate_graph! { | ||
531 | "main": ("/main.rs", ["std"]), | ||
532 | "std": ("/lib.rs", []), | ||
533 | }, | ||
534 | ); | ||
535 | |||
536 | assert_snapshot!(map, @r###" | ||
537 | ⋮crate | ||
538 | ⋮Bar: t v | ||
539 | ⋮Baz: _ | ||
540 | ⋮Foo: _ | ||
541 | "###); | ||
542 | } | ||
543 | |||
544 | #[test] | ||
545 | fn cfg_test() { | ||
546 | let map = def_map_with_crate_graph( | ||
547 | r#" | ||
548 | //- /main.rs | ||
549 | use {Foo, Bar, Baz}; | ||
550 | //- /lib.rs | ||
551 | #[prelude_import] | ||
552 | pub use self::prelude::*; | ||
553 | mod prelude { | ||
554 | #[cfg(test)] | ||
555 | pub struct Foo; | ||
556 | #[cfg(not(test))] | ||
557 | pub struct Bar; | ||
558 | #[cfg(all(not(any()), feature = "foo", feature = "bar", opt = "42"))] | ||
559 | pub struct Baz; | ||
560 | } | ||
561 | "#, | ||
562 | crate_graph! { | ||
563 | "main": ("/main.rs", ["std"]), | ||
564 | "std": ("/lib.rs", [], CfgOptions::default() | ||
565 | .atom("test".into()) | ||
566 | .key_value("feature".into(), "foo".into()) | ||
567 | .key_value("feature".into(), "bar".into()) | ||
568 | .key_value("opt".into(), "42".into()) | ||
569 | ), | ||
570 | }, | ||
571 | ); | ||
572 | |||
573 | assert_snapshot!(map, @r###" | ||
574 | ⋮crate | ||
575 | ⋮Bar: _ | ||
576 | ⋮Baz: t v | ||
577 | ⋮Foo: t v | ||
578 | "###); | ||
579 | } | ||
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index bd60f4258..e4b408394 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs | |||
@@ -515,3 +515,108 @@ fn path_qualified_macros() { | |||
515 | ⋮not_found: _ | 515 | ⋮not_found: _ |
516 | "###); | 516 | "###); |
517 | } | 517 | } |
518 | |||
519 | #[test] | ||
520 | fn macro_dollar_crate_is_correct_in_item() { | ||
521 | covers!(macro_dollar_crate_self); | ||
522 | covers!(macro_dollar_crate_other); | ||
523 | let map = def_map_with_crate_graph( | ||
524 | " | ||
525 | //- /main.rs | ||
526 | #[macro_use] | ||
527 | extern crate foo; | ||
528 | |||
529 | #[macro_use] | ||
530 | mod m { | ||
531 | macro_rules! current { | ||
532 | () => { | ||
533 | use $crate::Foo as FooSelf; | ||
534 | } | ||
535 | } | ||
536 | } | ||
537 | |||
538 | struct Foo; | ||
539 | |||
540 | current!(); | ||
541 | not_current1!(); | ||
542 | foo::not_current2!(); | ||
543 | |||
544 | //- /lib.rs | ||
545 | mod m { | ||
546 | #[macro_export] | ||
547 | macro_rules! not_current1 { | ||
548 | () => { | ||
549 | use $crate::Bar; | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | |||
554 | #[macro_export] | ||
555 | macro_rules! not_current2 { | ||
556 | () => { | ||
557 | use $crate::Baz; | ||
558 | } | ||
559 | } | ||
560 | |||
561 | struct Bar; | ||
562 | struct Baz; | ||
563 | ", | ||
564 | crate_graph! { | ||
565 | "main": ("/main.rs", ["foo"]), | ||
566 | "foo": ("/lib.rs", []), | ||
567 | }, | ||
568 | ); | ||
569 | assert_snapshot!(map, @r###" | ||
570 | ⋮crate | ||
571 | ⋮Bar: t v | ||
572 | ⋮Baz: t v | ||
573 | ⋮Foo: t v | ||
574 | ⋮FooSelf: t v | ||
575 | ⋮foo: t | ||
576 | ⋮m: t | ||
577 | ⋮ | ||
578 | ⋮crate::m | ||
579 | "###); | ||
580 | } | ||
581 | |||
582 | #[test] | ||
583 | fn macro_dollar_crate_is_correct_in_indirect_deps() { | ||
584 | covers!(macro_dollar_crate_other); | ||
585 | // From std | ||
586 | let map = def_map_with_crate_graph( | ||
587 | r#" | ||
588 | //- /main.rs | ||
589 | foo!(); | ||
590 | |||
591 | //- /std.rs | ||
592 | #[prelude_import] | ||
593 | use self::prelude::*; | ||
594 | |||
595 | pub use core::foo; | ||
596 | |||
597 | mod prelude {} | ||
598 | |||
599 | #[macro_use] | ||
600 | mod std_macros; | ||
601 | |||
602 | //- /core.rs | ||
603 | #[macro_export] | ||
604 | macro_rules! foo { | ||
605 | () => { | ||
606 | use $crate::bar; | ||
607 | } | ||
608 | } | ||
609 | |||
610 | pub struct bar; | ||
611 | "#, | ||
612 | crate_graph! { | ||
613 | "main": ("/main.rs", ["std"]), | ||
614 | "std": ("/std.rs", ["core"]), | ||
615 | "core": ("/core.rs", []), | ||
616 | }, | ||
617 | ); | ||
618 | assert_snapshot!(map, @r###" | ||
619 | ⋮crate | ||
620 | ⋮bar: t v | ||
621 | "###); | ||
622 | } | ||
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 39d1b7e46..394617e1a 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
1 | use std::{iter, sync::Arc}; | 3 | use std::{iter, sync::Arc}; |
2 | 4 | ||
3 | use ra_syntax::{ | 5 | use ra_syntax::{ |
@@ -5,7 +7,7 @@ use ra_syntax::{ | |||
5 | AstNode, | 7 | AstNode, |
6 | }; | 8 | }; |
7 | 9 | ||
8 | use crate::{name, type_ref::TypeRef, AsName, Name}; | 10 | use crate::{db::AstDatabase, name, type_ref::TypeRef, AsName, Crate, Name, Source}; |
9 | 11 | ||
10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 12 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
11 | pub struct Path { | 13 | pub struct Path { |
@@ -52,16 +54,19 @@ pub enum PathKind { | |||
52 | Abs, | 54 | Abs, |
53 | // Type based path like `<T>::foo` | 55 | // Type based path like `<T>::foo` |
54 | Type(Box<TypeRef>), | 56 | Type(Box<TypeRef>), |
57 | // `$crate` from macro expansion | ||
58 | DollarCrate(Crate), | ||
55 | } | 59 | } |
56 | 60 | ||
57 | impl Path { | 61 | impl Path { |
58 | /// Calls `cb` with all paths, represented by this use item. | 62 | /// Calls `cb` with all paths, represented by this use item. |
59 | pub fn expand_use_item( | 63 | pub fn expand_use_item( |
60 | item: &ast::UseItem, | 64 | item_src: Source<ast::UseItem>, |
65 | db: &impl AstDatabase, | ||
61 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), | 66 | mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>), |
62 | ) { | 67 | ) { |
63 | if let Some(tree) = item.use_tree() { | 68 | if let Some |