aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/assist_ctx.rs8
-rw-r--r--crates/ra_assists/src/assists/add_derive.rs4
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs2
-rw-r--r--crates/ra_assists/src/assists/add_impl.rs2
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs46
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs102
-rw-r--r--crates/ra_assists/src/assists/auto_import.rs5
-rw-r--r--crates/ra_assists/src/assists/change_visibility.rs2
-rw-r--r--crates/ra_assists/src/assists/fill_match_arms.rs2
-rw-r--r--crates/ra_assists/src/assists/flip_binexpr.rs2
-rw-r--r--crates/ra_assists/src/assists/flip_comma.rs2
-rw-r--r--crates/ra_assists/src/assists/inline_local_variable.rs2
-rw-r--r--crates/ra_assists/src/assists/introduce_variable.rs2
-rw-r--r--crates/ra_assists/src/assists/merge_match_arms.rs2
-rw-r--r--crates/ra_assists/src/assists/move_bounds.rs14
-rw-r--r--crates/ra_assists/src/assists/move_guard.rs2
-rw-r--r--crates/ra_assists/src/assists/raw_string.rs2
-rw-r--r--crates/ra_assists/src/assists/remove_dbg.rs2
-rw-r--r--crates/ra_assists/src/assists/replace_if_let_with_match.rs2
-rw-r--r--crates/ra_assists/src/assists/split_import.rs8
-rw-r--r--crates/ra_assists/src/ast_editor.rs315
-rw-r--r--crates/ra_assists/src/lib.rs3
-rw-r--r--crates/ra_assists/src/marks.rs2
-rw-r--r--crates/ra_batch/src/lib.rs20
-rw-r--r--crates/ra_cfg/Cargo.toml14
-rw-r--r--crates/ra_cfg/src/cfg_expr.rs132
-rw-r--r--crates/ra_cfg/src/lib.rs61
-rw-r--r--crates/ra_cli/Cargo.toml2
-rw-r--r--crates/ra_cli/src/analysis_bench.rs2
-rw-r--r--crates/ra_cli/src/analysis_stats.rs2
-rw-r--r--crates/ra_cli/src/help.rs2
-rw-r--r--crates/ra_cli/src/main.rs10
-rw-r--r--crates/ra_db/Cargo.toml1
-rw-r--r--crates/ra_db/src/input.rs48
-rw-r--r--crates/ra_db/src/lib.rs5
-rw-r--r--crates/ra_hir/Cargo.toml1
-rw-r--r--crates/ra_hir/src/adt.rs2
-rw-r--r--crates/ra_hir/src/attr.rs80
-rw-r--r--crates/ra_hir/src/code_model.rs16
-rw-r--r--crates/ra_hir/src/code_model/docs.rs2
-rw-r--r--crates/ra_hir/src/code_model/src.rs4
-rw-r--r--crates/ra_hir/src/db.rs2
-rw-r--r--crates/ra_hir/src/diagnostics.rs2
-rw-r--r--crates/ra_hir/src/either.rs2
-rw-r--r--crates/ra_hir/src/expr.rs2
-rw-r--r--crates/ra_hir/src/expr/lower.rs23
-rw-r--r--crates/ra_hir/src/expr/scope.rs2
-rw-r--r--crates/ra_hir/src/expr/validation.rs2
-rw-r--r--crates/ra_hir/src/from_source.rs2
-rw-r--r--crates/ra_hir/src/generics.rs1
-rw-r--r--crates/ra_hir/src/ids.rs22
-rw-r--r--crates/ra_hir/src/impl_block.rs41
-rw-r--r--crates/ra_hir/src/lang_item.rs4
-rw-r--r--crates/ra_hir/src/lib.rs5
-rw-r--r--crates/ra_hir/src/marks.rs5
-rw-r--r--crates/ra_hir/src/mock.rs25
-rw-r--r--crates/ra_hir/src/name.rs159
-rw-r--r--crates/ra_hir/src/nameres.rs14
-rw-r--r--crates/ra_hir/src/nameres/collector.rs60
-rw-r--r--crates/ra_hir/src/nameres/per_ns.rs2
-rw-r--r--crates/ra_hir/src/nameres/raw.rs102
-rw-r--r--crates/ra_hir/src/nameres/tests.rs70
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs105
-rw-r--r--crates/ra_hir/src/path.rs66
-rw-r--r--crates/ra_hir/src/source_binder.rs16
-rw-r--r--crates/ra_hir/src/source_id.rs2
-rw-r--r--crates/ra_hir/src/ty.rs141
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs14
-rw-r--r--crates/ra_hir/src/ty/display.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs36
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs10
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs24
-rw-r--r--crates/ra_hir/src/ty/lower.rs20
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs18
-rw-r--r--crates/ra_hir/src/ty/op.rs2
-rw-r--r--crates/ra_hir/src/ty/primitive.rs2
-rw-r--r--crates/ra_hir/src/ty/tests.rs142
-rw-r--r--crates/ra_hir/src/ty/traits.rs12
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs80
-rw-r--r--crates/ra_hir/src/type_ref.rs2
-rw-r--r--crates/ra_ide_api/Cargo.toml1
-rw-r--r--crates/ra_ide_api/src/assists.rs2
-rw-r--r--crates/ra_ide_api/src/call_info.rs2
-rw-r--r--crates/ra_ide_api/src/change.rs2
-rw-r--r--crates/ra_ide_api/src/completion.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs18
-rw-r--r--crates/ra_ide_api/src/completion/complete_keyword.rs20
-rw-r--r--crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_pattern.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_literal.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_record_pattern.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_snippet.rs2
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs2
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs2
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs1
-rw-r--r--crates/ra_ide_api/src/db.rs2
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs12
-rw-r--r--crates/ra_ide_api/src/display/function_signature.rs2
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs61
-rw-r--r--crates/ra_ide_api/src/display/short_label.rs2
-rw-r--r--crates/ra_ide_api/src/display/structure.rs120
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs2
-rw-r--r--crates/ra_ide_api/src/feature_flags.rs2
-rw-r--r--crates/ra_ide_api/src/folding_ranges.rs2
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs187
-rw-r--r--crates/ra_ide_api/src/goto_type_definition.rs2
-rw-r--r--crates/ra_ide_api/src/hover.rs79
-rw-r--r--crates/ra_ide_api/src/impls.rs2
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs106
-rw-r--r--crates/ra_ide_api/src/join_lines.rs2
-rw-r--r--crates/ra_ide_api/src/lib.rs6
-rw-r--r--crates/ra_ide_api/src/line_index.rs3
-rw-r--r--crates/ra_ide_api/src/line_index_utils.rs2
-rw-r--r--crates/ra_ide_api/src/marks.rs2
-rw-r--r--crates/ra_ide_api/src/matching_brace.rs2
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs8
-rw-r--r--crates/ra_ide_api/src/name_ref_kind.rs2
-rw-r--r--crates/ra_ide_api/src/parent_module.rs5
-rw-r--r--crates/ra_ide_api/src/references.rs2
-rw-r--r--crates/ra_ide_api/src/runnables.rs3
-rw-r--r--crates/ra_ide_api/src/snapshots/highlighting.html2
-rw-r--r--crates/ra_ide_api/src/status.rs2
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs26
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs2
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs2
-rw-r--r--crates/ra_ide_api/src/test_utils.rs2
-rw-r--r--crates/ra_ide_api/src/typing.rs2
-rw-r--r--crates/ra_ide_api/src/wasm_shims.rs2
-rw-r--r--crates/ra_lsp_server/Cargo.toml1
-rw-r--r--crates/ra_lsp_server/src/caps.rs2
-rw-r--r--crates/ra_lsp_server/src/cargo_target_spec.rs2
-rw-r--r--crates/ra_lsp_server/src/config.rs2
-rw-r--r--crates/ra_lsp_server/src/conv.rs2
-rw-r--r--crates/ra_lsp_server/src/lib.rs2
-rw-r--r--crates/ra_lsp_server/src/main.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/pending_requests.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/subscriptions.rs2
-rw-r--r--crates/ra_lsp_server/src/markdown.rs3
-rw-r--r--crates/ra_lsp_server/src/req.rs2
-rw-r--r--crates/ra_lsp_server/src/world.rs10
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs8
-rw-r--r--crates/ra_mbe/src/lib.rs8
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs2
-rw-r--r--crates/ra_mbe/src/mbe_expander/transcriber.rs2
-rw-r--r--crates/ra_mbe/src/subtree_source.rs2
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs2
-rw-r--r--crates/ra_mbe/src/tt_iter.rs2
-rw-r--r--crates/ra_parser/src/grammar.rs1
-rw-r--r--crates/ra_parser/src/grammar/attributes.rs21
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs38
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs12
-rw-r--r--crates/ra_parser/src/grammar/items.rs2
-rw-r--r--crates/ra_parser/src/grammar/items/consts.rs2
-rw-r--r--crates/ra_parser/src/grammar/items/nominal.rs2
-rw-r--r--crates/ra_parser/src/grammar/items/traits.rs2
-rw-r--r--crates/ra_parser/src/grammar/items/use_item.rs2
-rw-r--r--crates/ra_parser/src/grammar/params.rs2
-rw-r--r--crates/ra_parser/src/grammar/paths.rs2
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs2
-rw-r--r--crates/ra_parser/src/grammar/type_args.rs2
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs2
-rw-r--r--crates/ra_parser/src/grammar/types.rs2
-rw-r--r--crates/ra_parser/src/parser.rs2
-rw-r--r--crates/ra_parser/src/syntax_kind.rs2
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs2
-rw-r--r--crates/ra_parser/src/token_set.rs2
-rw-r--r--crates/ra_prof/src/lib.rs2
-rw-r--r--crates/ra_prof/src/memory_usage.rs2
-rw-r--r--crates/ra_project_model/Cargo.toml1
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs8
-rw-r--r--crates/ra_project_model/src/json_project.rs5
-rw-r--r--crates/ra_project_model/src/lib.rs57
-rw-r--r--crates/ra_project_model/src/sysroot.rs2
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/fuzz/fuzz_targets/parser.rs2
-rw-r--r--crates/ra_syntax/fuzz/fuzz_targets/reparse.rs2
-rw-r--r--crates/ra_syntax/src/algo.rs19
-rw-r--r--crates/ra_syntax/src/algo/visit.rs110
-rw-r--r--crates/ra_syntax/src/ast.rs1
-rw-r--r--crates/ra_syntax/src/ast/edit.rs271
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs93
-rw-r--r--crates/ra_syntax/src/ast/generated.rs46
-rw-r--r--crates/ra_syntax/src/ast/make.rs48
-rw-r--r--crates/ra_syntax/src/ast/traits.rs2
-rw-r--r--crates/ra_syntax/src/fuzz.rs2
-rw-r--r--crates/ra_syntax/src/grammar.ron8
-rw-r--r--crates/ra_syntax/src/lib.rs31
-rw-r--r--crates/ra_syntax/src/parsing/lexer.rs2
-rw-r--r--crates/ra_syntax/src/parsing/text_token_source.rs2
-rw-r--r--crates/ra_syntax/src/parsing/text_tree_sink.rs2
-rw-r--r--crates/ra_syntax/src/ptr.rs2
-rw-r--r--crates/ra_syntax/src/syntax_error.rs2
-rw-r--r--crates/ra_syntax/src/validation.rs20
-rw-r--r--crates/ra_syntax/src/validation/block.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0005_attribute_recover.txt68
-rw-r--r--crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt10
-rw-r--r--crates/ra_syntax/test_data/parser/err/0031_block_inner_attrs.txt72
-rw-r--r--crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.txt18
-rw-r--r--crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.txt18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.txt20
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0031_while_expr.txt34
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0054_record_field_attrs.txt26
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0064_if_expr.txt43
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0071_match_expr.txt65
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.rs6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0080_postfix_range.txt107
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0115_tuple_field_attrs.txt26
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0118_impl_inner_attributes.txt18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0120_match_arms_inner_attribute.txt54
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0121_match_arms_outer_attributes.txt130
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0122_generic_lifetime_type_attribute.txt36
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0125_record_literal_field_with_attr.txt18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0126_attr_on_expr_stmt.txt50
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0127_attr_on_last_expr_in_block.txt20
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0135_first_array_member_attributes.txt18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0136_subsequent_array_member_attributes.txt18
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.txt10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.txt10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt43
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0006_inner_attributes.txt268
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0008_mod_item.txt10
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0011_outer_attribute.txt53
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0017_attr_trailing_comma.txt20
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.txt89
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0044_let_attrs.txt26
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0045_block_inner_attrs.txt90
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0046_extern_inner_attributes.txt18
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt150
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0053_outer_attribute_on_macro_rules.txt10
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs7
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt97
-rw-r--r--crates/ra_text_edit/src/lib.rs2
-rw-r--r--crates/ra_text_edit/src/test_utils.rs2
-rw-r--r--crates/ra_text_edit/src/text_edit.rs2
-rw-r--r--crates/ra_tools/Cargo.toml2
-rw-r--r--crates/ra_tools/src/bin/pre-commit.rs2
-rw-r--r--crates/ra_tools/src/boilerplate_gen.rs4
-rw-r--r--crates/ra_tools/src/help.rs2
-rw-r--r--crates/ra_tools/src/lib.rs2
-rw-r--r--crates/ra_tools/src/main.rs2
-rw-r--r--crates/ra_tools/tests/cli.rs5
-rw-r--r--crates/ra_tools/tests/docs.rs63
-rw-r--r--crates/ra_tools/tests/main.rs2
-rw-r--r--crates/ra_tt/src/buffer.rs2
-rw-r--r--crates/ra_tt/src/lib.rs6
-rw-r--r--crates/test_utils/src/lib.rs2
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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_db::FileRange; 4use ra_db::FileRange;
3use ra_fmt::{leading_indent, reindent}; 5use ra_fmt::{leading_indent, reindent};
4use ra_syntax::{ 6use 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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::{ 4use 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
1use hir::{db::HirDatabase, HirDisplay, Ty}; 3use hir::{db::HirDatabase, HirDisplay, Ty};
2use ra_syntax::{ 4use 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
1use format_buf::format; 3use format_buf::format;
2use hir::db::HirDatabase; 4use hir::db::HirDatabase;
3use join_to_string::join; 5use 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
1use hir::{db::HirDatabase, HasSource}; 3use hir::{db::HirDatabase, HasSource};
2use ra_syntax::{ 4use ra_syntax::{
3 ast::{self, make, AstNode, NameOwner}, 5 ast::{self, edit, make, AstNode, NameOwner},
4 SmolStr, 6 SmolStr,
5}; 7};
6 8
7use crate::{ast_editor::AstEditor, Assist, AssistCtx, AssistId}; 9use crate::{Assist, AssistCtx, AssistId};
8 10
9#[derive(PartialEq)] 11#[derive(PartialEq)]
10enum AddMissingImplMembersMode { 12enum 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
96fn 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
102fn add_body(fn_def: ast::FnDef) -> ast::FnDef { 100fn 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)`.
4use hir::db::HirDatabase;
5use ra_syntax::ast::{self, AstNode};
6use ra_syntax::SyntaxNode;
7
8use 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`.
16pub(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
42fn 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
51fn 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)]
73mod 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
1use hir::{self, db::HirDatabase}; 3use hir::{self, db::HirDatabase};
2use ra_text_edit::TextEditBuilder; 4use 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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::{ 4use 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
1use std::iter; 3use std::iter;
2 4
3use hir::{db::HirDatabase, Adt, HasSource}; 5use 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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::ast::{AstNode, BinExpr, BinOp}; 4use 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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::{algo::non_trivia_sibling, Direction, T}; 4use 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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::{ 4use 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
1use format_buf::format; 3use format_buf::format;
2use hir::db::HirDatabase; 4use hir::db::HirDatabase;
3use ra_syntax::{ 5use 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
1use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit}; 3use crate::{Assist, AssistCtx, AssistId, TextRange, TextUnit};
2use hir::db::HirDatabase; 4use hir::db::HirDatabase;
3use ra_syntax::ast::{AstNode, MatchArm}; 5use 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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::{ 4use 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
8use crate::{ast_editor::AstEditor, Assist, AssistCtx, AssistId}; 10use crate::{Assist, AssistCtx, AssistId};
9 11
10pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 12pub(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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::{ 4use 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
1use hir::db::HirDatabase; 3use hir::db::HirDatabase;
2use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; 4use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
3use rustc_lexer; 5use 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
1use crate::{Assist, AssistCtx, AssistId}; 3use crate::{Assist, AssistCtx, AssistId};
2use hir::db::HirDatabase; 4use hir::db::HirDatabase;
3use ra_syntax::{ 5use 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
1use format_buf::format; 3use format_buf::format;
2use hir::db::HirDatabase; 4use hir::db::HirDatabase;
3use ra_fmt::extract_trivial_expression; 5use 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
1use std::iter::successors; 3use std::iter::successors;
2 4
3use hir::db::HirDatabase; 5use 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 @@
1use std::{iter, ops::RangeInclusive};
2
3use arrayvec::ArrayVec;
4use rustc_hash::FxHashMap;
5
6use ra_fmt::leading_indent;
7use ra_syntax::{
8 algo,
9 ast::{self, TypeBoundsOwner},
10 AstNode, Direction, InsertPosition, SyntaxElement,
11 SyntaxKind::*,
12 T,
13};
14use ra_text_edit::TextEditBuilder;
15
16pub struct AstEditor<N: AstNode> {
17 original_ast: N,
18 ast: N,
19}
20
21impl<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
104impl 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
182impl 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
215impl 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
232impl 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
252impl 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
267mod 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
8mod assist_ctx; 8mod assist_ctx;
9mod marks; 9mod marks;
10pub mod ast_editor;
11 10
12use hir::db::HirDatabase; 11use hir::db::HirDatabase;
13use itertools::Itertools; 12use 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
1test_utils::marks!( 3test_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
1use std::{collections::HashSet, error::Error, path::Path}; 3use std::{collections::HashSet, error::Error, path::Path};
2 4
3use rustc_hash::FxHashMap; 5use rustc_hash::FxHashMap;
@@ -5,7 +7,7 @@ use rustc_hash::FxHashMap;
5use crossbeam_channel::{unbounded, Receiver}; 7use crossbeam_channel::{unbounded, Receiver};
6use ra_db::{CrateGraph, FileId, SourceRootId}; 8use ra_db::{CrateGraph, FileId, SourceRootId};
7use ra_ide_api::{AnalysisChange, AnalysisHost, FeatureFlags}; 9use ra_ide_api::{AnalysisChange, AnalysisHost, FeatureFlags};
8use ra_project_model::{PackageRoot, ProjectWorkspace}; 10use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace};
9use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; 11use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
10use ra_vfs_glob::RustPackageFilterBuilder; 12use 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]
2edition = "2018"
3name = "ra_cfg"
4version = "0.1.0"
5authors = ["rust-analyzer developers"]
6
7[dependencies]
8rustc-hash = "1.0.1"
9
10ra_syntax = { path = "../ra_syntax" }
11tt = { path = "../ra_tt", package = "ra_tt" }
12
13[dev-dependencies]
14mbe = { 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
5use std::slice::Iter as SliceIter;
6
7use ra_syntax::SmolStr;
8use tt::{Leaf, Subtree, TokenTree};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub 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
20impl 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
38pub fn parse_cfg(tt: &Subtree) -> CfgExpr {
39 next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
40}
41
42fn 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)]
88mod 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
2use std::iter::IntoIterator;
3
4use ra_syntax::SmolStr;
5use rustc_hash::FxHashSet;
6
7mod cfg_expr;
8
9pub 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)]
22pub struct CfgOptions {
23 atoms: FxHashSet<SmolStr>,
24 key_values: FxHashSet<(SmolStr, SmolStr)>,
25}
26
27impl 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"]
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
9pico-args = "0.2.0" 9pico-args = "0.3.0"
10flexi_logger = "0.14.0" 10flexi_logger = "0.14.0"
11indicatif = "0.11.0" 11indicatif = "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
1use std::{ 3use 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
1use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; 3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
2 4
3use ra_db::SourceDatabase; 5use 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
1pub const GLOBAL_HELP: &str = "ra-cli 3pub const GLOBAL_HELP: &str = "ra-cli
2 4
3USAGE: 5USAGE:
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
1mod analysis_stats; 3mod analysis_stats;
2mod analysis_bench; 4mod analysis_bench;
3mod help; 5mod 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"
10rustc-hash = "1.0" 10rustc-hash = "1.0"
11 11
12ra_syntax = { path = "../ra_syntax" } 12ra_syntax = { path = "../ra_syntax" }
13ra_cfg = { path = "../ra_cfg" }
13ra_prof = { path = "../ra_prof" } 14ra_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
8use relative_path::{RelativePath, RelativePathBuf}; 9use relative_path::{RelativePath, RelativePathBuf};
9use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
10 11
12use ra_cfg::CfgOptions;
11use ra_syntax::SmolStr; 13use ra_syntax::SmolStr;
12use rustc_hash::FxHashSet; 14use 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
113impl CrateData { 116impl 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
135impl CrateGraph { 138impl 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)]
222mod tests { 234mod 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
16ra_syntax = { path = "../ra_syntax" } 16ra_syntax = { path = "../ra_syntax" }
17ra_arena = { path = "../ra_arena" } 17ra_arena = { path = "../ra_arena" }
18ra_cfg = { path = "../ra_cfg" }
18ra_db = { path = "../ra_db" } 19ra_db = { path = "../ra_db" }
19mbe = { path = "../ra_mbe", package = "ra_mbe" } 20mbe = { path = "../ra_mbe", package = "ra_mbe" }
20tt = { path = "../ra_tt", package = "ra_tt" } 21tt = { 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
3use std::sync::Arc;
4
5use mbe::ast_to_token_tree;
6use ra_cfg::CfgOptions;
7use ra_syntax::{
8 ast::{self, AstNode, AttrsOwner},
9 SmolStr,
10};
11use tt::Subtree;
12
13use crate::{db::AstDatabase, path::Path, HirFileId, Source};
14
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub(crate) struct Attr {
17 pub(crate) path: Path,
18 pub(crate) input: Option<AttrInput>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum AttrInput {
23 Literal(SmolStr),
24 TokenTree(Subtree),
25}
26
27impl 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
1pub(crate) mod src; 3pub(crate) mod src;
2pub(crate) mod docs; 4pub(crate) mod docs;
3 5
@@ -339,10 +341,14 @@ pub struct Struct {
339} 341}
340 342
341impl Struct { 343impl 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
425impl Enum { 431impl 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
1use std::sync::Arc; 3use std::sync::Arc;
2 4
3use ra_syntax::ast; 5use 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
1use ra_syntax::{ 3use ra_syntax::{
2 ast::{self, AstNode}, 4 ast::{self, AstNode},
3 SyntaxNode, 5 SyntaxNode,
@@ -119,7 +121,7 @@ impl HasSource for TypeAlias {
119impl HasSource for MacroDef { 121impl 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
1use std::sync::Arc; 3use std::sync::Arc;
2 4
3use ra_db::{salsa, SourceDatabase}; 5use 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
1use std::{any::Any, fmt}; 3use std::{any::Any, fmt};
2 4
3use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; 5use 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)]
2pub enum Either<A, B> { 4pub 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
1pub(crate) mod lower; 3pub(crate) mod lower;
2pub(crate) mod scope; 4pub(crate) mod scope;
3pub(crate) mod validation; 5pub(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
1use ra_arena::Arena; 3use ra_arena::Arena;
2use ra_syntax::{ 4use 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
594impl From<ast::BinOp> for BinaryOp { 603impl 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
1use std::sync::Arc; 3use std::sync::Arc;
2 4
3use ra_arena::{impl_arena_id, Arena, RawId}; 5use 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
1use std::sync::Arc; 3use std::sync::Arc;
2 4
3use ra_syntax::ast; 5use 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
1use ra_db::{FileId, FilePosition}; 3use ra_db::{FileId, FilePosition};
2use ra_syntax::{ 4use 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
1use std::{ 3use 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
11use crate::{ 13use 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)]
124pub struct MacroDefId(pub(crate) AstId<ast::MacroCall>); 137pub struct MacroDefId {
138 pub(crate) ast_id: AstId<ast::MacroCall>,
139 pub(crate) krate: Crate,
140}
125 141
126pub(crate) fn macro_def_query(db: &impl AstDatabase, id: MacroDefId) -> Option<Arc<MacroRules>> { 142pub(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
1use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
2use std::sync::Arc; 4use std::sync::Arc;
3 5
4use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 6use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
7use ra_cfg::CfgOptions;
5use ra_syntax::{ 8use ra_syntax::{
6 ast::{self, AstNode}, 9 ast::{self, AstNode},
7 AstPtr, 10 AstPtr,
8}; 11};
9 12
10use crate::{ 13use 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 {
174impl ModuleImplBlocks { 178impl 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, &macro_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(&macro_call).with_file_id(file_id); 240 let ast_id = db.ast_id_map(file_id).ast_id(&macro_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
1use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
2use std::sync::Arc; 4use std::sync::Arc;
3 5
@@ -151,7 +153,7 @@ impl LangItems {
151 153
152fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> { 154fn 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
10macro_rules! impl_froms { 10macro_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;
44mod type_alias; 44mod type_alias;
45mod type_ref; 45mod type_ref;
46mod ty; 46mod ty;
47mod attr;
47mod impl_block; 48mod impl_block;
48mod expr; 49mod expr;
49mod lang_item; 50mod 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
1test_utils::marks!( 3test_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
1use std::{panic, sync::Arc}; 3use std::{panic, sync::Arc};
2 4
3use parking_lot::Mutex; 5use parking_lot::Mutex;
6use ra_cfg::CfgOptions;
4use ra_db::{ 7use 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)]
269pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, Vec<String>))>); 272pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, CfgOptions, Vec<String>))>);
270 273
271#[macro_export] 274#[macro_export]
272macro_rules! crate_graph { 275macro_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
1use std::fmt; 3use std::fmt;
2 4
3use ra_syntax::{ast, SmolStr}; 5use 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)]
9pub struct Name { 11pub struct Name(Repr);
10 text: SmolStr,
11}
12 12
13impl fmt::Display for Name { 13#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 14enum Repr {
15 fmt::Display::fmt(&self.text, f) 15 Text(SmolStr),
16 } 16 TupleField(usize),
17} 17}
18 18
19impl fmt::Debug for Name { 19impl 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
59impl AsName for ast::NameRef { 71impl 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
66impl AsName for ast::Name { 80impl 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
82impl AsName for ra_db::Dependency { 95impl 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
89pub(crate) const ISIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"isize")); 102pub(crate) const ISIZE: Name = Name::new_inline_ascii(5, b"isize");
90pub(crate) const I8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"i8")); 103pub(crate) const I8: Name = Name::new_inline_ascii(2, b"i8");
91pub(crate) const I16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i16")); 104pub(crate) const I16: Name = Name::new_inline_ascii(3, b"i16");
92pub(crate) const I32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i32")); 105pub(crate) const I32: Name = Name::new_inline_ascii(3, b"i32");
93pub(crate) const I64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"i64")); 106pub(crate) const I64: Name = Name::new_inline_ascii(3, b"i64");
94pub(crate) const I128: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"i128")); 107pub(crate) const I128: Name = Name::new_inline_ascii(4, b"i128");
95pub(crate) const USIZE: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"usize")); 108pub(crate) const USIZE: Name = Name::new_inline_ascii(5, b"usize");
96pub(crate) const U8: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"u8")); 109pub(crate) const U8: Name = Name::new_inline_ascii(2, b"u8");
97pub(crate) const U16: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u16")); 110pub(crate) const U16: Name = Name::new_inline_ascii(3, b"u16");
98pub(crate) const U32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u32")); 111pub(crate) const U32: Name = Name::new_inline_ascii(3, b"u32");
99pub(crate) const U64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"u64")); 112pub(crate) const U64: Name = Name::new_inline_ascii(3, b"u64");
100pub(crate) const U128: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"u128")); 113pub(crate) const U128: Name = Name::new_inline_ascii(4, b"u128");
101pub(crate) const F32: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f32")); 114pub(crate) const F32: Name = Name::new_inline_ascii(3, b"f32");
102pub(crate) const F64: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"f64")); 115pub(crate) const F64: Name = Name::new_inline_ascii(3, b"f64");
103pub(crate) const BOOL: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"bool")); 116pub(crate) const BOOL: Name = Name::new_inline_ascii(4, b"bool");
104pub(crate) const CHAR: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"char")); 117pub(crate) const CHAR: Name = Name::new_inline_ascii(4, b"char");
105pub(crate) const STR: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"str")); 118pub(crate) const STR: Name = Name::new_inline_ascii(3, b"str");
106 119
107// Special names 120// Special names
108pub(crate) const SELF_PARAM: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"self")); 121pub(crate) const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self");
109pub(crate) const SELF_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Self")); 122pub(crate) const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self");
110pub(crate) const MACRO_RULES: Name = Name::new(SmolStr::new_inline_from_ascii(11, b"macro_rules")); 123pub(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)
113pub(crate) const STD: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"std")); 126pub(crate) const STD: Name = Name::new_inline_ascii(3, b"std");
114pub(crate) const ITER: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"iter")); 127pub(crate) const ITER: Name = Name::new_inline_ascii(4, b"iter");
115pub(crate) const OPS: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"ops")); 128pub(crate) const OPS: Name = Name::new_inline_ascii(3, b"ops");
116pub(crate) const FUTURE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"future")); 129pub(crate) const FUTURE: Name = Name::new_inline_ascii(6, b"future");
117pub(crate) const RESULT: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"result")); 130pub(crate) const RESULT: Name = Name::new_inline_ascii(6, b"result");
118pub(crate) const BOXED: Name = Name::new(SmolStr::new_inline_from_ascii(5, b"boxed")); 131pub(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)
121pub(crate) const INTO_ITERATOR_TYPE: Name = 134pub(crate) const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator");
122 Name::new(SmolStr::new_inline_from_ascii(12, b"IntoIterator")); 135pub(crate) const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item");
123pub(crate) const ITEM_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(4, b"Item")); 136pub(crate) const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try");
124pub(crate) const TRY_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Try")); 137pub(crate) const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok");
125pub(crate) const OK_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(2, b"Ok")); 138pub(crate) const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future");
126pub(crate) const FUTURE_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Future")); 139pub(crate) const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result");
127pub(crate) const RESULT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Result")); 140pub(crate) const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output");
128pub(crate) const OUTPUT_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Output")); 141pub(crate) const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target");
129pub(crate) const TARGET_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(6, b"Target")); 142pub(crate) const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box");
130pub(crate) const BOX_TYPE: Name = Name::new(SmolStr::new_inline_from_ascii(3, b"Box"));
131
132fn 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
3use ra_cfg::CfgOptions;
1use ra_db::FileId; 4use ra_db::FileId;
2use ra_syntax::{ast, SmolStr}; 5use ra_syntax::{ast, SmolStr};
3use rustc_hash::FxHashMap; 6use 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
77struct DefCollector<DB> { 84struct 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
89impl<'a, DB> DefCollector<&'a DB> 98impl<DB> DefCollector<'_, DB>
90where 99where
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
507impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> 516impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
508where 517where
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
703fn is_macro_rules(path: &Path) -> bool { 726fn 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
1use crate::{MacroDef, ModuleDef}; 3use 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
1use std::{ops::Index, sync::Arc}; 3use std::{ops::Index, sync::Arc};
2 4
3use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 5use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
@@ -8,8 +10,9 @@ use ra_syntax::{
8use test_utils::tested_by; 10use test_utils::tested_by;
9 11
10use crate::{ 12use 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.
124pub(super) type Attrs = Option<Arc<[Attr]>>;
125
126#[derive(Debug, PartialEq, Eq, Clone)]
127pub(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)]
119pub(super) enum RawItem { 133pub(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
195struct RawItemsCollector { 209struct 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
201impl RawItemsCollector { 217impl<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
375fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> { 421fn 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;
7use std::sync::Arc; 7use std::sync::Arc;
8 8
9use insta::assert_snapshot; 9use insta::assert_snapshot;
10use ra_cfg::CfgOptions;
10use ra_db::SourceDatabase; 11use ra_db::SourceDatabase;
11use test_utils::covers; 12use 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]
513fn 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]
545fn 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]
520fn 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]
583fn 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
1use std::{iter, sync::Arc}; 3use std::{iter, sync::Arc};
2 4
3use ra_syntax::{ 5use ra_syntax::{
@@ -5,7 +7,7 @@ use ra_syntax::{
5 AstNode, 7 AstNode,
6}; 8};
7 9
8use crate::{name, type_ref::TypeRef, AsName, Name}; 10use 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)]
11pub struct Path { 13pub 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
57impl Path { 61impl 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