aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock16
-rw-r--r--crates/ra_assists/src/add_derive.rs6
-rw-r--r--crates/ra_assists/src/add_impl.rs8
-rw-r--r--crates/ra_assists/src/add_missing_impl_members.rs15
-rw-r--r--crates/ra_assists/src/assist_ctx.rs16
-rw-r--r--crates/ra_assists/src/auto_import.rs13
-rw-r--r--crates/ra_assists/src/change_visibility.rs10
-rw-r--r--crates/ra_assists/src/flip_binexpr.rs2
-rw-r--r--crates/ra_assists/src/flip_comma.rs10
-rw-r--r--crates/ra_assists/src/inline_local_variable.rs432
-rw-r--r--crates/ra_assists/src/introduce_variable.rs28
-rw-r--r--crates/ra_assists/src/remove_dbg.rs6
-rw-r--r--crates/ra_assists/src/replace_if_let_with_match.rs4
-rw-r--r--crates/ra_assists/src/split_import.rs4
-rw-r--r--crates/ra_cli/src/analysis_stats.rs7
-rw-r--r--crates/ra_cli/src/main.rs35
-rw-r--r--crates/ra_fmt/src/lib.rs29
-rw-r--r--crates/ra_hir/src/adt.rs28
-rw-r--r--crates/ra_hir/src/code_model_api.rs73
-rw-r--r--crates/ra_hir/src/code_model_impl/function.rs8
-rw-r--r--crates/ra_hir/src/code_model_impl/module.rs4
-rw-r--r--crates/ra_hir/src/db.rs9
-rw-r--r--crates/ra_hir/src/expr.rs84
-rw-r--r--crates/ra_hir/src/expr/scope.rs19
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir/src/nameres.rs7
-rw-r--r--crates/ra_hir/src/nameres/raw.rs73
-rw-r--r--crates/ra_hir/src/path.rs13
-rw-r--r--crates/ra_hir/src/source_binder.rs52
-rw-r--r--crates/ra_hir/src/ty/infer.rs20
-rw-r--r--crates/ra_hir/src/ty/tests.rs75
-rw-r--r--crates/ra_ide_api/src/call_info.rs34
-rw-r--r--crates/ra_ide_api/src/completion.rs23
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_keyword.rs8
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs25
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs22
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap9
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs6
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs144
-rw-r--r--crates/ra_ide_api/src/folding_ranges.rs137
-rw-r--r--crates/ra_ide_api/src/hover.rs14
-rw-r--r--crates/ra_ide_api/src/join_lines.rs81
-rw-r--r--crates/ra_ide_api/src/matching_brace.rs9
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs12
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs202
-rw-r--r--crates/ra_ide_api/src/typing.rs30
-rw-r--r--crates/ra_mbe/src/lib.rs16
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs86
-rw-r--r--crates/ra_parser/src/event.rs6
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs1
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs17
-rw-r--r--crates/ra_parser/src/grammar/items.rs2
-rw-r--r--crates/ra_parser/src/grammar/items/traits.rs1
-rw-r--r--crates/ra_parser/src/grammar/type_args.rs1
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs45
-rw-r--r--crates/ra_parser/src/grammar/types.rs40
-rw-r--r--crates/ra_parser/src/lib.rs8
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs4
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/algo.rs41
-rw-r--r--crates/ra_syntax/src/ast.rs802
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs252
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs303
-rw-r--r--crates/ra_syntax/src/ast/generated.rs662
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs113
-rw-r--r--crates/ra_syntax/src/ast/traits.rs154
-rw-r--r--crates/ra_syntax/src/grammar.ron78
-rw-r--r--crates/ra_syntax/src/lib.rs34
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs142
-rw-r--r--crates/ra_syntax/src/parsing/text_tree_sink.rs28
-rw-r--r--crates/ra_syntax/src/string_lexing.rs338
-rw-r--r--crates/ra_syntax/src/string_lexing/parser.rs168
-rw-r--r--crates/ra_syntax/src/string_lexing/string.rs222
-rw-r--r--crates/ra_syntax/src/syntax_node.rs296
-rw-r--r--crates/ra_syntax/src/syntax_text.rs15
-rw-r--r--crates/ra_syntax/src/validation.rs18
-rw-r--r--crates/ra_syntax/src/validation/byte.rs8
-rw-r--r--crates/ra_syntax/src/validation/byte_string.rs8
-rw-r--r--crates/ra_syntax/src/validation/char.rs8
-rw-r--r--crates/ra_syntax/src/validation/string.rs8
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0000_struct_field_missing_comma.txt24
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0001_item_recovery_in_file.txt18
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0002_duplicate_shebang.txt8
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0003_C++_semicolon.txt30
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0004_use_path_bad_segment.txt8
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0005_attribute_recover.txt66
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0006_named_field_recovery.txt60
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0007_stray_curly_in_file.txt34
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0008_item_block_recovery.txt88
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0009_broken_struct_type_parameter.txt38
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0010_unsafe_lambda_block.txt54
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0011_extern_struct.txt12
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0013_invalid_type.txt46
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0014_where_no_bounds.txt26
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0015_curly_in_params.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0016_missing_semi.txt40
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0017_incomplete_binexpr.txt42
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0018_incomplete_fn.txt110
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0019_let_recover.txt110
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0020_fn_recover.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0021_incomplete_param.txt26
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0022_bad_exprs.txt146
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0023_mismatched_paren.txt50
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0024_many_type_parens.txt446
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0025_nope.txt212
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0026_imp_recovery.txt44
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0027_incomplere_where_for.txt30
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0028_macro_2.0.txt236
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0029_field_completion.txt26
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0030_string_suffixes.txt90
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.txt146
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0032_match_arms_inner_attrs.txt228
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0033_match_arms_outer_attrs.txt80
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0001_array_type_missing_semi.txt24
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0002_misplaced_label_err.txt28
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0003_pointer_type_no_mutability.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0004_impl_type.txt68
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0005_fn_pointer_type_missing_fn.txt22
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0006_unsafe_block_in_mod.txt40
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0007_async_without_semicolon.txt40
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0008_pub_expr.txt26
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0009_attr_on_expr_not_allowed.txt60
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0001_trait_item_list.txt82
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0002_use_tree_list.txt106
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0003_where_pred_for.txt80
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0004_value_parameters_no_patterns.txt62
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0005_function_type_params.txt51
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0006_self_param.txt138
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0007_type_param_bounds.txt60
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0008_path_part.txt112
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0009_loop_expr.txt30
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0010_extern_block.txt10
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0011_field_expr.txt32
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0012_type_item_where_clause.txt40
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0013_pointer_type_mut.txt48
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0014_never_type.txt16
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0015_continue_expr.txt46
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0016_unsafe_trait.txt16
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0017_array_type.txt26
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0018_arb_self_types.txt68
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0019_unary_expr.txt46
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0020_use_star.txt60
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0021_impl_item_list.txt82
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0022_crate_visibility.txt72
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0023_placeholder_type.txt16
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0024_slice_pat.txt50
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0025_slice_type.txt22
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0026_tuple_pat_fields.txt126
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0027_ref_pat.txt62
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0028_impl_trait_type.txt73
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0029_cast_expr.rs1
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0029_cast_expr.txt86
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0030_cond.txt208
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0031_while_expr.txt68
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0032_fn_pointer_type.txt76
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0033_reference_type;.txt68
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0034_break_expr.txt66
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0036_unsafe_extern_fn.txt28
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0037_qual_paths.txt64
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0038_full_range_expr.txt28
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0039_type_arg.txt30
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0040_crate_keyword_vis.txt62
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0041_trait_item.rs1
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0041_trait_item.txt144
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0042_call_expr.txt126
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0043_use_alias.txt96
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0044_block_items.txt34
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0045_param_list_opt_patterns.txt70
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0046_singleton_tuple_type.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0047_unsafe_default_impl.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0048_path_type_with_bounds.rs1
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0048_path_type_with_bounds.txt91
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0049_let_stmt;.txt70
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0050_fn_decl.txt26
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0051_unit_type.txt18
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0052_path_type.txt66
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0053_path_expr.txt98
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0054_field_attrs.txt46
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt98
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0056_where_clause.txt125
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0057_const_fn.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt90
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0059_match_arms_commas.txt80
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0060_extern_crate.txt12
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0061_struct_lit.txt86
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0062_mod_contents.txt62
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0063_impl_block_neg.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0064_if_expr.txt118
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0065_dyn_trait_type.txt73
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0066_match_arm.txt164
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0067_crate_path.txt12
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0068_union_items.txt42
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0069_use_tree_list_after_path.txt32
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.txt56
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0071_match_expr.txt52
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0072_return_expr.txt32
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0073_type_item_type_params.txt22
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.txt82
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0075_block.txt100
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0076_function_where_clause.txt42
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0077_try_expr.txt24
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0078_type_item.txt14
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0079_impl_block.txt12
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0080_postfix_range.txt34
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0081_for_type.txt172
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0082_ref_expr.txt64
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0083_struct_items.txt78
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0084_paren_type.txt18
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0085_expr_literals.txt194
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0086_function_ret_type.txt42
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0087_unsafe_impl.txt16
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0088_break_ambiguity.txt78
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0089_extern_fn.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0090_type_param_default.txt18
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0091_auto_trait.txt16
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0092_fn_pointer_type_with_ret.txt30
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0093_index_expr.txt30
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0094_unsafe_auto_trait.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0095_placeholder_pat.txt38
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0096_no_semi_after_block.txt146
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0097_default_impl.txt16
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0098_const_unsafe_fn.txt24
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0099_param_list.txt92
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0100_for_expr.txt42
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0101_unsafe_fn.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0102_field_pat_list.txt156
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0103_array_expr.txt60
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0104_path_fn_trait_args.txt36
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0105_block_expr.txt52
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0106_lambda_expr.rs3
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0106_lambda_expr.txt136
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0107_method_call_expr.txt50
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0108_tuple_expr.txt44
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0109_label.txt82
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0110_use_path.txt40
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0111_tuple_pat.txt50
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0112_bind_pat.txt172
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0113_nocontentexpr.txt62
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0114_tuple_struct_where.txt54
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0115_pos_field_attrs.txt44
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0116_trait_fn_placeholder_parameter.txt44
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0117_macro_call_type.txt44
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0118_impl_inner_attributes.txt44
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0118_match_guard.txt58
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0120_match_arms_inner_attribute.txt100
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0121_match_arms_outer_attributes.txt184
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0122_generic_lifetime_type_attribute.txt64
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0123_param_list_vararg.txt50
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0124_async_fn.txt20
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0125_crate_keyword_path.txt30
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0125_struct_literal_field_with_attr.txt46
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0126_attr_on_expr_stmt.txt92
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0127_attr_on_last_expr_in_block.txt60
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0001_struct_item.txt42
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0002_struct_item_field.txt18
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0004_file_shebang.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0005_fn_item.txt18
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0006_inner_attributes.txt212
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt50
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0008_mod_item.txt110
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0009_use_item.txt16
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0010_use_path_segments.txt26
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0011_outer_attribute.txt36
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0012_visibility.txt120
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0013_use_path_self_super.txt48
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0014_use_tree.txt98
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0015_use_tree.txt60
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0016_struct_flavors.txt86
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0017_attr_trailing_comma.txt30
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0018_struct_type_params.txt290
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0019_enums.txt154
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0020_type_param_bounds.rs1
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0020_type_param_bounds.txt334
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0021_extern_fn.txt74
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0022_empty_extern_block.txt28
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0023_static_items.txt40
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0024_const_item.txt40
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0025_extern_fn_in_block.txt38
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0026_const_fn_in_block.txt38
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0027_unsafe_fn_in_block.txt52
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0028_operator_binding_power.txt190
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0029_range_forms.txt138
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0030_traits.txt96
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0031_extern.txt796
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0032_where_for.txt115
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0033_label_break.txt224
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0034_crate_path_in_call.txt32
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt2524
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0036_fully_qualified.txt98
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0037_mod.txt22
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0038_where_pred_type.txt44
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0039_raw_fn_item.txt18
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0040_raw_struct_item_field.txt18
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0041_raw_keywords.txt50
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0042_ufcs_call_list.txt114
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0043_complex_assignment.txt102
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0044_let_attrs.txt76
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.txt236
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0046_extern_inner_attributes.txt36
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0047_minus_in_inner_pattern.txt310
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0048_compound_assignment.txt160
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0049_async_block.rs5
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0049_async_block.txt35
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0050_async_block_as_argument.rs5
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0050_async_block_as_argument.txt90
-rw-r--r--docs/user/README.md3
-rw-r--r--docs/user/features.md2
-rw-r--r--editors/code/package-lock.json51
-rw-r--r--editors/code/package.json38
-rw-r--r--editors/code/src/commands/cargo_watch.ts238
-rw-r--r--editors/code/src/commands/line_buffer.ts16
-rw-r--r--editors/code/src/commands/runnables.ts33
-rw-r--r--editors/code/src/commands/watch_status.ts51
-rw-r--r--editors/code/src/config.ts34
-rw-r--r--editors/code/src/extension.ts2
-rw-r--r--editors/code/src/utils/processes.ts51
-rw-r--r--editors/code/src/utils/terminateProcess.sh12
-rw-r--r--editors/emacs/ra.el128
319 files changed, 13161 insertions, 11728 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 669977163..06117ceaf 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1087,8 +1087,8 @@ dependencies = [
1087 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1087 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1088 "ra_parser 0.1.0", 1088 "ra_parser 0.1.0",
1089 "ra_text_edit 0.1.0", 1089 "ra_text_edit 0.1.0",
1090 "rowan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 1090 "rowan 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1091 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1091 "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1092 "test_utils 0.1.0", 1092 "test_utils 0.1.0",
1093 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1093 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1094 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1094 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1108,7 +1108,7 @@ dependencies = [
1108name = "ra_tt" 1108name = "ra_tt"
1109version = "0.1.0" 1109version = "0.1.0"
1110dependencies = [ 1110dependencies = [
1111 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1111 "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1112] 1112]
1113 1113
1114[[package]] 1114[[package]]
@@ -1308,12 +1308,12 @@ dependencies = [
1308 1308
1309[[package]] 1309[[package]]
1310name = "rowan" 1310name = "rowan"
1311version = "0.3.3" 1311version = "0.4.0"
1312source = "registry+https://github.com/rust-lang/crates.io-index" 1312source = "registry+https://github.com/rust-lang/crates.io-index"
1313dependencies = [ 1313dependencies = [
1314 "colosseum 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 1314 "colosseum 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
1315 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1315 "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1316 "smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1316 "smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1317 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1317 "text_unit 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1318] 1318]
1319 1319
@@ -1466,7 +1466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1466 1466
1467[[package]] 1467[[package]]
1468name = "smol_str" 1468name = "smol_str"
1469version = "0.1.9" 1469version = "0.1.10"
1470source = "registry+https://github.com/rust-lang/crates.io-index" 1470source = "registry+https://github.com/rust-lang/crates.io-index"
1471dependencies = [ 1471dependencies = [
1472 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 1472 "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1974,7 +1974,7 @@ dependencies = [
1974"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c" 1974"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c"
1975"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" 1975"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
1976"checksum ron 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "17f52a24414403f81528b67488cf8edc4eda977d3af1646bb6b106a600ead78f" 1976"checksum ron 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "17f52a24414403f81528b67488cf8edc4eda977d3af1646bb6b106a600ead78f"
1977"checksum rowan 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74d41f779e2c893339e34bebf035652c58214823cd412550111886c06632f89d" 1977"checksum rowan 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "397cd19c109641f10f3c66433440285e232d8cbd37406cf8f944a15ab1e63a8e"
1978"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" 1978"checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
1979"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" 1979"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
1980"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1980"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
@@ -1993,7 +1993,7 @@ dependencies = [
1993"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1993"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1994"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" 1994"checksum slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
1995"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" 1995"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
1996"checksum smol_str 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9af1035bc5d742ab6b7ab16713e41cc2ffe78cb474f6f43cd696b2d16052007e" 1996"checksum smol_str 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d077b3367211e9c6e2e012fb804c444e0d80ab5a51ae4137739b58e6446dcaef"
1997"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" 1997"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
1998"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" 1998"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
1999"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1999"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
diff --git a/crates/ra_assists/src/add_derive.rs b/crates/ra_assists/src/add_derive.rs
index e91b5eb8d..0c4cf2615 100644
--- a/crates/ra_assists/src/add_derive.rs
+++ b/crates/ra_assists/src/add_derive.rs
@@ -33,8 +33,10 @@ pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist>
33 33
34// Insert `derive` after doc comments. 34// Insert `derive` after doc comments.
35fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> { 35fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextUnit> {
36 let non_ws_child = 36 let non_ws_child = nominal
37 nominal.syntax().children().find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; 37 .syntax()
38 .children_with_tokens()
39 .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
38 Some(non_ws_child.range().start()) 40 Some(non_ws_child.range().start())
39} 41}
40 42
diff --git a/crates/ra_assists/src/add_impl.rs b/crates/ra_assists/src/add_impl.rs
index b292f188d..fa1c85890 100644
--- a/crates/ra_assists/src/add_impl.rs
+++ b/crates/ra_assists/src/add_impl.rs
@@ -1,7 +1,7 @@
1use join_to_string::join; 1use join_to_string::join;
2use hir::db::HirDatabase; 2use hir::db::HirDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner}, 4 ast::{self, AstNode, NameOwner, TypeParamsOwner},
5 TextUnit, 5 TextUnit,
6}; 6};
7 7
@@ -22,8 +22,10 @@ pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
22 buf.push_str(" "); 22 buf.push_str(" ");
23 buf.push_str(name.text().as_str()); 23 buf.push_str(name.text().as_str());
24 if let Some(type_params) = type_params { 24 if let Some(type_params) = type_params {
25 let lifetime_params = 25 let lifetime_params = type_params
26 type_params.lifetime_params().filter_map(|it| it.lifetime()).map(|it| it.text()); 26 .lifetime_params()
27 .filter_map(|it| it.lifetime_token())
28 .map(|it| it.text());
27 let type_params = 29 let type_params =
28 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text()); 30 type_params.type_params().filter_map(|it| it.name()).map(|it| it.text());
29 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf); 31 join(lifetime_params.chain(type_params)).surround_with("<", ">").to_buf(&mut buf);
diff --git a/crates/ra_assists/src/add_missing_impl_members.rs b/crates/ra_assists/src/add_missing_impl_members.rs
index e13f54c4f..19a2d05bc 100644
--- a/crates/ra_assists/src/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/add_missing_impl_members.rs
@@ -1,9 +1,11 @@
1use std::fmt::Write;
2
1use crate::{Assist, AssistId, AssistCtx}; 3use crate::{Assist, AssistId, AssistCtx};
2 4
3use hir::Resolver; 5use hir::Resolver;
4use hir::db::HirDatabase; 6use hir::db::HirDatabase;
5use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc}; 7use ra_syntax::{SmolStr, SyntaxKind, TextRange, TextUnit, TreeArc};
6use ra_syntax::ast::{self, AstNode, FnDef, ImplItem, ImplItemKind, NameOwner}; 8use ra_syntax::ast::{self, AstNode, AstToken, FnDef, ImplItem, ImplItemKind, NameOwner};
7use ra_db::FilePosition; 9use ra_db::FilePosition;
8use ra_fmt::{leading_indent, reindent}; 10use ra_fmt::{leading_indent, reindent};
9 11
@@ -91,8 +93,9 @@ fn add_missing_impl_members_inner(
91 }; 93 };
92 94
93 let changed_range = { 95 let changed_range = {
94 let children = impl_item_list.syntax().children(); 96 let children = impl_item_list.syntax().children_with_tokens();
95 let last_whitespace = children.filter_map(ast::Whitespace::cast).last(); 97 let last_whitespace =
98 children.filter_map(|it| ast::Whitespace::cast(it.as_token()?)).last();
96 99
97 last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| { 100 last_whitespace.map(|w| w.syntax().range()).unwrap_or_else(|| {
98 let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}"); 101 let in_brackets = impl_item_list.syntax().range().end() - TextUnit::of_str("}");
@@ -134,13 +137,13 @@ fn resolve_target_trait_def(
134fn build_func_body(def: &ast::FnDef) -> String { 137fn build_func_body(def: &ast::FnDef) -> String {
135 let mut buf = String::new(); 138 let mut buf = String::new();
136 139
137 for child in def.syntax().children() { 140 for child in def.syntax().children_with_tokens() {
138 match (child.prev_sibling().map(|c| c.kind()), child.kind()) { 141 match (child.prev_sibling_or_token().map(|c| c.kind()), child.kind()) {
139 (_, SyntaxKind::SEMI) => buf.push_str(" { unimplemented!() }"), 142 (_, SyntaxKind::SEMI) => buf.push_str(" { unimplemented!() }"),
140 (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {} 143 (_, SyntaxKind::ATTR) | (_, SyntaxKind::COMMENT) => {}
141 (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE) 144 (Some(SyntaxKind::ATTR), SyntaxKind::WHITESPACE)
142 | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {} 145 | (Some(SyntaxKind::COMMENT), SyntaxKind::WHITESPACE) => {}
143 _ => child.text().push_to(&mut buf), 146 _ => write!(buf, "{}", child).unwrap(),
144 }; 147 };
145 } 148 }
146 149
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 4ad21c74b..e80e35738 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -2,8 +2,8 @@ use hir::db::HirDatabase;
2use ra_text_edit::TextEditBuilder; 2use ra_text_edit::TextEditBuilder;
3use ra_db::FileRange; 3use ra_db::FileRange;
4use ra_syntax::{ 4use ra_syntax::{
5 SourceFile, TextRange, AstNode, TextUnit, SyntaxNode, 5 SourceFile, TextRange, AstNode, TextUnit, SyntaxNode, SyntaxElement, SyntaxToken,
6 algo::{find_leaf_at_offset, find_node_at_offset, find_covering_node, LeafAtOffset}, 6 algo::{find_token_at_offset, find_node_at_offset, find_covering_element, TokenAtOffset},
7}; 7};
8use ra_fmt::{leading_indent, reindent}; 8use ra_fmt::{leading_indent, reindent};
9 9
@@ -104,15 +104,19 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
104 Some(self.assist) 104 Some(self.assist)
105 } 105 }
106 106
107 pub(crate) fn leaf_at_offset(&self) -> LeafAtOffset<&'a SyntaxNode> { 107 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken<'a>> {
108 find_leaf_at_offset(self.source_file.syntax(), self.frange.range.start()) 108 find_token_at_offset(self.source_file.syntax(), self.frange.range.start())
109 } 109 }
110 110
111 pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> { 111 pub(crate) fn node_at_offset<N: AstNode>(&self) -> Option<&'a N> {
112 find_node_at_offset(self.source_file.syntax(), self.frange.range.start()) 112 find_node_at_offset(self.source_file.syntax(), self.frange.range.start())
113 } 113 }
114 pub(crate) fn covering_node(&self) -> &'a SyntaxNode { 114 pub(crate) fn covering_element(&self) -> SyntaxElement<'a> {
115 find_covering_node(self.source_file.syntax(), self.frange.range) 115 find_covering_element(self.source_file.syntax(), self.frange.range)
116 }
117
118 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement<'a> {
119 find_covering_element(self.source_file.syntax(), range)
116 } 120 }
117} 121}
118 122
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index 685dbed06..3fdf6b0d9 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -21,7 +21,7 @@ fn collect_path_segments_raw<'a>(
21) -> Option<usize> { 21) -> Option<usize> {
22 let oldlen = segments.len(); 22 let oldlen = segments.len();
23 loop { 23 loop {
24 let mut children = path.syntax().children(); 24 let mut children = path.syntax().children_with_tokens();
25 let (first, second, third) = ( 25 let (first, second, third) = (
26 children.next().map(|n| (n, n.kind())), 26 children.next().map(|n| (n, n.kind())),
27 children.next().map(|n| (n, n.kind())), 27 children.next().map(|n| (n, n.kind())),
@@ -29,11 +29,11 @@ fn collect_path_segments_raw<'a>(
29 ); 29 );
30 match (first, second, third) { 30 match (first, second, third) {
31 (Some((subpath, PATH)), Some((_, COLONCOLON)), Some((segment, PATH_SEGMENT))) => { 31 (Some((subpath, PATH)), Some((_, COLONCOLON)), Some((segment, PATH_SEGMENT))) => {
32 path = ast::Path::cast(subpath)?; 32 path = ast::Path::cast(subpath.as_node()?)?;
33 segments.push(ast::PathSegment::cast(segment)?); 33 segments.push(ast::PathSegment::cast(segment.as_node()?)?);
34 } 34 }
35 (Some((segment, PATH_SEGMENT)), _, _) => { 35 (Some((segment, PATH_SEGMENT)), _, _) => {
36 segments.push(ast::PathSegment::cast(segment)?); 36 segments.push(ast::PathSegment::cast(segment.as_node()?)?);
37 break; 37 break;
38 } 38 }
39 (_, _, _) => return None, 39 (_, _, _) => return None,
@@ -514,8 +514,7 @@ fn apply_auto_import<'a>(
514} 514}
515 515
516pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 516pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
517 let node = ctx.covering_node(); 517 let path: &ast::Path = ctx.node_at_offset()?;
518 let path = node.ancestors().find_map(ast::Path::cast)?;
519 // We don't want to mess with use statements 518 // We don't want to mess with use statements
520 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { 519 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
521 return None; 520 return None;
@@ -537,7 +536,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
537 ); 536 );
538 } 537 }
539 } else { 538 } else {
540 let current_file = node.ancestors().find_map(ast::SourceFile::cast)?; 539 let current_file = path.syntax().ancestors().find_map(ast::SourceFile::cast)?;
541 ctx.add_action( 540 ctx.add_action(
542 AssistId("auto_import"), 541 AssistId("auto_import"),
543 format!("import {} in the current file", fmt_segments(&segments)), 542 format!("import {} in the current file", fmt_segments(&segments)),
diff --git a/crates/ra_assists/src/change_visibility.rs b/crates/ra_assists/src/change_visibility.rs
index 50c1be5ae..c63470726 100644
--- a/crates/ra_assists/src/change_visibility.rs
+++ b/crates/ra_assists/src/change_visibility.rs
@@ -15,13 +15,13 @@ pub(crate) fn change_visibility(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi
15} 15}
16 16
17fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 17fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
18 let item_keyword = ctx.leaf_at_offset().find(|leaf| match leaf.kind() { 18 let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
19 FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true, 19 FN_KW | MOD_KW | STRUCT_KW | ENUM_KW | TRAIT_KW => true,
20 _ => false, 20 _ => false,
21 }); 21 });
22 22
23 let (offset, target) = if let Some(keyword) = item_keyword { 23 let (offset, target) = if let Some(keyword) = item_keyword {
24 let parent = keyword.parent()?; 24 let parent = keyword.parent();
25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF]; 25 let def_kws = vec![FN_DEF, MODULE, STRUCT_DEF, ENUM_DEF, TRAIT_DEF];
26 // Parent is not a definition, can't add visibility 26 // Parent is not a definition, can't add visibility
27 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) { 27 if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
@@ -33,8 +33,8 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
33 } 33 }
34 (vis_offset(parent), keyword.range()) 34 (vis_offset(parent), keyword.range())
35 } else { 35 } else {
36 let ident = ctx.leaf_at_offset().find(|leaf| leaf.kind() == IDENT)?; 36 let ident = ctx.token_at_offset().find(|leaf| leaf.kind() == IDENT)?;
37 let field = ident.ancestors().find_map(ast::NamedFieldDef::cast)?; 37 let field = ident.parent().ancestors().find_map(ast::NamedFieldDef::cast)?;
38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() { 38 if field.name()?.syntax().range() != ident.range() && field.visibility().is_some() {
39 return None; 39 return None;
40 } 40 }
@@ -51,7 +51,7 @@ fn add_vis(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
51} 51}
52 52
53fn vis_offset(node: &SyntaxNode) -> TextUnit { 53fn vis_offset(node: &SyntaxNode) -> TextUnit {
54 node.children() 54 node.children_with_tokens()
55 .skip_while(|it| match it.kind() { 55 .skip_while(|it| match it.kind() {
56 WHITESPACE | COMMENT | ATTR => true, 56 WHITESPACE | COMMENT | ATTR => true,
57 _ => false, 57 _ => false,
diff --git a/crates/ra_assists/src/flip_binexpr.rs b/crates/ra_assists/src/flip_binexpr.rs
index ec377642e..02d27f66d 100644
--- a/crates/ra_assists/src/flip_binexpr.rs
+++ b/crates/ra_assists/src/flip_binexpr.rs
@@ -8,7 +8,7 @@ pub(crate) fn flip_binexpr(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assis
8 let expr = ctx.node_at_offset::<BinExpr>()?; 8 let expr = ctx.node_at_offset::<BinExpr>()?;
9 let lhs = expr.lhs()?.syntax(); 9 let lhs = expr.lhs()?.syntax();
10 let rhs = expr.rhs()?.syntax(); 10 let rhs = expr.rhs()?.syntax();
11 let op_range = expr.op()?.range(); 11 let op_range = expr.op_token()?.range();
12 // The assist should be applied only if the cursor is on the operator 12 // The assist should be applied only if the cursor is on the operator
13 let cursor_in_range = ctx.frange.range.is_subrange(&op_range); 13 let cursor_in_range = ctx.frange.range.is_subrange(&op_range);
14 if !cursor_in_range { 14 if !cursor_in_range {
diff --git a/crates/ra_assists/src/flip_comma.rs b/crates/ra_assists/src/flip_comma.rs
index 6b98cac68..a9b108111 100644
--- a/crates/ra_assists/src/flip_comma.rs
+++ b/crates/ra_assists/src/flip_comma.rs
@@ -8,13 +8,13 @@ use ra_syntax::{
8use crate::{AssistCtx, Assist, AssistId}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(crate) fn flip_comma(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 let comma = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COMMA)?; 11 let comma = ctx.token_at_offset().find(|leaf| leaf.kind() == COMMA)?;
12 let prev = non_trivia_sibling(comma, Direction::Prev)?; 12 let prev = non_trivia_sibling(comma.into(), Direction::Prev)?;
13 let next = non_trivia_sibling(comma, Direction::Next)?; 13 let next = non_trivia_sibling(comma.into(), Direction::Next)?;
14 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| { 14 ctx.add_action(AssistId("flip_comma"), "flip comma", |edit| {
15 edit.target(comma.range()); 15 edit.target(comma.range());
16 edit.replace(prev.range(), next.text()); 16 edit.replace(prev.range(), next.to_string());
17 edit.replace(next.range(), prev.text()); 17 edit.replace(next.range(), prev.to_string());
18 }); 18 });
19 19
20 ctx.build() 20 ctx.build()
diff --git a/crates/ra_assists/src/inline_local_variable.rs b/crates/ra_assists/src/inline_local_variable.rs
index bd3cdb970..950c2910b 100644
--- a/crates/ra_assists/src/inline_local_variable.rs
+++ b/crates/ra_assists/src/inline_local_variable.rs
@@ -1,7 +1,11 @@
1use hir::db::HirDatabase; 1use hir::{
2use hir::source_binder::function_from_child_node; 2 db::HirDatabase,
3use ra_syntax::{ast::{self, AstNode}, TextRange}; 3 source_binder::function_from_child_node,
4use ra_syntax::ast::{PatKind, ExprKind}; 4};
5use ra_syntax::{
6 ast::{self, AstNode, AstToken, PatKind, ExprKind},
7 TextRange,
8};
5 9
6use crate::{Assist, AssistCtx, AssistId}; 10use crate::{Assist, AssistCtx, AssistId};
7use crate::assist_ctx::AssistBuilder; 11use crate::assist_ctx::AssistBuilder;
@@ -15,61 +19,77 @@ pub(crate) fn inline_local_varialbe(mut ctx: AssistCtx<impl HirDatabase>) -> Opt
15 if bind_pat.is_mutable() { 19 if bind_pat.is_mutable() {
16 return None; 20 return None;
17 } 21 }
18 let initializer = let_stmt.initializer()?; 22 let initializer_expr = let_stmt.initializer();
19 let wrap_in_parens = match initializer.kind() { 23 let delete_range = if let Some(whitespace) = let_stmt
20 ExprKind::LambdaExpr(_) 24 .syntax()
21 | ExprKind::IfExpr(_) 25 .next_sibling_or_token()
22 | ExprKind::LoopExpr(_) 26 .and_then(|it| ast::Whitespace::cast(it.as_token()?))
23 | ExprKind::ForExpr(_)
24 | ExprKind::WhileExpr(_)
25 | ExprKind::ContinueExpr(_)
26 | ExprKind::BreakExpr(_)
27 | ExprKind::Label(_)
28 | ExprKind::ReturnExpr(_)
29 | ExprKind::MatchExpr(_)
30 | ExprKind::StructLit(_)
31 | ExprKind::CastExpr(_)
32 | ExprKind::PrefixExpr(_)
33 | ExprKind::RangeExpr(_)
34 | ExprKind::BinExpr(_) => true,
35 ExprKind::CallExpr(_)
36 | ExprKind::IndexExpr(_)
37 | ExprKind::MethodCallExpr(_)
38 | ExprKind::FieldExpr(_)
39 | ExprKind::TryExpr(_)
40 | ExprKind::RefExpr(_)
41 | ExprKind::Literal(_)
42 | ExprKind::TupleExpr(_)
43 | ExprKind::ArrayExpr(_)
44 | ExprKind::ParenExpr(_)
45 | ExprKind::PathExpr(_)
46 | ExprKind::BlockExpr(_) => false,
47 };
48
49 let delete_range = if let Some(whitespace) =
50 let_stmt.syntax().next_sibling().and_then(ast::Whitespace::cast)
51 { 27 {
52 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end()) 28 TextRange::from_to(let_stmt.syntax().range().start(), whitespace.syntax().range().end())
53 } else { 29 } else {
54 let_stmt.syntax().range() 30 let_stmt.syntax().range()
55 }; 31 };
56 32
57 let init_str = if wrap_in_parens {
58 format!("({})", initializer.syntax().text().to_string())
59 } else {
60 initializer.syntax().text().to_string()
61 };
62 let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?; 33 let function = function_from_child_node(ctx.db, ctx.frange.file_id, bind_pat.syntax())?;
63 let scope = function.scopes(ctx.db); 34 let scope = function.scopes(ctx.db);
64 let refs = scope.find_all_refs(bind_pat); 35 let refs = scope.find_all_refs(bind_pat);
65 36
37 let mut wrap_in_parens = vec![true; refs.len()];
38
39 for (i, desc) in refs.iter().enumerate() {
40 let usage_node = ctx
41 .covering_node_for_range(desc.range)
42 .ancestors()
43 .find_map(|node| ast::PathExpr::cast(node))?;
44 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast);
45 let usage_parent = match usage_parent_option {
46 Some(u) => u,
47 None => {
48 wrap_in_parens[i] = false;
49 continue;
50 }
51 };
52
53 wrap_in_parens[i] = match (initializer_expr?.kind(), usage_parent.kind()) {
54 (ExprKind::CallExpr(_), _)
55 | (ExprKind::IndexExpr(_), _)
56 | (ExprKind::MethodCallExpr(_), _)
57 | (ExprKind::FieldExpr(_), _)
58 | (ExprKind::TryExpr(_), _)
59 | (ExprKind::RefExpr(_), _)
60 | (ExprKind::Literal(_), _)
61 | (ExprKind::TupleExpr(_), _)
62 | (ExprKind::ArrayExpr(_), _)
63 | (ExprKind::ParenExpr(_), _)
64 | (ExprKind::PathExpr(_), _)
65 | (ExprKind::BlockExpr(_), _)
66 | (_, ExprKind::CallExpr(_))
67 | (_, ExprKind::TupleExpr(_))
68 | (_, ExprKind::ArrayExpr(_))
69 | (_, ExprKind::ParenExpr(_))
70 | (_, ExprKind::ForExpr(_))
71 | (_, ExprKind::WhileExpr(_))
72 | (_, ExprKind::BreakExpr(_))
73 | (_, ExprKind::ReturnExpr(_))
74 | (_, ExprKind::MatchExpr(_)) => false,
75 _ => true,
76 };
77 }
78
79 let init_str = initializer_expr?.syntax().text().to_string();
80 let init_in_paren = format!("({})", &init_str);
81
66 ctx.add_action( 82 ctx.add_action(
67 AssistId("inline_local_variable"), 83 AssistId("inline_local_variable"),
68 "inline local variable", 84 "inline local variable",
69 move |edit: &mut AssistBuilder| { 85 move |edit: &mut AssistBuilder| {
70 edit.delete(delete_range); 86 edit.delete(delete_range);
71 for desc in refs { 87 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) {
72 edit.replace(desc.range, init_str.clone()) 88 if should_wrap {
89 edit.replace(desc.range, init_in_paren.clone())
90 } else {
91 edit.replace(desc.range, init_str.clone())
92 }
73 } 93 }
74 edit.set_cursor(delete_range.start()) 94 edit.set_cursor(delete_range.start())
75 }, 95 },
@@ -147,7 +167,7 @@ fn foo() {
147 167
148 } 168 }
149 let b = (1 + 1) * 10; 169 let b = (1 + 1) * 10;
150 bar((1 + 1)); 170 bar(1 + 1);
151}", 171}",
152 ); 172 );
153 } 173 }
@@ -215,7 +235,7 @@ fn foo() {
215 235
216 } 236 }
217 let b = (bar(1) as u64) * 10; 237 let b = (bar(1) as u64) * 10;
218 bar((bar(1) as u64)); 238 bar(bar(1) as u64);
219}", 239}",
220 ); 240 );
221 } 241 }
@@ -295,4 +315,324 @@ fn foo() {
295}", 315}",
296 ); 316 );
297 } 317 }
318
319 #[test]
320 fn test_call_expr() {
321 check_assist(
322 inline_local_varialbe,
323 "
324fn foo() {
325 let a<|> = bar(10 + 1);
326 let b = a * 10;
327 let c = a as usize;
328}",
329 "
330fn foo() {
331 <|>let b = bar(10 + 1) * 10;
332 let c = bar(10 + 1) as usize;
333}",
334 );
335 }
336
337 #[test]
338 fn test_index_expr() {
339 check_assist(
340 inline_local_varialbe,
341 "
342fn foo() {
343 let x = vec![1, 2, 3];
344 let a<|> = x[0];
345 let b = a * 10;
346 let c = a as usize;
347}",
348 "
349fn foo() {
350 let x = vec![1, 2, 3];
351 <|>let b = x[0] * 10;
352 let c = x[0] as usize;
353}",
354 );
355 }
356
357 #[test]
358 fn test_method_call_expr() {
359 check_assist(
360 inline_local_varialbe,
361 "
362fn foo() {
363 let bar = vec![1];
364 let a<|> = bar.len();
365 let b = a * 10;
366 let c = a as usize;
367}",
368 "
369fn foo() {
370 let bar = vec![1];
371 <|>let b = bar.len() * 10;
372 let c = bar.len() as usize;
373}",
374 );
375 }
376
377 #[test]
378 fn test_field_expr() {
379 check_assist(
380 inline_local_varialbe,
381 "
382struct Bar {
383 foo: usize
384}
385
386fn foo() {
387 let bar = Bar { foo: 1 };
388 let a<|> = bar.foo;
389 let b = a * 10;
390 let c = a as usize;
391}",
392 "
393struct Bar {
394 foo: usize
395}
396
397fn foo() {
398 let bar = Bar { foo: 1 };
399 <|>let b = bar.foo * 10;
400 let c = bar.foo as usize;
401}",
402 );
403 }
404
405 #[test]
406 fn test_try_expr() {
407 check_assist(
408 inline_local_varialbe,
409 "
410fn foo() -> Option<usize> {
411 let bar = Some(1);
412 let a<|> = bar?;
413 let b = a * 10;
414 let c = a as usize;
415 None
416}",
417 "
418fn foo() -> Option<usize> {
419 let bar = Some(1);
420 <|>let b = bar? * 10;
421 let c = bar? as usize;
422 None
423}",
424 );
425 }
426
427 #[test]
428 fn test_ref_expr() {
429 check_assist(
430 inline_local_varialbe,
431 "
432fn foo() {
433 let bar = 10;
434 let a<|> = &bar;
435 let b = a * 10;
436}",
437 "
438fn foo() {
439 let bar = 10;
440 <|>let b = &bar * 10;
441}",
442 );
443 }
444
445 #[test]
446 fn test_tuple_expr() {
447 check_assist(
448 inline_local_varialbe,
449 "
450fn foo() {
451 let a<|> = (10, 20);
452 let b = a[0];
453}",
454 "
455fn foo() {
456 <|>let b = (10, 20)[0];
457}",
458 );
459 }
460
461 #[test]
462 fn test_array_expr() {
463 check_assist(
464 inline_local_varialbe,
465 "
466fn foo() {
467 let a<|> = [1, 2, 3];
468 let b = a.len();
469}",
470 "
471fn foo() {
472 <|>let b = [1, 2, 3].len();
473}",
474 );
475 }
476
477 #[test]
478 fn test_paren() {
479 check_assist(
480 inline_local_varialbe,
481 "
482fn foo() {
483 let a<|> = (10 + 20);
484 let b = a * 10;
485 let c = a as usize;
486}",
487 "
488fn foo() {
489 <|>let b = (10 + 20) * 10;
490 let c = (10 + 20) as usize;
491}",
492 );
493 }
494
495 #[test]
496 fn test_path_expr() {
497 check_assist(
498 inline_local_varialbe,
499 "
500fn foo() {
501 let d = 10;
502 let a<|> = d;
503 let b = a * 10;
504 let c = a as usize;
505}",
506 "
507fn foo() {
508 let d = 10;
509 <|>let b = d * 10;
510 let c = d as usize;
511}",
512 );
513 }
514
515 #[test]
516 fn test_block_expr() {
517 check_assist(
518 inline_local_varialbe,
519 "
520fn foo() {
521 let a<|> = { 10 };
522 let b = a * 10;
523 let c = a as usize;
524}",
525 "
526fn foo() {
527 <|>let b = { 10 } * 10;
528 let c = { 10 } as usize;
529}",
530 );
531 }
532
533 #[test]
534 fn test_used_in_different_expr1() {
535 check_assist(
536 inline_local_varialbe,
537 "
538fn foo() {
539 let a<|> = 10 + 20;
540 let b = a * 10;
541 let c = (a, 20);
542 let d = [a, 10];
543 let e = (a);
544}",
545 "
546fn foo() {
547 <|>let b = (10 + 20) * 10;
548 let c = (10 + 20, 20);
549 let d = [10 + 20, 10];
550 let e = (10 + 20);
551}",
552 );
553 }
554
555 #[test]
556 fn test_used_in_for_expr() {
557 check_assist(
558 inline_local_varialbe,
559 "
560fn foo() {
561 let a<|> = vec![10, 20];
562 for i in a {}
563}",
564 "
565fn foo() {
566 <|>for i in vec![10, 20] {}
567}",
568 );
569 }
570
571 #[test]
572 fn test_used_in_while_expr() {
573 check_assist(
574 inline_local_varialbe,
575 "
576fn foo() {
577 let a<|> = 1 > 0;
578 while a {}
579}",
580 "
581fn foo() {
582 <|>while 1 > 0 {}
583}",
584 );
585 }
586
587 #[test]
588 fn test_used_in_break_expr() {
589 check_assist(
590 inline_local_varialbe,
591 "
592fn foo() {
593 let a<|> = 1 + 1;
594 loop {
595 break a;
596 }
597}",
598 "
599fn foo() {
600 <|>loop {
601 break 1 + 1;
602 }
603}",
604 );
605 }
606
607 #[test]
608 fn test_used_in_return_expr() {
609 check_assist(
610 inline_local_varialbe,
611 "
612fn foo() {
613 let a<|> = 1 > 0;
614 return a;
615}",
616 "
617fn foo() {
618 <|>return 1 > 0;
619}",
620 );
621 }
622
623 #[test]
624 fn test_used_in_match_expr() {
625 check_assist(
626 inline_local_varialbe,
627 "
628fn foo() {
629 let a<|> = 1 > 0;
630 match a {}
631}",
632 "
633fn foo() {
634 <|>match 1 > 0 {}
635}",
636 );
637 }
298} 638}
diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs
index 353bc4105..fb7333c8c 100644
--- a/crates/ra_assists/src/introduce_variable.rs
+++ b/crates/ra_assists/src/introduce_variable.rs
@@ -2,9 +2,8 @@ use test_utils::tested_by;
2use hir::db::HirDatabase; 2use hir::db::HirDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, AstNode}, 4 ast::{self, AstNode},
5 SyntaxKind::{ 5 SyntaxNode, TextUnit,
6 WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT 6 SyntaxKind::{WHITESPACE, MATCH_ARM, LAMBDA_EXPR, PATH_EXPR, BREAK_EXPR, LOOP_EXPR, RETURN_EXPR, COMMENT},
7 }, SyntaxNode, TextUnit,
8}; 7};
9 8
10use crate::{AssistCtx, Assist, AssistId}; 9use crate::{AssistCtx, Assist, AssistId};
@@ -13,14 +12,14 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
13 if ctx.frange.range.is_empty() { 12 if ctx.frange.range.is_empty() {
14 return None; 13 return None;
15 } 14 }
16 let node = ctx.covering_node(); 15 let node = ctx.covering_element();
17 if node.kind() == COMMENT { 16 if node.kind() == COMMENT {
18 tested_by!(introduce_var_in_comment_is_not_applicable); 17 tested_by!(introduce_var_in_comment_is_not_applicable);
19 return None; 18 return None;
20 } 19 }
21 let expr = node.ancestors().find_map(valid_target_expr)?; 20 let expr = node.ancestors().find_map(valid_target_expr)?;
22 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?; 21 let (anchor_stmt, wrap_in_block) = anchor_stmt(expr)?;
23 let indent = anchor_stmt.prev_sibling()?; 22 let indent = anchor_stmt.prev_sibling_or_token()?.as_token()?;
24 if indent.kind() != WHITESPACE { 23 if indent.kind() != WHITESPACE {
25 return None; 24 return None;
26 } 25 }
@@ -54,16 +53,15 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx<impl HirDatabase>) -> Option
54 // We want to maintain the indent level, 53 // We want to maintain the indent level,
55 // but we do not want to duplicate possible 54 // but we do not want to duplicate possible
56 // extra newlines in the indent block 55 // extra newlines in the indent block
57 for chunk in indent.text().chunks() { 56 let text = indent.text();
58 if chunk.starts_with("\r\n") { 57 if text.starts_with("\r\n") {
59 buf.push_str("\r\n"); 58 buf.push_str("\r\n");
60 buf.push_str(chunk.trim_start_matches("\r\n")); 59 buf.push_str(text.trim_start_matches("\r\n"));
61 } else if chunk.starts_with("\n") { 60 } else if text.starts_with("\n") {
62 buf.push_str("\n"); 61 buf.push_str("\n");
63 buf.push_str(chunk.trim_start_matches("\n")); 62 buf.push_str(text.trim_start_matches("\n"));
64 } else { 63 } else {
65 buf.push_str(chunk); 64 buf.push_str(text);
66 }
67 } 65 }
68 66
69 edit.target(expr.syntax().range()); 67 edit.target(expr.syntax().range());
diff --git a/crates/ra_assists/src/remove_dbg.rs b/crates/ra_assists/src/remove_dbg.rs
index 6ea48d909..ae9958f11 100644
--- a/crates/ra_assists/src/remove_dbg.rs
+++ b/crates/ra_assists/src/remove_dbg.rs
@@ -62,15 +62,15 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b
62 let name_ref = path.segment()?.name_ref()?; 62 let name_ref = path.segment()?.name_ref()?;
63 63
64 // Make sure it is actually a dbg-macro call, dbg followed by ! 64 // Make sure it is actually a dbg-macro call, dbg followed by !
65 let excl = path.syntax().next_sibling()?; 65 let excl = path.syntax().next_sibling_or_token()?;
66 66
67 if name_ref.text() != macro_name || excl.kind() != EXCL { 67 if name_ref.text() != macro_name || excl.kind() != EXCL {
68 return None; 68 return None;
69 } 69 }
70 70
71 let node = macro_call.token_tree()?.syntax(); 71 let node = macro_call.token_tree()?.syntax();
72 let first_child = node.first_child()?; 72 let first_child = node.first_child_or_token()?;
73 let last_child = node.last_child()?; 73 let last_child = node.last_child_or_token()?;
74 74
75 match (first_child.kind(), last_child.kind()) { 75 match (first_child.kind(), last_child.kind()) {
76 (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true), 76 (L_PAREN, R_PAREN) | (L_BRACK, R_BRACK) | (L_CURLY, R_CURLY) => Some(true),
diff --git a/crates/ra_assists/src/replace_if_let_with_match.rs b/crates/ra_assists/src/replace_if_let_with_match.rs
index 230573499..2b451f08d 100644
--- a/crates/ra_assists/src/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/replace_if_let_with_match.rs
@@ -11,8 +11,8 @@ pub(crate) fn replace_if_let_with_match(mut ctx: AssistCtx<impl HirDatabase>) ->
11 let expr = cond.expr()?; 11 let expr = cond.expr()?;
12 let then_block = if_expr.then_branch()?; 12 let then_block = if_expr.then_branch()?;
13 let else_block = match if_expr.else_branch()? { 13 let else_block = match if_expr.else_branch()? {
14 ast::ElseBranchFlavor::Block(it) => it, 14 ast::ElseBranch::Block(it) => it,
15 ast::ElseBranchFlavor::IfExpr(_) => return None, 15 ast::ElseBranch::IfExpr(_) => return None,
16 }; 16 };
17 17
18 ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| { 18 ctx.add_action(AssistId("replace_if_let_with_match"), "replace with match", |edit| {
diff --git a/crates/ra_assists/src/split_import.rs b/crates/ra_assists/src/split_import.rs
index dd5be4e91..4bf1852db 100644
--- a/crates/ra_assists/src/split_import.rs
+++ b/crates/ra_assists/src/split_import.rs
@@ -8,8 +8,8 @@ use ra_syntax::{
8use crate::{AssistCtx, Assist, AssistId}; 8use crate::{AssistCtx, Assist, AssistId};
9 9
10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 10pub(crate) fn split_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
11 let colon_colon = ctx.leaf_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?; 11 let colon_colon = ctx.token_at_offset().find(|leaf| leaf.kind() == COLONCOLON)?;
12 let path = colon_colon.parent().and_then(ast::Path::cast)?; 12 let path = ast::Path::cast(colon_colon.parent())?;
13 let top_path = generate(Some(path), |it| it.parent_path()).last()?; 13 let top_path = generate(Some(path), |it| it.parent_path()).last()?;
14 14
15 let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast); 15 let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast);
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index ee410c548..4516ed660 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -1,4 +1,4 @@
1use std::collections::HashSet; 1use std::{collections::HashSet, time::Instant};
2 2
3use ra_db::SourceDatabase; 3use ra_db::SourceDatabase;
4use ra_batch::BatchDatabase; 4use ra_batch::BatchDatabase;
@@ -8,8 +8,10 @@ use ra_syntax::AstNode;
8use crate::Result; 8use crate::Result;
9 9
10pub fn run(verbose: bool) -> Result<()> { 10pub fn run(verbose: bool) -> Result<()> {
11 let db_load_time = Instant::now();
11 let (db, roots) = BatchDatabase::load_cargo(".")?; 12 let (db, roots) = BatchDatabase::load_cargo(".")?;
12 println!("Database loaded, {} roots", roots.len()); 13 println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
14 let analysis_time = Instant::now();
13 let mut num_crates = 0; 15 let mut num_crates = 0;
14 let mut visited_modules = HashSet::new(); 16 let mut visited_modules = HashSet::new();
15 let mut visit_queue = Vec::new(); 17 let mut visit_queue = Vec::new();
@@ -96,5 +98,6 @@ pub fn run(verbose: bool) -> Result<()> {
96 num_exprs_partially_unknown, 98 num_exprs_partially_unknown,
97 (num_exprs_partially_unknown * 100 / num_exprs) 99 (num_exprs_partially_unknown * 100 / num_exprs)
98 ); 100 );
101 println!("Analysis: {:?}", analysis_time.elapsed());
99 Ok(()) 102 Ok(())
100} 103}
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index ecea516f1..45555be6e 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -3,10 +3,8 @@ mod analysis_stats;
3use std::{fs, io::Read, path::Path}; 3use std::{fs, io::Read, path::Path};
4 4
5use clap::{App, Arg, SubCommand}; 5use clap::{App, Arg, SubCommand};
6use join_to_string::join;
7use ra_ide_api::{Analysis, FileRange};
8use ra_ide_api::file_structure; 6use ra_ide_api::file_structure;
9use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; 7use ra_syntax::{SourceFile, TreeArc, AstNode};
10use tools::collect_tests; 8use tools::collect_tests;
11use flexi_logger::Logger; 9use flexi_logger::Logger;
12use ra_prof::profile; 10use ra_prof::profile;
@@ -25,11 +23,6 @@ fn main() -> Result<()> {
25 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) 23 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump")))
26 .subcommand(SubCommand::with_name("symbols")) 24 .subcommand(SubCommand::with_name("symbols"))
27 .subcommand( 25 .subcommand(
28 SubCommand::with_name("extend-selection")
29 .arg(Arg::with_name("start"))
30 .arg(Arg::with_name("end")),
31 )
32 .subcommand(
33 SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), 26 SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")),
34 ) 27 )
35 .get_matches(); 28 .get_matches();
@@ -56,13 +49,6 @@ fn main() -> Result<()> {
56 let (test, tree) = render_test(file, line)?; 49 let (test, tree) = render_test(file, line)?;
57 println!("{}\n{}", test, tree); 50 println!("{}\n{}", test, tree);
58 } 51 }
59 ("extend-selection", Some(matches)) => {
60 let start: u32 = matches.value_of("start").unwrap().parse()?;
61 let end: u32 = matches.value_of("end").unwrap().parse()?;
62 let text = read_stdin()?;
63 let sels = selections(text, start, end);
64 println!("{}", sels)
65 }
66 ("analysis-stats", Some(matches)) => { 52 ("analysis-stats", Some(matches)) => {
67 let verbose = matches.is_present("verbose"); 53 let verbose = matches.is_present("verbose");
68 analysis_stats::run(verbose)?; 54 analysis_stats::run(verbose)?;
@@ -97,22 +83,3 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> {
97 let tree = file.syntax().debug_dump(); 83 let tree = file.syntax().debug_dump();
98 Ok((test.text, tree)) 84 Ok((test.text, tree))
99} 85}
100
101fn selections(text: String, start: u32, end: u32) -> String {
102 let (analysis, file_id) = Analysis::from_single_file(text);
103 let mut ranges = Vec::new();
104 let mut range = TextRange::from_to((start - 1).into(), (end - 1).into());
105 loop {
106 ranges.push(range);
107 let next = analysis.extend_selection(FileRange { file_id, range }).unwrap();
108 if range == next {
109 break;
110 }
111 range = next;
112 }
113 let ranges = ranges
114 .iter()
115 .map(|r| (1 + u32::from(r.start()), 1 + u32::from(r.end())))
116 .map(|(s, e)| format!("({} {})", s, e));
117 join(ranges).separator(" ").surround_with("(", ")").to_string()
118}
diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs
index 62e6fb9c1..85b7ce250 100644
--- a/crates/ra_fmt/src/lib.rs
+++ b/crates/ra_fmt/src/lib.rs
@@ -2,9 +2,8 @@
2//! 2//!
3use itertools::Itertools; 3use itertools::Itertools;
4use ra_syntax::{ 4use ra_syntax::{
5 AstNode, 5 SyntaxNode, SyntaxKind::*, SyntaxToken, SyntaxKind,
6 SyntaxNode, SyntaxKind::*, 6 ast::{self, AstNode, AstToken},
7 ast::{self, AstToken},
8 algo::generate, 7 algo::generate,
9}; 8};
10 9
@@ -15,26 +14,22 @@ pub fn reindent(text: &str, indent: &str) -> String {
15 14
16/// If the node is on the beginning of the line, calculate indent. 15/// If the node is on the beginning of the line, calculate indent.
17pub fn leading_indent(node: &SyntaxNode) -> Option<&str> { 16pub fn leading_indent(node: &SyntaxNode) -> Option<&str> {
18 for leaf in prev_leaves(node) { 17 for token in prev_tokens(node.first_token()?) {
19 if let Some(ws) = ast::Whitespace::cast(leaf) { 18 if let Some(ws) = ast::Whitespace::cast(token) {
20 let ws_text = ws.text(); 19 let ws_text = ws.text();
21 if let Some(pos) = ws_text.rfind('\n') { 20 if let Some(pos) = ws_text.rfind('\n') {
22 return Some(&ws_text[pos + 1..]); 21 return Some(&ws_text[pos + 1..]);
23 } 22 }
24 } 23 }
25 if leaf.leaf_text().unwrap().contains('\n') { 24 if token.text().contains('\n') {
26 break; 25 break;
27 } 26 }
28 } 27 }
29 None 28 None
30} 29}
31 30
32fn prev_leaves(node: &SyntaxNode) -> impl Iterator<Item = &SyntaxNode> { 31fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
33 generate(prev_leaf(node), |&node| prev_leaf(node)) 32 generate(token.prev_token(), |&token| token.prev_token())
34}
35
36fn prev_leaf(node: &SyntaxNode) -> Option<&SyntaxNode> {
37 generate(node.ancestors().find_map(SyntaxNode::prev_sibling), |it| it.last_child()).last()
38} 33}
39 34
40pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> { 35pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> {
@@ -52,20 +47,20 @@ pub fn extract_trivial_expression(block: &ast::Block) -> Option<&ast::Expr> {
52 Some(expr) 47 Some(expr)
53} 48}
54 49
55pub fn compute_ws(left: &SyntaxNode, right: &SyntaxNode) -> &'static str { 50pub fn compute_ws(left: SyntaxKind, right: SyntaxKind) -> &'static str {
56 match left.kind() { 51 match left {
57 L_PAREN | L_BRACK => return "", 52 L_PAREN | L_BRACK => return "",
58 L_CURLY => { 53 L_CURLY => {
59 if let USE_TREE = right.kind() { 54 if let USE_TREE = right {
60 return ""; 55 return "";
61 } 56 }
62 } 57 }
63 _ => (), 58 _ => (),
64 } 59 }
65 match right.kind() { 60 match right {
66 R_PAREN | R_BRACK => return "", 61 R_PAREN | R_BRACK => return "",
67 R_CURLY => { 62 R_CURLY => {
68 if let USE_TREE = left.kind() { 63 if let USE_TREE = left {
69 return ""; 64 return "";
70 } 65 }
71 } 66 }
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index 78ea8976b..e027eedd9 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -6,7 +6,7 @@ use std::sync::Arc;
6use ra_arena::{RawId, Arena, impl_arena_id}; 6use ra_arena::{RawId, Arena, impl_arena_id};
7use ra_syntax::{ 7use ra_syntax::{
8 TreeArc, 8 TreeArc,
9 ast::{self, NameOwner, StructFlavor, TypeAscriptionOwner} 9 ast::{self, NameOwner, StructKind, TypeAscriptionOwner}
10}; 10};
11 11
12use crate::{ 12use crate::{
@@ -47,7 +47,7 @@ pub struct StructData {
47impl StructData { 47impl StructData {
48 fn new(struct_def: &ast::StructDef) -> StructData { 48 fn new(struct_def: &ast::StructDef) -> StructData {
49 let name = struct_def.name().map(|n| n.as_name()); 49 let name = struct_def.name().map(|n| n.as_name());
50 let variant_data = VariantData::new(struct_def.flavor()); 50 let variant_data = VariantData::new(struct_def.kind());
51 let variant_data = Arc::new(variant_data); 51 let variant_data = Arc::new(variant_data);
52 StructData { name, variant_data } 52 StructData { name, variant_data }
53 } 53 }
@@ -94,7 +94,7 @@ impl EnumData {
94 let variants = variants(&*enum_def) 94 let variants = variants(&*enum_def)
95 .map(|var| EnumVariantData { 95 .map(|var| EnumVariantData {
96 name: var.name().map(|it| it.as_name()), 96 name: var.name().map(|it| it.as_name()),
97 variant_data: Arc::new(VariantData::new(var.flavor())), 97 variant_data: Arc::new(VariantData::new(var.kind())),
98 }) 98 })
99 .collect(); 99 .collect();
100 Arc::new(EnumData { name, variants }) 100 Arc::new(EnumData { name, variants })
@@ -143,9 +143,9 @@ impl VariantData {
143} 143}
144 144
145impl VariantData { 145impl VariantData {
146 fn new(flavor: StructFlavor) -> Self { 146 fn new(flavor: StructKind) -> Self {
147 let inner = match flavor { 147 let inner = match flavor {
148 ast::StructFlavor::Tuple(fl) => { 148 ast::StructKind::Tuple(fl) => {
149 let fields = fl 149 let fields = fl
150 .fields() 150 .fields()
151 .enumerate() 151 .enumerate()
@@ -156,7 +156,7 @@ impl VariantData {
156 .collect(); 156 .collect();
157 VariantDataInner::Tuple(fields) 157 VariantDataInner::Tuple(fields)
158 } 158 }
159 ast::StructFlavor::Named(fl) => { 159 ast::StructKind::Named(fl) => {
160 let fields = fl 160 let fields = fl
161 .fields() 161 .fields()
162 .map(|fd| StructFieldData { 162 .map(|fd| StructFieldData {
@@ -166,7 +166,7 @@ impl VariantData {
166 .collect(); 166 .collect();
167 VariantDataInner::Struct(fields) 167 VariantDataInner::Struct(fields)
168 } 168 }
169 ast::StructFlavor::Unit => VariantDataInner::Unit, 169 ast::StructKind::Unit => VariantDataInner::Unit,
170 }; 170 };
171 VariantData(inner) 171 VariantData(inner)
172 } 172 }
@@ -200,27 +200,27 @@ impl StructField {
200 let fields = var_data.fields().unwrap(); 200 let fields = var_data.fields().unwrap();
201 let ss; 201 let ss;
202 let es; 202 let es;
203 let (file_id, struct_flavor) = match self.parent { 203 let (file_id, struct_kind) = match self.parent {
204 VariantDef::Struct(s) => { 204 VariantDef::Struct(s) => {
205 let (file_id, source) = s.source(db); 205 let (file_id, source) = s.source(db);
206 ss = source; 206 ss = source;
207 (file_id, ss.flavor()) 207 (file_id, ss.kind())
208 } 208 }
209 VariantDef::EnumVariant(e) => { 209 VariantDef::EnumVariant(e) => {
210 let (file_id, source) = e.source(db); 210 let (file_id, source) = e.source(db);
211 es = source; 211 es = source;
212 (file_id, es.flavor()) 212 (file_id, es.kind())
213 } 213 }
214 }; 214 };
215 215
216 let field_sources = match struct_flavor { 216 let field_sources = match struct_kind {
217 ast::StructFlavor::Tuple(fl) => { 217 ast::StructKind::Tuple(fl) => {
218 fl.fields().map(|it| FieldSource::Pos(it.to_owned())).collect() 218 fl.fields().map(|it| FieldSource::Pos(it.to_owned())).collect()
219 } 219 }
220 ast::StructFlavor::Named(fl) => { 220 ast::StructKind::Named(fl) => {
221 fl.fields().map(|it| FieldSource::Named(it.to_owned())).collect() 221 fl.fields().map(|it| FieldSource::Named(it.to_owned())).collect()
222 } 222 }
223 ast::StructFlavor::Unit => Vec::new(), 223 ast::StructKind::Unit => Vec::new(),
224 }; 224 };
225 let field = field_sources 225 let field = field_sources
226 .into_iter() 226 .into_iter()
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 624c25c4d..9e6170440 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -4,7 +4,7 @@ use ra_db::{CrateId, SourceRootId, Edition};
4use ra_syntax::{ast::self, TreeArc}; 4use ra_syntax::{ast::self, TreeArc};
5 5
6use crate::{ 6use crate::{
7 Name, ScopesWithSourceMap, Ty, HirFileId, 7 Name, ScopesWithSourceMap, Ty, HirFileId, ImportSource,
8 HirDatabase, DefDatabase, 8 HirDatabase, DefDatabase,
9 type_ref::TypeRef, 9 type_ref::TypeRef,
10 nameres::{ModuleScope, Namespace, ImportId, CrateModuleId}, 10 nameres::{ModuleScope, Namespace, ImportId, CrateModuleId},
@@ -117,11 +117,7 @@ impl Module {
117 } 117 }
118 118
119 /// Returns the syntax of the last path segment corresponding to this import 119 /// Returns the syntax of the last path segment corresponding to this import
120 pub fn import_source( 120 pub fn import_source(&self, db: &impl HirDatabase, import: ImportId) -> ImportSource {
121 &self,
122 db: &impl HirDatabase,
123 import: ImportId,
124 ) -> TreeArc<ast::PathSegment> {
125 self.import_source_impl(db, import) 121 self.import_source_impl(db, import)
126 } 122 }
127 123
@@ -433,6 +429,45 @@ impl Docs for EnumVariant {
433 } 429 }
434} 430}
435 431
432/// The defs which have a body.
433#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
434pub enum DefWithBody {
435 Function(Function),
436 Const(Const),
437 Static(Static),
438}
439
440impl_froms!(DefWithBody: Function, Const, Static);
441
442impl DefWithBody {
443 pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> {
444 db.infer(*self)
445 }
446
447 pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
448 db.body_with_source_map(*self).1
449 }
450
451 pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> {
452 db.body_hir(*self)
453 }
454
455 /// Builds a resolver for code inside this item.
456 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
457 match *self {
458 DefWithBody::Const(ref c) => c.resolver(db),
459 DefWithBody::Function(ref f) => f.resolver(db),
460 DefWithBody::Static(ref s) => s.resolver(db),
461 }
462 }
463
464 pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap {
465 let scopes = db.expr_scopes(*self);
466 let source_map = db.body_with_source_map(*self).1;
467 ScopesWithSourceMap { scopes, source_map }
468 }
469}
470
436#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 471#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
437pub struct Function { 472pub struct Function {
438 pub(crate) id: FunctionId, 473 pub(crate) id: FunctionId,
@@ -483,11 +518,11 @@ impl Function {
483 } 518 }
484 519
485 pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { 520 pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
486 db.body_with_source_map(*self).1 521 db.body_with_source_map((*self).into()).1
487 } 522 }
488 523
489 pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { 524 pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> {
490 db.body_hir(*self) 525 db.body_hir((*self).into())
491 } 526 }
492 527
493 pub fn ty(&self, db: &impl HirDatabase) -> Ty { 528 pub fn ty(&self, db: &impl HirDatabase) -> Ty {
@@ -495,8 +530,8 @@ impl Function {
495 } 530 }
496 531
497 pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { 532 pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap {
498 let scopes = db.expr_scopes(*self); 533 let scopes = db.expr_scopes((*self).into());
499 let source_map = db.body_with_source_map(*self).1; 534 let source_map = db.body_with_source_map((*self).into()).1;
500 ScopesWithSourceMap { scopes, source_map } 535 ScopesWithSourceMap { scopes, source_map }
501 } 536 }
502 537
@@ -505,7 +540,7 @@ impl Function {
505 } 540 }
506 541
507 pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { 542 pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> {
508 db.infer(*self) 543 db.infer((*self).into())
509 } 544 }
510 545
511 pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { 546 pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> {
@@ -561,6 +596,14 @@ impl Const {
561 db.const_signature(*self) 596 db.const_signature(*self)
562 } 597 }
563 598
599 pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> {
600 db.infer((*self).into())
601 }
602
603 pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
604 db.body_with_source_map((*self).into()).1
605 }
606
564 /// The containing impl block, if this is a method. 607 /// The containing impl block, if this is a method.
565 pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { 608 pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> {
566 let module_impls = db.impls_in_module(self.module(db)); 609 let module_impls = db.impls_in_module(self.module(db));
@@ -625,6 +668,14 @@ impl Static {
625 // take the outer scope... 668 // take the outer scope...
626 self.module(db).resolver(db) 669 self.module(db).resolver(db)
627 } 670 }
671
672 pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> {
673 db.infer((*self).into())
674 }
675
676 pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
677 db.body_with_source_map((*self).into()).1
678 }
628} 679}
629 680
630impl Docs for Static { 681impl Docs for Static {
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs
index 334cb302b..f8bd0f784 100644
--- a/crates/ra_hir/src/code_model_impl/function.rs
+++ b/crates/ra_hir/src/code_model_impl/function.rs
@@ -20,12 +20,12 @@ impl FnSignature {
20 TypeRef::from_ast(type_ref) 20 TypeRef::from_ast(type_ref)
21 } else { 21 } else {
22 let self_type = TypeRef::Path(Name::self_type().into()); 22 let self_type = TypeRef::Path(Name::self_type().into());
23 match self_param.flavor() { 23 match self_param.kind() {
24 ast::SelfParamFlavor::Owned => self_type, 24 ast::SelfParamKind::Owned => self_type,
25 ast::SelfParamFlavor::Ref => { 25 ast::SelfParamKind::Ref => {
26 TypeRef::Reference(Box::new(self_type), Mutability::Shared) 26 TypeRef::Reference(Box::new(self_type), Mutability::Shared)
27 } 27 }
28 ast::SelfParamFlavor::MutRef => { 28 ast::SelfParamKind::MutRef => {
29 TypeRef::Reference(Box::new(self_type), Mutability::Mut) 29 TypeRef::Reference(Box::new(self_type), Mutability::Mut)
30 } 30 }
31 } 31 }
diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs
index 0edb8ade5..88dee3a69 100644
--- a/crates/ra_hir/src/code_model_impl/module.rs
+++ b/crates/ra_hir/src/code_model_impl/module.rs
@@ -5,7 +5,7 @@ use crate::{
5 Module, ModuleSource, Name, AstId, 5 Module, ModuleSource, Name, AstId,
6 nameres::{CrateModuleId, ImportId}, 6 nameres::{CrateModuleId, ImportId},
7 HirDatabase, DefDatabase, 7 HirDatabase, DefDatabase,
8 HirFileId, 8 HirFileId, ImportSource,
9}; 9};
10 10
11impl ModuleSource { 11impl ModuleSource {
@@ -72,7 +72,7 @@ impl Module {
72 &self, 72 &self,
73 db: &impl HirDatabase, 73 db: &impl HirDatabase,
74 import: ImportId, 74 import: ImportId,
75 ) -> TreeArc<ast::PathSegment> { 75 ) -> ImportSource {
76 let (file_id, source) = self.definition_source(db); 76 let (file_id, source) = self.definition_source(db);
77 let (_, source_map) = db.raw_items_with_source_map(file_id); 77 let (_, source_map) = db.raw_items_with_source_map(file_id);
78 source_map.get(&source, import) 78 source_map.get(&source, import)
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 147005848..be8a8c98b 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -8,6 +8,7 @@ use crate::{
8 Function, FnSignature, ExprScopes, TypeAlias, 8 Function, FnSignature, ExprScopes, TypeAlias,
9 Struct, Enum, StructField, 9 Struct, Enum, StructField,
10 Const, ConstSignature, Static, 10 Const, ConstSignature, Static,
11 DefWithBody,
11 nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, 12 nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap},
12 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, 13 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig},
13 adt::{StructData, EnumData}, 14 adt::{StructData, EnumData},
@@ -83,10 +84,10 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> {
83#[salsa::query_group(HirDatabaseStorage)] 84#[salsa::query_group(HirDatabaseStorage)]
84pub trait HirDatabase: DefDatabase { 85pub trait HirDatabase: DefDatabase {
85 #[salsa::invoke(ExprScopes::expr_scopes_query)] 86 #[salsa::invoke(ExprScopes::expr_scopes_query)]
86 fn expr_scopes(&self, func: Function) -> Arc<ExprScopes>; 87 fn expr_scopes(&self, def: DefWithBody) -> Arc<ExprScopes>;
87 88
88 #[salsa::invoke(crate::ty::infer)] 89 #[salsa::invoke(crate::ty::infer)]
89 fn infer(&self, func: Function) -> Arc<InferenceResult>; 90 fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>;
90 91
91 #[salsa::invoke(crate::ty::type_for_def)] 92 #[salsa::invoke(crate::ty::type_for_def)]
92 fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty; 93 fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty;
@@ -100,11 +101,11 @@ pub trait HirDatabase: DefDatabase {
100 #[salsa::invoke(crate::expr::body_with_source_map_query)] 101 #[salsa::invoke(crate::expr::body_with_source_map_query)]
101 fn body_with_source_map( 102 fn body_with_source_map(
102 &self, 103 &self,
103 func: Function, 104 def: DefWithBody,
104 ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); 105 ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>);
105 106
106 #[salsa::invoke(crate::expr::body_hir_query)] 107 #[salsa::invoke(crate::expr::body_hir_query)]
107 fn body_hir(&self, func: Function) -> Arc<crate::expr::Body>; 108 fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>;
108 109
109 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] 110 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
110 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; 111 fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index a85422955..b2a237ece 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -6,11 +6,11 @@ use rustc_hash::FxHashMap;
6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; 6use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
7use ra_syntax::{ 7use ra_syntax::{
8 SyntaxNodePtr, AstPtr, AstNode, 8 SyntaxNodePtr, AstPtr, AstNode,
9 ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor, TypeAscriptionOwner} 9 ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralKind, TypeAscriptionOwner}
10}; 10};
11 11
12use crate::{ 12use crate::{
13 Path, Name, HirDatabase, Function, Resolver, 13 Path, Name, HirDatabase, Resolver,DefWithBody,
14 name::AsName, 14 name::AsName,
15 type_ref::{Mutability, TypeRef}, 15 type_ref::{Mutability, TypeRef},
16}; 16};
@@ -27,9 +27,8 @@ impl_arena_id!(ExprId);
27/// The body of an item (function, const etc.). 27/// The body of an item (function, const etc.).
28#[derive(Debug, Eq, PartialEq)] 28#[derive(Debug, Eq, PartialEq)]
29pub struct Body { 29pub struct Body {
30 // FIXME: this should be more general, consts & statics also have bodies 30 /// The def of the item this body belongs to
31 /// The Function of the item this body belongs to 31 owner: DefWithBody,
32 owner: Function,
33 exprs: Arena<ExprId, Expr>, 32 exprs: Arena<ExprId, Expr>,
34 pats: Arena<PatId, Pat>, 33 pats: Arena<PatId, Pat>,
35 /// The patterns for the function's parameters. While the parameter types are 34 /// The patterns for the function's parameters. While the parameter types are
@@ -66,7 +65,7 @@ impl Body {
66 self.body_expr 65 self.body_expr
67 } 66 }
68 67
69 pub fn owner(&self) -> Function { 68 pub fn owner(&self) -> DefWithBody {
70 self.owner 69 self.owner
71 } 70 }
72 71
@@ -463,8 +462,8 @@ impl Pat {
463 462
464// Queries 463// Queries
465 464
466struct ExprCollector { 465pub(crate) struct ExprCollector {
467 owner: Function, 466 owner: DefWithBody,
468 exprs: Arena<ExprId, Expr>, 467 exprs: Arena<ExprId, Expr>,
469 pats: Arena<PatId, Pat>, 468 pats: Arena<PatId, Pat>,
470 source_map: BodySourceMap, 469 source_map: BodySourceMap,
@@ -473,7 +472,7 @@ struct ExprCollector {
473} 472}
474 473
475impl ExprCollector { 474impl ExprCollector {
476 fn new(owner: Function) -> Self { 475 fn new(owner: DefWithBody) -> Self {
477 ExprCollector { 476 ExprCollector {
478 owner, 477 owner,
479 exprs: Arena::default(), 478 exprs: Arena::default(),
@@ -516,8 +515,8 @@ impl ExprCollector {
516 let else_branch = e 515 let else_branch = e
517 .else_branch() 516 .else_branch()
518 .map(|b| match b { 517 .map(|b| match b {
519 ast::ElseBranchFlavor::Block(it) => self.collect_block(it), 518 ast::ElseBranch::Block(it) => self.collect_block(it),
520 ast::ElseBranchFlavor::IfExpr(elif) => { 519 ast::ElseBranch::IfExpr(elif) => {
521 let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap(); 520 let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap();
522 self.collect_expr(expr) 521 self.collect_expr(expr)
523 } 522 }
@@ -533,8 +532,8 @@ impl ExprCollector {
533 let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); 532 let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
534 let then_branch = self.collect_block_opt(e.then_branch()); 533 let then_branch = self.collect_block_opt(e.then_branch());
535 let else_branch = e.else_branch().map(|b| match b { 534 let else_branch = e.else_branch().map(|b| match b {
536 ast::ElseBranchFlavor::Block(it) => self.collect_block(it), 535 ast::ElseBranch::Block(it) => self.collect_block(it),
537 ast::ElseBranchFlavor::IfExpr(elif) => { 536 ast::ElseBranch::IfExpr(elif) => {
538 let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap(); 537 let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap();
539 self.collect_expr(expr) 538 self.collect_expr(expr)
540 } 539 }
@@ -726,14 +725,8 @@ impl ExprCollector {
726 self.alloc_expr(Expr::Array { exprs }, syntax_ptr) 725 self.alloc_expr(Expr::Array { exprs }, syntax_ptr)
727 } 726 }
728 ast::ExprKind::Literal(e) => { 727 ast::ExprKind::Literal(e) => {
729 let child = if let Some(child) = e.literal_expr() { 728 let lit = match e.kind() {
730 child 729 LiteralKind::IntNumber { suffix } => {
731 } else {
732 return self.alloc_expr(Expr::Missing, syntax_ptr);
733 };
734
735 let lit = match child.flavor() {
736 LiteralFlavor::IntNumber { suffix } => {
737 let known_name = suffix 730 let known_name = suffix
738 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known)); 731 .and_then(|it| IntTy::from_suffix(&it).map(UncertainIntTy::Known));
739 732
@@ -742,7 +735,7 @@ impl ExprCollector {
742 known_name.unwrap_or(UncertainIntTy::Unknown), 735 known_name.unwrap_or(UncertainIntTy::Unknown),
743 ) 736 )
744 } 737 }
745 LiteralFlavor::FloatNumber { suffix } => { 738 LiteralKind::FloatNumber { suffix } => {
746 let known_name = suffix 739 let known_name = suffix
747 .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known)); 740 .and_then(|it| FloatTy::from_suffix(&it).map(UncertainFloatTy::Known));
748 741
@@ -751,13 +744,13 @@ impl ExprCollector {
751 known_name.unwrap_or(UncertainFloatTy::Unknown), 744 known_name.unwrap_or(UncertainFloatTy::Unknown),
752 ) 745 )
753 } 746 }
754 LiteralFlavor::ByteString => Literal::ByteString(Default::default()), 747 LiteralKind::ByteString => Literal::ByteString(Default::default()),
755 LiteralFlavor::String => Literal::String(Default::default()), 748 LiteralKind::String => Literal::String(Default::default()),
756 LiteralFlavor::Byte => { 749 LiteralKind::Byte => {
757 Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8())) 750 Literal::Int(Default::default(), UncertainIntTy::Known(IntTy::u8()))
758 } 751 }
759 LiteralFlavor::Bool => Literal::Bool(Default::default()), 752 LiteralKind::Bool => Literal::Bool(Default::default()),
760 LiteralFlavor::Char => Literal::Char(Default::default()), 753 LiteralKind::Char => Literal::Char(Default::default()),
761 }; 754 };
762 self.alloc_expr(Expr::Literal(lit), syntax_ptr) 755 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
763 } 756 }
@@ -766,6 +759,7 @@ impl ExprCollector {
766 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 759 ast::ExprKind::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
767 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 760 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
768 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 761 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
762 ast::ExprKind::MacroCall(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
769 } 763 }
770 } 764 }
771 765
@@ -871,12 +865,20 @@ impl ExprCollector {
871 } 865 }
872 } 866 }
873 867
868 fn collect_const_body(&mut self, node: &ast::ConstDef) {
869 let body = self.collect_expr_opt(node.body());
870 self.body_expr = Some(body);
871 }
872
873 fn collect_static_body(&mut self, node: &ast::StaticDef) {
874 let body = self.collect_expr_opt(node.body());
875 self.body_expr = Some(body);
876 }
877
874 fn collect_fn_body(&mut self, node: &ast::FnDef) { 878 fn collect_fn_body(&mut self, node: &ast::FnDef) {
875 if let Some(param_list) = node.param_list() { 879 if let Some(param_list) = node.param_list() {
876 if let Some(self_param) = param_list.self_param() { 880 if let Some(self_param) = param_list.self_param() {
877 let self_param = SyntaxNodePtr::new( 881 let self_param = SyntaxNodePtr::new(self_param.syntax());
878 self_param.self_kw().expect("self param without self keyword").syntax(),
879 );
880 let param_pat = self.alloc_pat( 882 let param_pat = self.alloc_pat(
881 Pat::Bind { 883 Pat::Bind {
882 name: Name::self_param(), 884 name: Name::self_param(),
@@ -917,24 +919,20 @@ impl ExprCollector {
917 919
918pub(crate) fn body_with_source_map_query( 920pub(crate) fn body_with_source_map_query(
919 db: &impl HirDatabase, 921 db: &impl HirDatabase,
920 func: Function, 922 def: DefWithBody,
921) -> (Arc<Body>, Arc<BodySourceMap>) { 923) -> (Arc<Body>, Arc<BodySourceMap>) {
922 let mut collector = ExprCollector::new(func); 924 let mut collector = ExprCollector::new(def);
923 925
924 // FIXME: consts, etc. 926 match def {
925 collector.collect_fn_body(&func.source(db).1); 927 DefWithBody::Const(ref c) => collector.collect_const_body(&c.source(db).1),
928 DefWithBody::Function(ref f) => collector.collect_fn_body(&f.source(db).1),
929 DefWithBody::Static(ref s) => collector.collect_static_body(&s.source(db).1),
930 }
926 931
927 let (body, source_map) = collector.finish(); 932 let (body, source_map) = collector.finish();
928 (Arc::new(body), Arc::new(source_map)) 933 (Arc::new(body), Arc::new(source_map))
929} 934}
930 935
931pub(crate) fn body_hir_query(db: &impl HirDatabase, func: Function) -> Arc<Body> { 936pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> {
932 db.body_with_source_map(func).0 937 db.body_with_source_map(def).0
933}
934
935#[cfg(test)]
936fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> (Body, BodySourceMap) {
937 let mut collector = ExprCollector::new(function);
938 collector.collect_fn_body(node);
939 collector.finish()
940} 938}
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs
index ed005c9f7..48283907b 100644
--- a/crates/ra_hir/src/expr/scope.rs
+++ b/crates/ra_hir/src/expr/scope.rs
@@ -10,7 +10,7 @@ use ra_syntax::{
10use ra_arena::{Arena, RawId, impl_arena_id}; 10use ra_arena::{Arena, RawId, impl_arena_id};
11 11
12use crate::{ 12use crate::{
13 Name, AsName, Function, 13 Name, AsName,DefWithBody,
14 expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, 14 expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap},
15 HirDatabase, 15 HirDatabase,
16}; 16};
@@ -40,8 +40,8 @@ pub struct ScopeData {
40 40
41impl ExprScopes { 41impl ExprScopes {
42 // FIXME: This should take something more general than Function 42 // FIXME: This should take something more general than Function
43 pub(crate) fn expr_scopes_query(db: &impl HirDatabase, function: Function) -> Arc<ExprScopes> { 43 pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> {
44 let body = db.body_hir(function); 44 let body = db.body_hir(def);
45 let res = ExprScopes::new(body); 45 let res = ExprScopes::new(body);
46 Arc::new(res) 46 Arc::new(res)
47 } 47 }
@@ -297,8 +297,9 @@ mod tests {
297 use ra_syntax::{SourceFile, algo::find_node_at_offset}; 297 use ra_syntax::{SourceFile, algo::find_node_at_offset};
298 use test_utils::{extract_offset, assert_eq_text}; 298 use test_utils::{extract_offset, assert_eq_text};
299 use ra_arena::ArenaId; 299 use ra_arena::ArenaId;
300 use crate::Function;
300 301
301 use crate::expr; 302 use crate::expr::{ExprCollector};
302 303
303 use super::*; 304 use super::*;
304 305
@@ -316,7 +317,7 @@ mod tests {
316 let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 317 let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
317 let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 318 let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
318 let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; 319 let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) };
319 let (body, source_map) = expr::collect_fn_body_syntax(irrelevant_function, fn_def); 320 let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def);
320 let scopes = ExprScopes::new(Arc::new(body)); 321 let scopes = ExprScopes::new(Arc::new(body));
321 let scopes = 322 let scopes =
322 ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; 323 ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) };
@@ -405,6 +406,12 @@ mod tests {
405 ); 406 );
406 } 407 }
407 408
409 fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> (Body, BodySourceMap) {
410 let mut collector = ExprCollector::new(DefWithBody::Function(function));
411 collector.collect_fn_body(node);
412 collector.finish()
413 }
414
408 fn do_check_local_name(code: &str, expected_offset: u32) { 415 fn do_check_local_name(code: &str, expected_offset: u32) {
409 let (off, code) = extract_offset(code); 416 let (off, code) = extract_offset(code);
410 let file = SourceFile::parse(&code); 417 let file = SourceFile::parse(&code);
@@ -415,7 +422,7 @@ mod tests {
415 let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 422 let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
416 423
417 let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; 424 let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) };
418 let (body, source_map) = expr::collect_fn_body_syntax(irrelevant_function, fn_def); 425 let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def);
419 let scopes = ExprScopes::new(Arc::new(body)); 426 let scopes = ExprScopes::new(Arc::new(body));
420 let scopes = 427 let scopes =
421 ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; 428 ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) };
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 7c603bbd3..c19450f39 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -56,7 +56,7 @@ pub use self::{
56 name::Name, 56 name::Name,
57 source_id::{AstIdMap, ErasedFileAstId}, 57 source_id::{AstIdMap, ErasedFileAstId},
58 ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner}, 58 ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner},
59 nameres::{PerNs, Namespace}, 59 nameres::{PerNs, Namespace, ImportId, ImportSource},
60 ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, 60 ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay},
61 impl_block::{ImplBlock, ImplItem}, 61 impl_block::{ImplBlock, ImplItem},
62 docs::{Docs, Documentation}, 62 docs::{Docs, Documentation},
@@ -67,6 +67,7 @@ pub use self::{
67 67
68pub use self::code_model_api::{ 68pub use self::code_model_api::{
69 Crate, CrateDependency, 69 Crate, CrateDependency,
70 DefWithBody,
70 Module, ModuleDef, ModuleSource, 71 Module, ModuleDef, ModuleSource,
71 Struct, Enum, EnumVariant, 72 Struct, Enum, EnumVariant,
72 Function, FnSignature, 73 Function, FnSignature,
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 8adc6d368..4ae04514a 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -71,9 +71,12 @@ use crate::{
71 AstId, 71 AstId,
72}; 72};
73 73
74pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; 74pub(crate) use self::raw::{RawItems, ImportSourceMap};
75 75
76pub use self::per_ns::{PerNs, Namespace}; 76pub use self::{
77 per_ns::{PerNs, Namespace},
78 raw::{ImportId, ImportSource},
79};
77 80
78/// Contans all top-level defs from a macro-expanded crate 81/// Contans all top-level defs from a macro-expanded crate
79#[derive(Debug, PartialEq, Eq)] 82#[derive(Debug, PartialEq, Eq)]
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index 0936229ac..b7416ede6 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -31,21 +31,43 @@ pub struct RawItems {
31 31
32#[derive(Debug, Default, PartialEq, Eq)] 32#[derive(Debug, Default, PartialEq, Eq)]
33pub struct ImportSourceMap { 33pub struct ImportSourceMap {
34 map: ArenaMap<ImportId, AstPtr<ast::PathSegment>>, 34 map: ArenaMap<ImportId, ImportSourcePtr>,
35}
36
37#[derive(Debug, PartialEq, Eq, Clone, Copy)]
38enum ImportSourcePtr {
39 UseTree(AstPtr<ast::UseTree>),
40 ExternCrate(AstPtr<ast::ExternCrateItem>),
41}
42
43impl ImportSourcePtr {
44 fn to_node(self, file: &SourceFile) -> ImportSource {
45 match self {
46 ImportSourcePtr::UseTree(ptr) => ImportSource::UseTree(ptr.to_node(file).to_owned()),
47 ImportSourcePtr::ExternCrate(ptr) => {
48 ImportSource::ExternCrate(ptr.to_node(file).to_owned())
49 }
50 }
51 }
52}
53
54pub enum ImportSource {
55 UseTree(TreeArc<ast::UseTree>),
56 ExternCrate(TreeArc<ast::ExternCrateItem>),
35} 57}
36 58
37impl ImportSourceMap { 59impl ImportSourceMap {
38 fn insert(&mut self, import: ImportId, segment: &ast::PathSegment) { 60 fn insert(&mut self, import: ImportId, ptr: ImportSourcePtr) {
39 self.map.insert(import, AstPtr::new(segment)) 61 self.map.insert(import, ptr)
40 } 62 }
41 63
42 pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> TreeArc<ast::PathSegment> { 64 pub(crate) fn get(&self, source: &ModuleSource, import: ImportId) -> ImportSource {
43 let file = match source { 65 let file = match source {
44 ModuleSource::SourceFile(file) => &*file, 66 ModuleSource::SourceFile(file) => &*file,
45 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(), 67 ModuleSource::Module(m) => m.syntax().ancestors().find_map(SourceFile::cast).unwrap(),
46 }; 68 };
47 69
48 self.map[import].to_node(file).to_owned() 70 self.map[import].to_node(file)
49 } 71 }
50} 72}
51 73
@@ -256,18 +278,14 @@ impl RawItemsCollector {
256 fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) { 278 fn add_use_item(&mut self, current_module: Option<Module>, use_item: &ast::UseItem) {
257 let is_prelude = use_item.has_atom_attr("prelude_import"); 279 let is_prelude = use_item.has_atom_attr("prelude_import");
258 280
259 Path::expand_use_item(use_item, |path, segment, alias| { 281 Path::expand_use_item(use_item, |path, use_tree, is_glob, alias| {
260 let import = self.raw_items.imports.alloc(ImportData { 282 let import_data =
261 path, 283 ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false };
262 alias, 284 self.push_import(
263 is_glob: segment.is_none(), 285 current_module,
264 is_prelude, 286 import_data,
265 is_extern_crate: false, 287 ImportSourcePtr::UseTree(AstPtr::new(use_tree)),
266 }); 288 );
267 if let Some(segment) = segment {
268 self.source_map.insert(import, segment)
269 }
270 self.push_item(current_module, RawItem::Import(import))
271 }) 289 })
272 } 290 }
273 291
@@ -279,14 +297,18 @@ impl RawItemsCollector {
279 if let Some(name_ref) = extern_crate.name_ref() { 297 if let Some(name_ref) = extern_crate.name_ref() {
280 let path = Path::from_name_ref(name_ref); 298 let path = Path::from_name_ref(name_ref);
281 let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name); 299 let alias = extern_crate.alias().and_then(|a| a.name()).map(AsName::as_name);
282 let import = self.raw_items.imports.alloc(ImportData { 300 let import_data = ImportData {
283 path, 301 path,
284 alias, 302 alias,
285 is_glob: false, 303 is_glob: false,
286 is_prelude: false, 304 is_prelude: false,
287 is_extern_crate: true, 305 is_extern_crate: true,
288 }); 306 };
289 self.push_item(current_module, RawItem::Import(import)) 307 self.push_import(
308 current_module,
309 import_data,
310 ImportSourcePtr::ExternCrate(AstPtr::new(extern_crate)),
311 );
290 } 312 }
291 } 313 }
292 314
@@ -303,6 +325,17 @@ impl RawItemsCollector {
303 self.push_item(current_module, RawItem::Macro(m)); 325 self.push_item(current_module, RawItem::Macro(m));
304 } 326 }
305 327
328 fn push_import(
329 &mut self,
330 current_module: Option<Module>,
331 data: ImportData,
332 source: ImportSourcePtr,
333 ) {
334 let import = self.raw_items.imports.alloc(data);
335 self.source_map.insert(import, source);
336 self.push_item(current_module, RawItem::Import(import))
337 }
338
306 fn push_item(&mut self, current_module: Option<Module>, item: RawItem) { 339 fn push_item(&mut self, current_module: Option<Module>, item: RawItem) {
307 match current_module { 340 match current_module {
308 Some(module) => match &mut self.raw_items.modules[module] { 341 Some(module) => match &mut self.raw_items.modules[module] {
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 6cc8104f4..5449cddfd 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -46,7 +46,7 @@ impl Path {
46 /// Calls `cb` with all paths, represented by this use item. 46 /// Calls `cb` with all paths, represented by this use item.
47 pub fn expand_use_item<'a>( 47 pub fn expand_use_item<'a>(
48 item: &'a ast::UseItem, 48 item: &'a ast::UseItem,
49 mut cb: impl FnMut(Path, Option<&'a ast::PathSegment>, Option<Name>), 49 mut cb: impl FnMut(Path, &'a ast::UseTree, bool, Option<Name>),
50 ) { 50 ) {
51 if let Some(tree) = item.use_tree() { 51 if let Some(tree) = item.use_tree() {
52 expand_use_tree(None, tree, &mut cb); 52 expand_use_tree(None, tree, &mut cb);
@@ -156,7 +156,7 @@ impl From<Name> for Path {
156fn expand_use_tree<'a>( 156fn expand_use_tree<'a>(
157 prefix: Option<Path>, 157 prefix: Option<Path>,
158 tree: &'a ast::UseTree, 158 tree: &'a ast::UseTree,
159 cb: &mut impl FnMut(Path, Option<&'a ast::PathSegment>, Option<Name>), 159 cb: &mut impl FnMut(Path, &'a ast::UseTree, bool, Option<Name>),
160) { 160) {
161 if let Some(use_tree_list) = tree.use_tree_list() { 161 if let Some(use_tree_list) = tree.use_tree_list() {
162 let prefix = match tree.path() { 162 let prefix = match tree.path() {
@@ -181,18 +181,15 @@ fn expand_use_tree<'a>(
181 if let Some(segment) = ast_path.segment() { 181 if let Some(segment) = ast_path.segment() {
182 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) { 182 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
183 if let Some(prefix) = prefix { 183 if let Some(prefix) = prefix {
184 cb(prefix, Some(segment), alias); 184 cb(prefix, tree, false, alias);
185 return; 185 return;
186 } 186 }
187 } 187 }
188 } 188 }
189 } 189 }
190 if let Some(path) = convert_path(prefix, ast_path) { 190 if let Some(path) = convert_path(prefix, ast_path) {
191 if tree.has_star() { 191 let is_glob = tree.has_star();
192 cb(path, None, alias) 192 cb(path, tree, is_glob, alias)
193 } else if let Some(segment) = ast_path.segment() {
194 cb(path, Some(segment), alias)
195 };
196 } 193 }
197 // FIXME: report errors somewhere 194 // FIXME: report errors somewhere
198 // We get here if we do 195 // We get here if we do
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 9dae4c3d1..182ed4c91 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -9,11 +9,11 @@ use ra_db::{FileId, FilePosition};
9use ra_syntax::{ 9use ra_syntax::{
10 SyntaxNode, 10 SyntaxNode,
11 ast::{self, AstNode, NameOwner}, 11 ast::{self, AstNode, NameOwner},
12 algo::{find_node_at_offset, find_leaf_at_offset}, 12 algo::{find_node_at_offset, find_token_at_offset},
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Function, Struct, Enum, 16 HirDatabase, Function, Struct, Enum,Const,Static,
17 AsName, Module, HirFileId, Crate, Trait, Resolver, 17 AsName, Module, HirFileId, Crate, Trait, Resolver,
18 ids::LocationCtx, 18 ids::LocationCtx,
19 expr, AstId 19 expr, AstId
@@ -87,6 +87,27 @@ fn module_from_source(
87 ) 87 )
88} 88}
89 89
90pub fn const_from_source(
91 db: &impl HirDatabase,
92 file_id: FileId,
93 const_def: &ast::ConstDef,
94) -> Option<Const> {
95 let module = module_from_child_node(db, file_id, const_def.syntax())?;
96 let res = const_from_module(db, module, const_def);
97 Some(res)
98}
99
100pub fn const_from_module(
101 db: &impl HirDatabase,
102 module: Module,
103 const_def: &ast::ConstDef,
104) -> Const {
105 let (file_id, _) = module.definition_source(db);
106 let file_id = file_id.into();
107 let ctx = LocationCtx::new(db, module, file_id);
108 Const { id: ctx.to_def(const_def) }
109}
110
90pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { 111pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> {
91 let file = db.parse(position.file_id); 112 let file = db.parse(position.file_id);
92 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; 113 let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?;
@@ -134,6 +155,27 @@ pub fn struct_from_module(
134 Struct { id: ctx.to_def(struct_def) } 155 Struct { id: ctx.to_def(struct_def) }
135} 156}
136 157
158pub fn static_from_source(
159 db: &impl HirDatabase,
160 file_id: FileId,
161 static_def: &ast::StaticDef,
162) -> Option<Static> {
163 let module = module_from_child_node(db, file_id, static_def.syntax())?;
164 let res = static_from_module(db, module, static_def);
165 Some(res)
166}
167
168pub fn static_from_module(
169 db: &impl HirDatabase,
170 module: Module,
171 static_def: &ast::StaticDef,
172) -> Static {
173 let (file_id, _) = module.definition_source(db);
174 let file_id = file_id.into();
175 let ctx = LocationCtx::new(db, module, file_id);
176 Static { id: ctx.to_def(static_def) }
177}
178
137pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { 179pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum {
138 let (file_id, _) = module.definition_source(db); 180 let (file_id, _) = module.definition_source(db);
139 let file_id = file_id.into(); 181 let file_id = file_id.into();
@@ -155,9 +197,9 @@ pub fn trait_from_module(
155pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver { 197pub fn resolver_for_position(db: &impl HirDatabase, position: FilePosition) -> Resolver {
156 let file_id = position.file_id; 198 let file_id = position.file_id;
157 let file = db.parse(file_id); 199 let file = db.parse(file_id);
158 find_leaf_at_offset(file.syntax(), position.offset) 200 find_token_at_offset(file.syntax(), position.offset)
159 .find_map(|node| { 201 .find_map(|token| {
160 node.ancestors().find_map(|node| { 202 token.parent().ancestors().find_map(|node| {
161 if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() { 203 if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() {
162 if let Some(func) = function_from_child_node(db, file_id, node) { 204 if let Some(func) = function_from_child_node(db, file_id, node) {
163 let scopes = func.scopes(db); 205 let scopes = func.scopes(db);
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 573115321..887153484 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -27,8 +27,9 @@ use test_utils::tested_by;
27 27
28use crate::{ 28use crate::{
29 Function, StructField, Path, Name, 29 Function, StructField, Path, Name,
30 FnSignature, AdtDef, 30 FnSignature, AdtDef,ConstSignature,
31 HirDatabase, 31 HirDatabase,
32 DefWithBody,
32 ImplItem, 33 ImplItem,
33 type_ref::{TypeRef, Mutability}, 34 type_ref::{TypeRef, Mutability},
34 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, 35 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self},
@@ -43,14 +44,17 @@ use crate::{
43use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; 44use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor};
44 45
45/// The entry point of type inference. 46/// The entry point of type inference.
46pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { 47pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> {
47 db.check_canceled(); 48 db.check_canceled();
48 let body = func.body(db); 49 let body = def.body(db);
49 let resolver = func.resolver(db); 50 let resolver = def.resolver(db);
50 let mut ctx = InferenceContext::new(db, body, resolver); 51 let mut ctx = InferenceContext::new(db, body, resolver);
51 52
52 let signature = func.signature(db); 53 match def {
53 ctx.collect_fn_signature(&signature); 54 DefWithBody::Const(ref c) => ctx.collect_const_signature(&c.signature(db)),
55 DefWithBody::Function(ref f) => ctx.collect_fn_signature(&f.signature(db)),
56 DefWithBody::Static(ref s) => ctx.collect_const_signature(&s.signature(db)),
57 }
54 58
55 ctx.infer_body(); 59 ctx.infer_body();
56 60
@@ -1142,6 +1146,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1142 ty 1146 ty
1143 } 1147 }
1144 1148
1149 fn collect_const_signature(&mut self, signature: &ConstSignature) {
1150 self.return_ty = self.make_ty(signature.type_ref());
1151 }
1152
1145 fn collect_fn_signature(&mut self, signature: &FnSignature) { 1153 fn collect_fn_signature(&mut self, signature: &FnSignature) {
1146 let body = Arc::clone(&self.body); // avoid borrow checker problem 1154 let body = Arc::clone(&self.body); // avoid borrow checker problem
1147 for (type_ref, pat) in signature.params().iter().zip(body.params()) { 1155 for (type_ref, pat) in signature.params().iter().zip(body.params()) {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 655f3c522..0b7c841df 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -11,6 +11,8 @@ use crate::{
11 source_binder, 11 source_binder,
12 mock::MockDatabase, 12 mock::MockDatabase,
13 ty::display::HirDisplay, 13 ty::display::HirDisplay,
14 ty::InferenceResult,
15 expr::BodySourceMap
14}; 16};
15 17
16// These tests compare the inference results for all expressions in a file 18// These tests compare the inference results for all expressions in a file
@@ -1267,6 +1269,9 @@ fn test() {
1267} 1269}
1268"#), 1270"#),
1269 @r###" 1271 @r###"
1272[52; 53) '1': u32
1273[103; 104) '2': u32
1274[211; 212) '5': u32
1270[227; 305) '{ ...:ID; }': () 1275[227; 305) '{ ...:ID; }': ()
1271[237; 238) 'x': u32 1276[237; 238) 'x': u32
1272[241; 252) 'Struct::FOO': u32 1277[241; 252) 'Struct::FOO': u32
@@ -1855,6 +1860,9 @@ fn test() {
1855} 1860}
1856"#), 1861"#),
1857 @r###" 1862 @r###"
1863[49; 50) '0': u32
1864[80; 83) '101': u32
1865[126; 128) '99': u32
1858[95; 213) '{ ...NST; }': () 1866[95; 213) '{ ...NST; }': ()
1859[138; 139) 'x': {unknown} 1867[138; 139) 'x': {unknown}
1860[142; 153) 'LOCAL_CONST': {unknown} 1868[142; 153) 'LOCAL_CONST': {unknown}
@@ -1881,6 +1889,10 @@ fn test() {
1881} 1889}
1882"#), 1890"#),
1883 @r###" 1891 @r###"
1892[29; 32) '101': u32
1893[70; 73) '101': u32
1894[118; 120) '99': u32
1895[161; 163) '99': u32
1884[85; 280) '{ ...MUT; }': () 1896[85; 280) '{ ...MUT; }': ()
1885[173; 174) 'x': {unknown} 1897[173; 174) 'x': {unknown}
1886[177; 189) 'LOCAL_STATIC': {unknown} 1898[177; 189) 'LOCAL_STATIC': {unknown}
@@ -2212,6 +2224,24 @@ fn test<T: Iterable<Item=u32>>() {
2212 ); 2224 );
2213} 2225}
2214 2226
2227#[test]
2228fn infer_const_body() {
2229 assert_snapshot_matches!(
2230 infer(r#"
2231const A: u32 = 1 + 1;
2232static B: u64 = { let x = 1; x };
2233"#),
2234 @r###"
2235[16; 17) '1': u32
2236[16; 21) '1 + 1': u32
2237[20; 21) '1': u32
2238[39; 55) '{ let ...1; x }': u64
2239[45; 46) 'x': u64
2240[49; 50) '1': u64
2241[52; 53) 'x': u64"###
2242 );
2243}
2244
2215fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2245fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
2216 let func = source_binder::function_from_position(db, pos).unwrap(); 2246 let func = source_binder::function_from_position(db, pos).unwrap();
2217 let body_source_map = func.body_source_map(db); 2247 let body_source_map = func.body_source_map(db);
@@ -2228,11 +2258,11 @@ fn infer(content: &str) -> String {
2228 let source_file = db.parse(file_id); 2258 let source_file = db.parse(file_id);
2229 let mut acc = String::new(); 2259 let mut acc = String::new();
2230 acc.push_str("\n"); 2260 acc.push_str("\n");
2231 for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { 2261
2232 let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); 2262 let mut infer_def = |inference_result: Arc<InferenceResult>,
2233 let inference_result = func.infer(&db); 2263 body_source_map: Arc<BodySourceMap>| {
2234 let body_source_map = func.body_source_map(&db);
2235 let mut types = Vec::new(); 2264 let mut types = Vec::new();
2265
2236 for (pat, ty) in inference_result.type_of_pat.iter() { 2266 for (pat, ty) in inference_result.type_of_pat.iter() {
2237 let syntax_ptr = match body_source_map.pat_syntax(pat) { 2267 let syntax_ptr = match body_source_map.pat_syntax(pat) {
2238 Some(sp) => sp, 2268 Some(sp) => sp,
@@ -2240,6 +2270,7 @@ fn infer(content: &str) -> String {
2240 }; 2270 };
2241 types.push((syntax_ptr, ty)); 2271 types.push((syntax_ptr, ty));
2242 } 2272 }
2273
2243 for (expr, ty) in inference_result.type_of_expr.iter() { 2274 for (expr, ty) in inference_result.type_of_expr.iter() {
2244 let syntax_ptr = match body_source_map.expr_syntax(expr) { 2275 let syntax_ptr = match body_source_map.expr_syntax(expr) {
2245 Some(sp) => sp, 2276 Some(sp) => sp,
@@ -2251,16 +2282,36 @@ fn infer(content: &str) -> String {
2251 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); 2282 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end()));
2252 for (syntax_ptr, ty) in &types { 2283 for (syntax_ptr, ty) in &types {
2253 let node = syntax_ptr.to_node(&source_file); 2284 let node = syntax_ptr.to_node(&source_file);
2254 write!( 2285 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node) {
2255 acc, 2286 (self_param.self_kw_token().range(), "self".to_string())
2256 "{} '{}': {}\n", 2287 } else {
2257 syntax_ptr.range(), 2288 (syntax_ptr.range(), node.text().to_string().replace("\n", " "))
2258 ellipsize(node.text().to_string().replace("\n", " "), 15), 2289 };
2259 ty.display(&db) 2290 write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap();
2260 )
2261 .unwrap();
2262 } 2291 }
2292 };
2293
2294 for const_def in source_file.syntax().descendants().filter_map(ast::ConstDef::cast) {
2295 let konst = source_binder::const_from_source(&db, file_id, const_def).unwrap();
2296 let inference_result = konst.infer(&db);
2297 let body_source_map = konst.body_source_map(&db);
2298 infer_def(inference_result, body_source_map)
2263 } 2299 }
2300
2301 for static_def in source_file.syntax().descendants().filter_map(ast::StaticDef::cast) {
2302 let static_ = source_binder::static_from_source(&db, file_id, static_def).unwrap();
2303 let inference_result = static_.infer(&db);
2304 let body_source_map = static_.body_source_map(&db);
2305 infer_def(inference_result, body_source_map)
2306 }
2307
2308 for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) {
2309 let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap();
2310 let inference_result = func.infer(&db);
2311 let body_source_map = func.body_source_map(&db);
2312 infer_def(inference_result, body_source_map)
2313 }
2314
2264 acc.truncate(acc.trim_end().len()); 2315 acc.truncate(acc.trim_end().len());
2265 acc 2316 acc
2266} 2317}
diff --git a/crates/ra_ide_api/src/call_info.rs b/crates/ra_ide_api/src/call_info.rs
index c5e8d5843..29fa7d30b 100644
--- a/crates/ra_ide_api/src/call_info.rs
+++ b/crates/ra_ide_api/src/call_info.rs
@@ -28,6 +28,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
28 let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?; 28 let function = hir::source_binder::function_from_source(db, symbol.file_id, fn_def)?;
29 29
30 let mut call_info = CallInfo::new(db, function, fn_def)?; 30 let mut call_info = CallInfo::new(db, function, fn_def)?;
31
31 // If we have a calling expression let's find which argument we are on 32 // If we have a calling expression let's find which argument we are on
32 let num_params = call_info.parameters.len(); 33 let num_params = call_info.parameters.len();
33 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some(); 34 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
@@ -38,18 +39,28 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
38 } 39 }
39 } else if num_params > 1 { 40 } else if num_params > 1 {
40 // Count how many parameters into the call we are. 41 // Count how many parameters into the call we are.
41 if let Some(ref arg_list) = calling_node.arg_list() { 42 if let Some(arg_list) = calling_node.arg_list() {
43 // Number of arguments specified at the call site
44 let num_args_at_callsite = arg_list.args().count();
45
42 let arg_list_range = arg_list.syntax().range(); 46 let arg_list_range = arg_list.syntax().range();
43 if !arg_list_range.contains_inclusive(position.offset) { 47 if !arg_list_range.contains_inclusive(position.offset) {
44 tested_by!(call_info_bad_offset); 48 tested_by!(call_info_bad_offset);
45 return None; 49 return None;
46 } 50 }
47 51
48 let param = arg_list 52 let mut param = std::cmp::min(
49 .args() 53 num_args_at_callsite,
50 .position(|arg| arg.syntax().range().contains(position.offset)) 54 arg_list
51 .or(Some(num_params - 1)) 55 .args()
52 .unwrap(); 56 .take_while(|arg| arg.syntax().range().end() < position.offset)
57 .count(),
58 );
59
60 // If we are in a method account for `self`
61 if has_self {
62 param = param + 1;
63 }
53 64
54 call_info.active_parameter = Some(param); 65 call_info.active_parameter = Some(param);
55 } 66 }
@@ -156,6 +167,17 @@ fn bar() { foo(3, <|>); }"#,
156 } 167 }
157 168
158 #[test] 169 #[test]
170 fn test_fn_signature_two_args_empty() {
171 let info = call_info(
172 r#"fn foo(x: u32, y: u32) -> u32 {x + y}
173fn bar() { foo(<|>); }"#,
174 );
175
176 assert_eq!(info.parameters, vec!("x".to_string(), "y".to_string()));
177 assert_eq!(info.active_parameter, Some(0));
178 }
179
180 #[test]
159 fn test_fn_signature_for_impl() { 181 fn test_fn_signature_for_impl() {
160 let info = call_info( 182 let info = call_info(
161 r#"struct F; impl F { pub fn new() { F{}} } 183 r#"struct F; impl F { pub fn new() { F{}} }
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index 639942f7b..a846a7a3c 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -13,7 +13,7 @@ mod complete_scope;
13mod complete_postfix; 13mod complete_postfix;
14 14
15use ra_db::SourceDatabase; 15use ra_db::SourceDatabase;
16use ra_syntax::ast::{self, AstNode}; 16use ra_syntax::{ast::{self, AstNode}, SyntaxKind::{ATTR, COMMENT}};
17 17
18use crate::{ 18use crate::{
19 db, 19 db,
@@ -76,11 +76,10 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> {
76 let body_range = body.syntax().range(); 76 let body_range = body.syntax().range();
77 let label: String = node 77 let label: String = node
78 .syntax() 78 .syntax()
79 .children() 79 .children_with_tokens()
80 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body 80 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
81 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments 81 .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR)) // Filter out comments and attrs
82 .filter(|child| ast::Attr::cast(child).is_none()) // Filter out attributes 82 .map(|node| node.to_string())
83 .map(|node| node.text().to_string())
84 .collect(); 83 .collect();
85 label 84 label
86 } else { 85 } else {
@@ -93,10 +92,9 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> {
93pub fn const_label(node: &ast::ConstDef) -> String { 92pub fn const_label(node: &ast::ConstDef) -> String {
94 let label: String = node 93 let label: String = node
95 .syntax() 94 .syntax()
96 .children() 95 .children_with_tokens()
97 .filter(|child| ast::Comment::cast(child).is_none()) 96 .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
98 .filter(|child| ast::Attr::cast(child).is_none()) 97 .map(|node| node.to_string())
99 .map(|node| node.text().to_string())
100 .collect(); 98 .collect();
101 99
102 label.trim().to_owned() 100 label.trim().to_owned()
@@ -105,10 +103,9 @@ pub fn const_label(node: &ast::ConstDef) -> String {
105pub fn type_label(node: &ast::TypeAliasDef) -> String { 103pub fn type_label(node: &ast::TypeAliasDef) -> String {
106 let label: String = node 104 let label: String = node
107 .syntax() 105 .syntax()
108 .children() 106 .children_with_tokens()
109 .filter(|child| ast::Comment::cast(child).is_none()) 107 .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
110 .filter(|child| ast::Attr::cast(child).is_none()) 108 .map(|node| node.to_string())
111 .map(|node| node.text().to_string())
112 .collect(); 109 .collect();
113 110
114 label.trim().to_owned() 111 label.trim().to_owned()
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs
index ffdc744b2..f87ccdeb9 100644
--- a/crates/ra_ide_api/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs
@@ -17,7 +17,7 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
17 } 17 }
18 18
19 let mut params = FxHashMap::default(); 19 let mut params = FxHashMap::default();
20 for node in ctx.leaf.ancestors() { 20 for node in ctx.token.parent().ancestors() {
21 let _ = visitor_ctx(&mut params) 21 let _ = visitor_ctx(&mut params)
22 .visit::<ast::SourceFile, _>(process) 22 .visit::<ast::SourceFile, _>(process)
23 .visit::<ast::ItemList, _>(process) 23 .visit::<ast::ItemList, _>(process)
diff --git a/crates/ra_ide_api/src/completion/complete_keyword.rs b/crates/ra_ide_api/src/completion/complete_keyword.rs
index 841c0c554..718b83418 100644
--- a/crates/ra_ide_api/src/completion/complete_keyword.rs
+++ b/crates/ra_ide_api/src/completion/complete_keyword.rs
@@ -2,7 +2,7 @@ use ra_syntax::{
2 algo::visit::{visitor, Visitor}, 2 algo::visit::{visitor, Visitor},
3 AstNode, 3 AstNode,
4 ast::{self, LoopBodyOwner}, 4 ast::{self, LoopBodyOwner},
5 SyntaxKind::*, SyntaxNode, 5 SyntaxKind::*, SyntaxToken,
6}; 6};
7 7
8use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind, CompletionItemKind}; 8use crate::completion::{CompletionContext, CompletionItem, Completions, CompletionKind, CompletionItemKind};
@@ -62,7 +62,7 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
62 acc.add(keyword(ctx, "else", "else {$0}")); 62 acc.add(keyword(ctx, "else", "else {$0}"));
63 acc.add(keyword(ctx, "else if", "else if $0 {}")); 63 acc.add(keyword(ctx, "else if", "else if $0 {}"));
64 } 64 }
65 if is_in_loop_body(ctx.leaf) { 65 if is_in_loop_body(ctx.token) {
66 if ctx.can_be_stmt { 66 if ctx.can_be_stmt {
67 acc.add(keyword(ctx, "continue", "continue;")); 67 acc.add(keyword(ctx, "continue", "continue;"));
68 acc.add(keyword(ctx, "break", "break;")); 68 acc.add(keyword(ctx, "break", "break;"));
@@ -74,8 +74,8 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte
74 acc.add_all(complete_return(ctx, fn_def, ctx.can_be_stmt)); 74 acc.add_all(complete_return(ctx, fn_def, ctx.can_be_stmt));
75} 75}
76 76
77fn is_in_loop_body(leaf: &SyntaxNode) -> bool { 77fn is_in_loop_body(leaf: SyntaxToken) -> bool {
78 for node in leaf.ancestors() { 78 for node in leaf.parent().ancestors() {
79 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR { 79 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
80 break; 80 break;
81 } 81 }
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index 5ff1b9927..e54fe7b7e 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -19,11 +19,14 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
19 for (name, res) in module_scope.entries() { 19 for (name, res) in module_scope.entries() {
20 if Some(module) == ctx.module { 20 if Some(module) == ctx.module {
21 if let Some(import) = res.import { 21 if let Some(import) = res.import {
22 let path = module.import_source(ctx.db, import); 22 if let hir::ImportSource::UseTree(tree) =
23 if path.syntax().range().contains_inclusive(ctx.offset) { 23 module.import_source(ctx.db, import)
24 // for `use self::foo<|>`, don't suggest `foo` as a completion 24 {
25 tested_by!(dont_complete_current_use); 25 if tree.syntax().range().contains_inclusive(ctx.offset) {
26 continue; 26 // for `use self::foo<|>`, don't suggest `foo` as a completion
27 tested_by!(dont_complete_current_use);
28 continue;
29 }
27 } 30 }
28 } 31 }
29 } 32 }
@@ -73,6 +76,18 @@ mod tests {
73 } 76 }
74 77
75 #[test] 78 #[test]
79 fn dont_complete_current_use_in_braces_with_glob() {
80 let completions = do_completion(
81 r"
82 mod foo { pub struct S; }
83 use self::{foo::*, bar<|>};
84 ",
85 CompletionKind::Reference,
86 );
87 assert_eq!(completions.len(), 2);
88 }
89
90 #[test]
76 fn completes_mod_with_docs() { 91 fn completes_mod_with_docs() {
77 check_reference_completion( 92 check_reference_completion(
78 "mod_with_docs", 93 "mod_with_docs",
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index 724d0dfbf..65dffa470 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -1,8 +1,8 @@
1use ra_text_edit::AtomTextEdit; 1use ra_text_edit::AtomTextEdit;
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, SourceFile, TextUnit, TextRange, 3 AstNode, SyntaxNode, SourceFile, TextUnit, TextRange, SyntaxToken,
4 ast, 4 ast,
5 algo::{find_leaf_at_offset, find_covering_node, find_node_at_offset}, 5 algo::{find_token_at_offset, find_covering_element, find_node_at_offset},
6 SyntaxKind::*, 6 SyntaxKind::*,
7}; 7};
8use hir::{source_binder, Resolver}; 8use hir::{source_binder, Resolver};
@@ -15,7 +15,7 @@ use crate::{db, FilePosition};
15pub(crate) struct CompletionContext<'a> { 15pub(crate) struct CompletionContext<'a> {
16 pub(super) db: &'a db::RootDatabase, 16 pub(super) db: &'a db::RootDatabase,
17 pub(super) offset: TextUnit, 17 pub(super) offset: TextUnit,
18 pub(super) leaf: &'a SyntaxNode, 18 pub(super) token: SyntaxToken<'a>,
19 pub(super) resolver: Resolver, 19 pub(super) resolver: Resolver,
20 pub(super) module: Option<hir::Module>, 20 pub(super) module: Option<hir::Module>,
21 pub(super) function: Option<hir::Function>, 21 pub(super) function: Option<hir::Function>,
@@ -49,10 +49,10 @@ impl<'a> CompletionContext<'a> {
49 ) -> Option<CompletionContext<'a>> { 49 ) -> Option<CompletionContext<'a>> {
50 let resolver = source_binder::resolver_for_position(db, position); 50 let resolver = source_binder::resolver_for_position(db, position);
51 let module = source_binder::module_from_position(db, position); 51 let module = source_binder::module_from_position(db, position);
52 let leaf = find_leaf_at_offset(original_file.syntax(), position.offset).left_biased()?; 52 let token = find_token_at_offset(original_file.syntax(), position.offset).left_biased()?;
53 let mut ctx = CompletionContext { 53 let mut ctx = CompletionContext {
54 db, 54 db,
55 leaf, 55 token,
56 offset: position.offset, 56 offset: position.offset,
57 resolver, 57 resolver,
58 module, 58 module,
@@ -76,9 +76,9 @@ impl<'a> CompletionContext<'a> {
76 76
77 // The range of the identifier that is being completed. 77 // The range of the identifier that is being completed.
78 pub(crate) fn source_range(&self) -> TextRange { 78 pub(crate) fn source_range(&self) -> TextRange {
79 match self.leaf.kind() { 79 match self.token.kind() {
80 // workaroud when completion is triggered by trigger characters. 80 // workaroud when completion is triggered by trigger characters.
81 IDENT => self.leaf.range(), 81 IDENT => self.token.range(),
82 _ => TextRange::offset_len(self.offset, 0.into()), 82 _ => TextRange::offset_len(self.offset, 0.into()),
83 } 83 }
84 } 84 }
@@ -139,10 +139,11 @@ impl<'a> CompletionContext<'a> {
139 _ => (), 139 _ => (),
140 } 140 }
141 141
142 self.use_item_syntax = self.leaf.ancestors().find_map(ast::UseItem::cast); 142 self.use_item_syntax = self.token.parent().ancestors().find_map(ast::UseItem::cast);
143 143
144 self.function_syntax = self 144 self.function_syntax = self
145 .leaf 145 .token
146 .parent()
146 .ancestors() 147 .ancestors()
147 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) 148 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
148 .find_map(ast::FnDef::cast); 149 .find_map(ast::FnDef::cast);
@@ -224,8 +225,7 @@ impl<'a> CompletionContext<'a> {
224} 225}
225 226
226fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<&N> { 227fn find_node_with_range<N: AstNode>(syntax: &SyntaxNode, range: TextRange) -> Option<&N> {
227 let node = find_covering_node(syntax, range); 228 find_covering_element(syntax, range).ancestors().find_map(N::cast)
228 node.ancestors().find_map(N::cast)
229} 229}
230 230
231fn is_node<N: AstNode>(node: &SyntaxNode) -> bool { 231fn is_node<N: AstNode>(node: &SyntaxNode) -> bool {
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap
index 70ea96e1b..daccd9fba 100644
--- a/crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__enum_variant_with_details.snap
@@ -1,6 +1,6 @@
1--- 1---
2created: "2019-02-18T09:22:24.062138085Z" 2created: "2019-04-02T07:43:12.954637543Z"
3creator: insta@0.6.2 3creator: insta@0.7.4
4source: crates/ra_ide_api/src/completion/completion_item.rs 4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions 5expression: kind_completions
6--- 6---
@@ -33,6 +33,9 @@ expression: kind_completions
33 delete: [180; 180), 33 delete: [180; 180),
34 insert: "S", 34 insert: "S",
35 kind: EnumVariant, 35 kind: EnumVariant,
36 detail: "(S)" 36 detail: "(S)",
37 documentation: Documentation(
38 ""
39 )
37 } 40 }
38] 41]
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 5a78e94d8..2dfaa0045 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -106,8 +106,10 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
106 single_use_tree: &ast::UseTree, 106 single_use_tree: &ast::UseTree,
107) -> Option<TextEdit> { 107) -> Option<TextEdit> {
108 let use_tree_list_node = single_use_tree.syntax().parent()?; 108 let use_tree_list_node = single_use_tree.syntax().parent()?;
109 if single_use_tree.path()?.segment()?.syntax().first_child()?.kind() == SyntaxKind::SELF_KW { 109 if single_use_tree.path()?.segment()?.syntax().first_child_or_token()?.kind()
110 let start = use_tree_list_node.prev_sibling()?.range().start(); 110 == SyntaxKind::SELF_KW
111 {
112 let start = use_tree_list_node.prev_sibling_or_token()?.range().start();
111 let end = use_tree_list_node.range().end(); 113 let end = use_tree_list_node.range().end();
112 let range = TextRange::from_to(start, end); 114 let range = TextRange::from_to(start, end);
113 let mut edit_builder = TextEditBuilder::default(); 115 let mut edit_builder = TextEditBuilder::default();
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs
index 63879a0b5..7293ba359 100644
--- a/crates/ra_ide_api/src/extend_selection.rs
+++ b/crates/ra_ide_api/src/extend_selection.rs
@@ -1,8 +1,9 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 Direction, SyntaxNode, TextRange, TextUnit, AstNode, 3 Direction, SyntaxNode, TextRange, TextUnit, SyntaxElement,
4 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, 4 algo::{find_covering_element, find_token_at_offset, TokenAtOffset},
5 SyntaxKind::*, 5 SyntaxKind::*, SyntaxToken,
6 ast::{self, AstNode, AstToken},
6}; 7};
7 8
8use crate::{FileRange, db::RootDatabase}; 9use crate::{FileRange, db::RootDatabase};
@@ -32,53 +33,58 @@ fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
32 33
33 if range.is_empty() { 34 if range.is_empty() {
34 let offset = range.start(); 35 let offset = range.start();
35 let mut leaves = find_leaf_at_offset(root, offset); 36 let mut leaves = find_token_at_offset(root, offset);
36 if leaves.clone().all(|it| it.kind() == WHITESPACE) { 37 if leaves.clone().all(|it| it.kind() == WHITESPACE) {
37 return Some(extend_ws(root, leaves.next()?, offset)); 38 return Some(extend_ws(root, leaves.next()?, offset));
38 } 39 }
39 let leaf_range = match leaves { 40 let leaf_range = match leaves {
40 LeafAtOffset::None => return None, 41 TokenAtOffset::None => return None,
41 LeafAtOffset::Single(l) => { 42 TokenAtOffset::Single(l) => {
42 if string_kinds.contains(&l.kind()) { 43 if string_kinds.contains(&l.kind()) {
43 extend_single_word_in_comment_or_string(l, offset).unwrap_or_else(|| l.range()) 44 extend_single_word_in_comment_or_string(l, offset).unwrap_or_else(|| l.range())
44 } else { 45 } else {
45 l.range() 46 l.range()
46 } 47 }
47 } 48 }
48 LeafAtOffset::Between(l, r) => pick_best(l, r).range(), 49 TokenAtOffset::Between(l, r) => pick_best(l, r).range(),
49 }; 50 };
50 return Some(leaf_range); 51 return Some(leaf_range);
51 }; 52 };
52 let node = find_covering_node(root, range); 53 let node = match find_covering_element(root, range) {
54 SyntaxElement::Token(token) => {
55 if token.range() != range {
56 return Some(token.range());
57 }
58 if let Some(comment) = ast::Comment::cast(token) {
59 if let Some(range) = extend_comments(comment) {
60 return Some(range);
61 }
62 }
63 token.parent()
64 }
65 SyntaxElement::Node(node) => node,
66 };
67 if node.range() != range {
68 return Some(node.range());
69 }
53 70
54 // Using shallowest node with same range allows us to traverse siblings. 71 // Using shallowest node with same range allows us to traverse siblings.
55 let node = node.ancestors().take_while(|n| n.range() == node.range()).last().unwrap(); 72 let node = node.ancestors().take_while(|n| n.range() == node.range()).last().unwrap();
56 73
57 if range == node.range() { 74 if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) {
58 if string_kinds.contains(&node.kind()) { 75 if let Some(range) = extend_list_item(node) {
59 if let Some(range) = extend_comments(node) { 76 return Some(range);
60 return Some(range);
61 }
62 }
63
64 if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) {
65 if let Some(range) = extend_list_item(node) {
66 return Some(range);
67 }
68 } 77 }
69 } 78 }
70 79
71 match node.ancestors().skip_while(|n| n.range() == range).next() { 80 node.parent().map(|it| it.range())
72 None => None,
73 Some(parent) => Some(parent.range()),
74 }
75} 81}
76 82
77fn extend_single_word_in_comment_or_string( 83fn extend_single_word_in_comment_or_string(
78 leaf: &SyntaxNode, 84 leaf: SyntaxToken,
79 offset: TextUnit, 85 offset: TextUnit,
80) -> Option<TextRange> { 86) -> Option<TextRange> {
81 let text: &str = leaf.leaf_text()?; 87 let text: &str = leaf.text();
82 let cursor_position: u32 = (offset - leaf.range().start()).into(); 88 let cursor_position: u32 = (offset - leaf.range().start()).into();
83 89
84 let (before, after) = text.split_at(cursor_position as usize); 90 let (before, after) = text.split_at(cursor_position as usize);
@@ -101,14 +107,14 @@ fn extend_single_word_in_comment_or_string(
101 } 107 }
102} 108}
103 109
104fn extend_ws(root: &SyntaxNode, ws: &SyntaxNode, offset: TextUnit) -> TextRange { 110fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextUnit) -> TextRange {
105 let ws_text = ws.leaf_text().unwrap(); 111 let ws_text = ws.text();
106 let suffix = TextRange::from_to(offset, ws.range().end()) - ws.range().start(); 112 let suffix = TextRange::from_to(offset, ws.range().end()) - ws.range().start();
107 let prefix = TextRange::from_to(ws.range().start(), offset) - ws.range().start(); 113 let prefix = TextRange::from_to(ws.range().start(), offset) - ws.range().start();
108 let ws_suffix = &ws_text.as_str()[suffix]; 114 let ws_suffix = &ws_text.as_str()[suffix];
109 let ws_prefix = &ws_text.as_str()[prefix]; 115 let ws_prefix = &ws_text.as_str()[prefix];
110 if ws_text.contains('\n') && !ws_suffix.contains('\n') { 116 if ws_text.contains('\n') && !ws_suffix.contains('\n') {
111 if let Some(node) = ws.next_sibling() { 117 if let Some(node) = ws.next_sibling_or_token() {
112 let start = match ws_prefix.rfind('\n') { 118 let start = match ws_prefix.rfind('\n') {
113 Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32), 119 Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32),
114 None => node.range().start(), 120 None => node.range().start(),
@@ -124,9 +130,9 @@ fn extend_ws(root: &SyntaxNode, ws: &SyntaxNode, offset: TextUnit) -> TextRange
124 ws.range() 130 ws.range()
125} 131}
126 132
127fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode { 133fn pick_best<'a>(l: SyntaxToken<'a>, r: SyntaxToken<'a>) -> SyntaxToken<'a> {
128 return if priority(r) > priority(l) { r } else { l }; 134 return if priority(r) > priority(l) { r } else { l };
129 fn priority(n: &SyntaxNode) -> usize { 135 fn priority(n: SyntaxToken) -> usize {
130 match n.kind() { 136 match n.kind() {
131 WHITESPACE => 0, 137 WHITESPACE => 0,
132 IDENT | SELF_KW | SUPER_KW | CRATE_KW | LIFETIME => 2, 138 IDENT | SELF_KW | SUPER_KW | CRATE_KW | LIFETIME => 2,
@@ -137,54 +143,60 @@ fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode {
137