aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/gen_lsp_server/src/lib.rs2
-rw-r--r--crates/ra_analysis/src/completion/mod.rs (renamed from crates/ra_analysis/src/completion.rs)328
-rw-r--r--crates/ra_analysis/src/completion/reference_completion.rs316
-rw-r--r--crates/ra_analysis/src/db.rs8
-rw-r--r--crates/ra_analysis/src/descriptors/function/scope.rs6
-rw-r--r--crates/ra_analysis/src/descriptors/module/imp.rs16
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs43
-rw-r--r--crates/ra_analysis/src/descriptors/module/scope.rs6
-rw-r--r--crates/ra_analysis/src/imp.rs41
-rw-r--r--crates/ra_analysis/src/lib.rs23
-rw-r--r--crates/ra_analysis/src/symbol_index.rs8
-rw-r--r--crates/ra_analysis/src/syntax_ptr.rs11
-rw-r--r--crates/ra_analysis/tests/tests.rs41
-rw-r--r--crates/ra_cli/src/main.rs10
-rw-r--r--crates/ra_editor/src/code_actions.rs19
-rw-r--r--crates/ra_editor/src/extend_selection.rs6
-rw-r--r--crates/ra_editor/src/folding_ranges.rs6
-rw-r--r--crates/ra_editor/src/lib.rs18
-rw-r--r--crates/ra_editor/src/line_index.rs219
-rw-r--r--crates/ra_editor/src/symbols.rs40
-rw-r--r--crates/ra_editor/src/test_utils.rs14
-rw-r--r--crates/ra_editor/src/typing.rs16
-rw-r--r--crates/ra_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/caps.rs2
-rw-r--r--crates/ra_lsp_server/src/conv.rs23
-rw-r--r--crates/ra_lsp_server/src/main.rs41
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs28
-rw-r--r--crates/ra_lsp_server/src/main_loop/mod.rs24
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs2
-rw-r--r--crates/ra_syntax/Cargo.toml1
-rw-r--r--crates/ra_syntax/src/ast/generated.rs1326
-rw-r--r--crates/ra_syntax/src/ast/generated.rs.tera16
-rw-r--r--crates/ra_syntax/src/ast/mod.rs30
-rw-r--r--crates/ra_syntax/src/grammar.ron16
-rw-r--r--crates/ra_syntax/src/grammar/mod.rs2
-rw-r--r--crates/ra_syntax/src/lexer/ptr.rs3
-rw-r--r--crates/ra_syntax/src/lib.rs37
-rw-r--r--crates/ra_syntax/src/parser_impl/event.rs2
-rw-r--r--crates/ra_syntax/src/reparsing.rs8
-rw-r--r--crates/ra_syntax/src/string_lexing/byte.rs51
-rw-r--r--crates/ra_syntax/src/string_lexing/byte_string.rs51
-rw-r--r--crates/ra_syntax/src/string_lexing/char.rs176
-rw-r--r--crates/ra_syntax/src/string_lexing/mod.rs314
-rw-r--r--crates/ra_syntax/src/string_lexing/parser.rs201
-rw-r--r--crates/ra_syntax/src/string_lexing/string.rs46
-rw-r--r--crates/ra_syntax/src/syntax_kinds/generated.rs4
-rw-r--r--crates/ra_syntax/src/utils.rs5
-rw-r--r--crates/ra_syntax/src/validation.rs78
-rw-r--r--crates/ra_syntax/src/validation/byte.rs211
-rw-r--r--crates/ra_syntax/src/validation/byte_string.rs178
-rw-r--r--crates/ra_syntax/src/validation/char.rs276
-rw-r--r--crates/ra_syntax/src/validation/mod.rs24
-rw-r--r--crates/ra_syntax/src/validation/string.rs168
-rw-r--r--crates/ra_syntax/src/yellow/syntax_error.rs55
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0000_struct_field_missing_comma.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0001_item_recovery_in_file.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0002_duplicate_shebang.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0003_C++_semicolon.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0004_use_path_bad_segment.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0005_attribute_recover.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0006_named_field_recovery.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0007_stray_curly_in_file.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0008_item_block_recovery.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0009_broken_struct_type_parameter.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0010_unsafe_lambda_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0011_extern_struct.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0012_broken_lambda.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0013_invalid_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0014_where_no_bounds.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0015_curly_in_params.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0016_missing_semi.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0017_incomplete_binexpr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0018_incomplete_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0019_let_recover.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0020_fn_recover.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0021_incomplete_param.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0022_bad_exprs.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0023_mismatched_paren.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0024_many_type_parens.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0025_nope.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0026_imp_recovery.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/err/0027_incomplere_where_for.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0001_const_unsafe_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0002_const_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0003_extern_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0004_extern_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0005_extern_crate.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0007_unsafe_trait.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0008_unsafe_impl.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0009_unsafe_auto_trait.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0010_unsafe_default_impl.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0011_unsafe_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0012_unsafe_extern_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0013_unsafe_block_in_mod.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0014_type_item_type_params.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0015_type_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0016_type_item_where_clause.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0017_paren_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0018_unit_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0019_singleton_tuple_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0020_never_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0021_pointer_type_no_mutability.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0022_pointer_type_mut.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0023_array_type_missing_semi.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0024_array_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0025_slice_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0026_reference_type;.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0027_placeholder_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0028_fn_pointer_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0029_fn_pointer_type_missing_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0031_for_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0032_path_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0034_bind_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0035_ref_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0036_placeholder_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0037_crate_visibility.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0038_function_ret_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0039_path_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0040_expr_literals.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0041_type_param_bounds.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0042_type_param_default.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0043_call_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0044_ref_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0045_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0046_default_impl.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0047_impl_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0048_impl_item_neg.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0049_trait_item_list.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0050_let_stmt;.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0051_method_call_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0052_field_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0053_block_items.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0054_field_pat_list.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0055_self_param.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0056_trait_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0057_auto_trait.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0058_type_arg.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0059_function_where_clause.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0060_function_type_params.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0061_struct_lit.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0063_impl_trait_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0063_lambda_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0064_param_list.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0065_if_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0066_lambda_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0067_block_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0068_pub_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0068_return_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0069_match_arm.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0070_match_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0071_tuple_pat_fields.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0072_path_part.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0073_impl_item_list.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0074_unary_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0075_try_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0076_cond.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0077_while_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0078_mod_contents.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0079_cast_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0080_tuple_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0081_index_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0082_tuple_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0083_postfix_range.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0084_loop_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0085_for_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0085_match_arms_commas.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0086_array_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0086_no_semi_after_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0087_stmt_postfix_expr_ambiguity.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0088_stmt_bin_expr_ambiguity.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0089_slice_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0091_fn_decl.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0092_literal_pattern.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0093_path_fn_trait_args.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0094_range_pat.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0095_path_type_with_bounds.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0096_value_parameters_no_patterns.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0097_param_list_opt_patterns.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0098_where_clause.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0099_crate_keyword_vis.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0100_dyn_trait_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0101_qual_paths.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0102_full_range_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0103_field_attrs.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0104_arb_self_types.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0105_continue_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0106_break_expr.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0107_label.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0108_misplaced_label_err.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0109_struct_items.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0110_union_items.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0111_impl_type.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0112_crate_path.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/0113_where_pred_for.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0000_empty.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0001_struct_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0002_struct_item_field.txt2
-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.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0006_inner_attributes.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0007_extern_crate.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0008_mod_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0009_use_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0010_use_path_segments.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0011_outer_attribute.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0012_visibility.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0013_use_path_self_super.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0014_use_tree.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0015_use_tree.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0016_struct_flavors.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0017_attr_trailing_comma.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0018_struct_type_params.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0019_enums.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0020_type_param_bounds.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0021_extern_fn.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0022_empty_extern_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0023_static_items.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0024_const_item.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0025_extern_fn_in_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0026_const_fn_in_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0027_unsafe_fn_in_block.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0028_operator_binding_power.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0029_range_forms.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0030_traits.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0031_extern.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0032_where_for.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0033_label_break.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0034_macro_2.0.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0034_macro_stuck.txt2
-rw-r--r--crates/ra_syntax/tests/data/parser/ok/0035_crate_path_in_call.txt2
-rw-r--r--crates/ra_syntax/tests/test.rs4
232 files changed, 3685 insertions, 1271 deletions
diff --git a/crates/gen_lsp_server/src/lib.rs b/crates/gen_lsp_server/src/lib.rs
index e45a6b5e2..5dab8f408 100644
--- a/crates/gen_lsp_server/src/lib.rs
+++ b/crates/gen_lsp_server/src/lib.rs
@@ -1,4 +1,4 @@
1//! A language server scaffold, exposing synchroneous crossbeam-channel based API. 1//! A language server scaffold, exposing a synchronous crossbeam-channel based API.
2//! This crate handles protocol handshaking and parsing messages, while you 2//! This crate handles protocol handshaking and parsing messages, while you
3//! control the message dispatch loop yourself. 3//! control the message dispatch loop yourself.
4//! 4//!
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion/mod.rs
index 7c3476e5c..2e082705e 100644
--- a/crates/ra_analysis/src/completion.rs
+++ b/crates/ra_analysis/src/completion/mod.rs
@@ -1,20 +1,20 @@
1mod reference_completion;
2
1use ra_editor::find_node_at_offset; 3use ra_editor::find_node_at_offset;
2use ra_syntax::{ 4use ra_syntax::{
3 algo::visit::{visitor, visitor_ctx, Visitor, VisitorCtx}, 5 algo::find_leaf_at_offset,
4 ast::{self, AstChildren, LoopBodyOwner, ModuleItemOwner}, 6 algo::visit::{visitor_ctx, VisitorCtx},
5 AstNode, AtomEdit, File, 7 ast,
6 SyntaxKind::*, 8 AstNode, AtomEdit,
7 SyntaxNodeRef, TextUnit, 9 SyntaxNodeRef,
8}; 10};
9use rustc_hash::{FxHashMap, FxHashSet}; 11use rustc_hash::{FxHashMap};
10 12
11use crate::{ 13use crate::{
12 db::{self, SyntaxDatabase}, 14 db::{self, SyntaxDatabase},
13 descriptors::function::FnScopes, 15 descriptors::{DescriptorDatabase, module::ModuleSource},
14 descriptors::module::{ModuleId, ModuleScope, ModuleTree, ModuleSource}, 16 input::{FilesDatabase},
15 descriptors::DescriptorDatabase, 17 Cancelable, FilePosition
16 input::FilesDatabase,
17 Cancelable, FilePosition,
18}; 18};
19 19
20#[derive(Debug)] 20#[derive(Debug)]
@@ -27,175 +27,65 @@ pub struct CompletionItem {
27 pub snippet: Option<String>, 27 pub snippet: Option<String>,
28} 28}
29 29
30pub(crate) fn resolve_based_completion( 30pub(crate) fn completions(
31 db: &db::RootDatabase, 31 db: &db::RootDatabase,
32 position: FilePosition, 32 position: FilePosition,
33) -> Cancelable<Option<Vec<CompletionItem>>> { 33) -> Cancelable<Option<Vec<CompletionItem>>> {
34 let source_root_id = db.file_source_root(position.file_id); 34 let original_file = db.file_syntax(position.file_id);
35 let file = db.file_syntax(position.file_id); 35 // Insert a fake ident to get a valid parse tree
36 let module_tree = db.module_tree(source_root_id)?;
37 let module_id = match module_tree.any_module_for_source(ModuleSource::File(position.file_id)) {
38 None => return Ok(None),
39 Some(it) => it,
40 };
41 let file = { 36 let file = {
42 let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string()); 37 let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string());
43 file.reparse(&edit) 38 original_file.reparse(&edit)
39 };
40
41 let leaf = match find_leaf_at_offset(original_file.syntax(), position.offset).left_biased() {
42 None => return Ok(None),
43 Some(it) => it,
44 }; 44 };
45 let target_module_id = match find_target_module(&module_tree, module_id, &file, position.offset) 45 let source_root_id = db.file_source_root(position.file_id);
46 { 46 let module_tree = db.module_tree(source_root_id)?;
47 let module_source = ModuleSource::for_node(position.file_id, leaf);
48 let module_id = match module_tree.any_module_for_source(module_source) {
47 None => return Ok(None), 49 None => return Ok(None),
48 Some(it) => it, 50 Some(it) => it,
49 }; 51 };
50 let module_scope = db.module_scope(source_root_id, target_module_id)?;
51 let res: Vec<_> = module_scope
52 .entries()
53 .iter()
54 .map(|entry| CompletionItem {
55 label: entry.name().to_string(),
56 lookup: None,
57 snippet: None,
58 })
59 .collect();
60 Ok(Some(res))
61}
62
63pub(crate) fn find_target_module(
64 module_tree: &ModuleTree,
65 module_id: ModuleId,
66 file: &File,
67 offset: TextUnit,
68) -> Option<ModuleId> {
69 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), offset)?;
70 let mut crate_path = crate_path(name_ref)?;
71
72 crate_path.pop();
73 let mut target_module = module_id.root(&module_tree);
74 for name in crate_path {
75 target_module = target_module.child(module_tree, name.text().as_str())?;
76 }
77 Some(target_module)
78}
79 52
80fn crate_path(name_ref: ast::NameRef) -> Option<Vec<ast::NameRef>> {
81 let mut path = name_ref
82 .syntax()
83 .parent()
84 .and_then(ast::PathSegment::cast)?
85 .parent_path();
86 let mut res = Vec::new(); 53 let mut res = Vec::new();
87 loop {
88 let segment = path.segment()?;
89 match segment.kind()? {
90 ast::PathSegmentKind::Name(name) => res.push(name),
91 ast::PathSegmentKind::CrateKw => break,
92 ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None,
93 }
94 path = path.qualifier()?;
95 }
96 res.reverse();
97 Some(res)
98}
99
100pub(crate) fn scope_completion(
101 db: &db::RootDatabase,
102 position: FilePosition,
103) -> Option<Vec<CompletionItem>> {
104 let original_file = db.file_syntax(position.file_id);
105 // Insert a fake ident to get a valid parse tree
106 let file = {
107 let edit = AtomEdit::insert(position.offset, "intellijRulezz".to_string());
108 original_file.reparse(&edit)
109 };
110 let mut has_completions = false; 54 let mut has_completions = false;
111 let mut res = Vec::new(); 55 // First, let's try to complete a reference to some declaration.
112 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 56 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
113 has_completions = true; 57 has_completions = true;
114 complete_name_ref(&file, name_ref, &mut res); 58 reference_completion::completions(
59 &mut res,
60 db,
61 source_root_id,
62 &module_tree,
63 module_id,
64 &file,
65 name_ref,
66 )?;
115 // special case, `trait T { fn foo(i_am_a_name_ref) {} }` 67 // special case, `trait T { fn foo(i_am_a_name_ref) {} }`
116 if is_node::<ast::Param>(name_ref.syntax()) { 68 if is_node::<ast::Param>(name_ref.syntax()) {
117 param_completions(name_ref.syntax(), &mut res); 69 param_completions(name_ref.syntax(), &mut res);
118 } 70 }
119 let name_range = name_ref.syntax().range();
120 let top_node = name_ref
121 .syntax()
122 .ancestors()
123 .take_while(|it| it.range() == name_range)
124 .last()
125 .unwrap();
126 match top_node.parent().map(|it| it.kind()) {
127 Some(ROOT) | Some(ITEM_LIST) => complete_mod_item_snippets(&mut res),
128 _ => (),
129 }
130 } 71 }
72
73 // Otherwise, if this is a declaration, use heuristics to suggest a name.
131 if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { 74 if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) {
132 if is_node::<ast::Param>(name.syntax()) { 75 if is_node::<ast::Param>(name.syntax()) {
133 has_completions = true; 76 has_completions = true;
134 param_completions(name.syntax(), &mut res); 77 param_completions(name.syntax(), &mut res);
135 } 78 }
136 } 79 }
137 if has_completions { 80 let res = if has_completions { Some(res) } else { None };
138 Some(res) 81 Ok(res)
139 } else {
140 None
141 }
142}
143
144fn complete_module_items(
145 file: &File,
146 items: AstChildren<ast::ModuleItem>,
147 this_item: Option<ast::NameRef>,
148 acc: &mut Vec<CompletionItem>,
149) {
150 let scope = ModuleScope::new(items); // FIXME
151 acc.extend(
152 scope
153 .entries()
154 .iter()
155 .filter(|entry| {
156 let syntax = entry.ptr().resolve(file);
157 Some(syntax.borrowed()) != this_item.map(|it| it.syntax())
158 })
159 .map(|entry| CompletionItem {
160 label: entry.name().to_string(),
161 lookup: None,
162 snippet: None,
163 }),
164 );
165}
166
167fn complete_name_ref(file: &File, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
168 if !is_node::<ast::Path>(name_ref.syntax()) {
169 return;
170 }
171 let mut visited_fn = false;
172 for node in name_ref.syntax().ancestors() {
173 if let Some(items) = visitor()
174 .visit::<ast::Root, _>(|it| Some(it.items()))
175 .visit::<ast::Module, _>(|it| Some(it.item_list()?.items()))
176 .accept(node)
177 {
178 if let Some(items) = items {
179 complete_module_items(file, items, Some(name_ref), acc);
180 }
181 break;
182 } else if !visited_fn {
183 if let Some(fn_def) = ast::FnDef::cast(node) {
184 visited_fn = true;
185 complete_expr_keywords(&file, fn_def, name_ref, acc);
186 complete_expr_snippets(acc);
187 let scopes = FnScopes::new(fn_def);
188 complete_fn(name_ref, &scopes, acc);
189 }
190 }
191 }
192} 82}
193 83
194fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) { 84fn param_completions(ctx: SyntaxNodeRef, acc: &mut Vec<CompletionItem>) {
195 let mut params = FxHashMap::default(); 85 let mut params = FxHashMap::default();
196 for node in ctx.ancestors() { 86 for node in ctx.ancestors() {
197 let _ = visitor_ctx(&mut params) 87 let _ = visitor_ctx(&mut params)
198 .visit::<ast::Root, _>(process) 88 .visit::<ast::SourceFile, _>(process)
199 .visit::<ast::ItemList, _>(process) 89 .visit::<ast::ItemList, _>(process)
200 .accept(node); 90 .accept(node);
201 } 91 }
@@ -238,140 +128,6 @@ fn is_node<'a, N: AstNode<'a>>(node: SyntaxNodeRef<'a>) -> bool {
238 } 128 }
239} 129}
240 130
241fn complete_expr_keywords(
242 file: &File,
243 fn_def: ast::FnDef,
244 name_ref: ast::NameRef,
245 acc: &mut Vec<CompletionItem>,
246) {
247 acc.push(keyword("if", "if $0 {}"));
248 acc.push(keyword("match", "match $0 {}"));
249 acc.push(keyword("while", "while $0 {}"));
250 acc.push(keyword("loop", "loop {$0}"));
251
252 if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) {
253 if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) {
254 if if_expr.syntax().range().end() < name_ref.syntax().range().start() {
255 acc.push(keyword("else", "else {$0}"));
256 acc.push(keyword("else if", "else if $0 {}"));
257 }
258 }
259 }
260 if is_in_loop_body(name_ref) {
261 acc.push(keyword("continue", "continue"));
262 acc.push(keyword("break", "break"));
263 }
264 acc.extend(complete_return(fn_def, name_ref));
265}
266
267fn is_in_loop_body(name_ref: ast::NameRef) -> bool {
268 for node in name_ref.syntax().ancestors() {
269 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
270 break;
271 }
272 let loop_body = visitor()
273 .visit::<ast::ForExpr, _>(LoopBodyOwner::loop_body)
274 .visit::<ast::WhileExpr, _>(LoopBodyOwner::loop_body)
275 .visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body)
276 .accept(node);
277 if let Some(Some(body)) = loop_body {
278 if name_ref
279 .syntax()
280 .range()
281 .is_subrange(&body.syntax().range())
282 {
283 return true;
284 }
285 }
286 }
287 false
288}
289
290fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<CompletionItem> {
291 // let is_last_in_block = name_ref.syntax().ancestors().filter_map(ast::Expr::cast)
292 // .next()
293 // .and_then(|it| it.syntax().parent())
294 // .and_then(ast::Block::cast)
295 // .is_some();
296
297 // if is_last_in_block {
298 // return None;
299 // }
300
301 let is_stmt = match name_ref
302 .syntax()
303 .ancestors()
304 .filter_map(ast::ExprStmt::cast)
305 .next()
306 {
307 None => false,
308 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(),
309 };
310 let snip = match (is_stmt, fn_def.ret_type().is_some()) {
311 (true, true) => "return $0;",
312 (true, false) => "return;",
313 (false, true) => "return $0",
314 (false, false) => "return",
315 };
316 Some(keyword("return", snip))
317}
318
319fn keyword(kw: &str, snip: &str) -> CompletionItem {
320 CompletionItem {
321 label: kw.to_string(),
322 lookup: None,
323 snippet: Some(snip.to_string()),
324 }
325}
326
327fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) {
328 acc.push(CompletionItem {
329 label: "pd".to_string(),
330 lookup: None,
331 snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()),
332 });
333 acc.push(CompletionItem {
334 label: "ppd".to_string(),
335 lookup: None,
336 snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()),
337 });
338}
339
340fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) {
341 acc.push(CompletionItem {
342 label: "tfn".to_string(),
343 lookup: None,
344 snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()),
345 });
346 acc.push(CompletionItem {
347 label: "pub(crate)".to_string(),
348 lookup: None,
349 snippet: Some("pub(crate) $0".to_string()),
350 })
351}
352
353fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
354 let mut shadowed = FxHashSet::default();
355 acc.extend(
356 scopes
357 .scope_chain(name_ref.syntax())
358 .flat_map(|scope| scopes.entries(scope).iter())
359 .filter(|entry| shadowed.insert(entry.name()))
360 .map(|entry| CompletionItem {
361 label: entry.name().to_string(),
362 lookup: None,
363 snippet: None,
364 }),
365 );
366 if scopes.self_param.is_some() {
367 acc.push(CompletionItem {
368 label: "self".to_string(),
369 lookup: None,
370 snippet: None,
371 })
372 }
373}
374
375#[cfg(test)] 131#[cfg(test)]
376mod tests { 132mod tests {
377 use test_utils::assert_eq_dbg; 133 use test_utils::assert_eq_dbg;
@@ -382,7 +138,8 @@ mod tests {
382 138
383 fn check_scope_completion(code: &str, expected_completions: &str) { 139 fn check_scope_completion(code: &str, expected_completions: &str) {
384 let (analysis, position) = single_file_with_position(code); 140 let (analysis, position) = single_file_with_position(code);
385 let completions = scope_completion(&analysis.imp.db, position) 141 let completions = completions(&analysis.imp.db, position)
142 .unwrap()
386 .unwrap() 143 .unwrap()
387 .into_iter() 144 .into_iter()
388 .filter(|c| c.snippet.is_none()) 145 .filter(|c| c.snippet.is_none())
@@ -392,7 +149,8 @@ mod tests {
392 149
393 fn check_snippet_completion(code: &str, expected_completions: &str) { 150 fn check_snippet_completion(code: &str, expected_completions: &str) {
394 let (analysis, position) = single_file_with_position(code); 151 let (analysis, position) = single_file_with_position(code);
395 let completions = scope_completion(&analysis.imp.db, position) 152 let completions = completions(&analysis.imp.db, position)
153 .unwrap()
396 .unwrap() 154 .unwrap()
397 .into_iter() 155 .into_iter()
398 .filter(|c| c.snippet.is_some()) 156 .filter(|c| c.snippet.is_some())
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs
new file mode 100644
index 000000000..6c5fd0be6
--- /dev/null
+++ b/crates/ra_analysis/src/completion/reference_completion.rs
@@ -0,0 +1,316 @@
1use rustc_hash::{FxHashSet};
2use ra_editor::find_node_at_offset;
3use ra_syntax::{
4 algo::visit::{visitor, Visitor},
5 SourceFileNode, AstNode,
6 ast::{self, LoopBodyOwner},
7 SyntaxKind::*,
8};
9
10use crate::{
11 db::RootDatabase,
12 input::{SourceRootId},
13 completion::CompletionItem,
14 descriptors::module::{ModuleId, ModuleTree},
15 descriptors::function::FnScopes,
16 descriptors::DescriptorDatabase,
17 Cancelable
18};
19
20pub(super) fn completions(
21 acc: &mut Vec<CompletionItem>,
22 db: &RootDatabase,
23 source_root_id: SourceRootId,
24 module_tree: &ModuleTree,
25 module_id: ModuleId,
26 file: &SourceFileNode,
27 name_ref: ast::NameRef,
28) -> Cancelable<()> {
29 let kind = match classify_name_ref(name_ref) {
30 Some(it) => it,
31 None => return Ok(()),
32 };
33
34 match kind {
35 NameRefKind::LocalRef { enclosing_fn } => {
36 if let Some(fn_def) = enclosing_fn {
37 let scopes = FnScopes::new(fn_def);
38 complete_fn(name_ref, &scopes, acc);
39 complete_expr_keywords(&file, fn_def, name_ref, acc);
40 complete_expr_snippets(acc);
41 }
42
43 let module_scope = db.module_scope(source_root_id, module_id)?;
44 acc.extend(
45 module_scope
46 .entries()
47 .iter()
48 .filter(|entry| {
49 // Don't expose this item
50 !entry.ptr().range().is_subrange(&name_ref.syntax().range())
51 })
52 .map(|entry| CompletionItem {
53 label: entry.name().to_string(),
54 lookup: None,
55 snippet: None,
56 }),
57 );
58 }
59 NameRefKind::CratePath(path) => {
60 complete_path(acc, db, source_root_id, module_tree, module_id, path)?
61 }
62 NameRefKind::BareIdentInMod => {
63 let name_range = name_ref.syntax().range();
64 let top_node = name_ref
65 .syntax()
66 .ancestors()
67 .take_while(|it| it.range() == name_range)
68 .last()
69 .unwrap();
70 match top_node.parent().map(|it| it.kind()) {
71 Some(SOURCE_FILE) | Some(ITEM_LIST) => complete_mod_item_snippets(acc),
72 _ => (),
73 }
74 }
75 }
76 Ok(())
77}
78
79enum NameRefKind<'a> {
80 /// NameRef is a part of single-segment path, for example, a refernece to a
81 /// local variable.
82 LocalRef {
83 enclosing_fn: Option<ast::FnDef<'a>>,
84 },
85 /// NameRef is the last segment in crate:: path
86 CratePath(Vec<ast::NameRef<'a>>),
87 /// NameRef is bare identifier at the module's root.
88 /// Used for keyword completion
89 BareIdentInMod,
90}
91
92fn classify_name_ref(name_ref: ast::NameRef) -> Option<NameRefKind> {
93 let name_range = name_ref.syntax().range();
94 let top_node = name_ref
95 .syntax()
96 .ancestors()
97 .take_while(|it| it.range() == name_range)
98 .last()
99 .unwrap();
100 match top_node.parent().map(|it| it.kind()) {
101 Some(SOURCE_FILE) | Some(ITEM_LIST) => return Some(NameRefKind::BareIdentInMod),
102 _ => (),
103 }
104
105 let parent = name_ref.syntax().parent()?;
106 if let Some(segment) = ast::PathSegment::cast(parent) {
107 let path = segment.parent_path();
108 if let Some(crate_path) = crate_path(path) {
109 return Some(NameRefKind::CratePath(crate_path));
110 }
111 if path.qualifier().is_none() {
112 let enclosing_fn = name_ref
113 .syntax()
114 .ancestors()
115 .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
116 .find_map(ast::FnDef::cast);
117 return Some(NameRefKind::LocalRef { enclosing_fn });
118 }
119 }
120 None
121}
122
123fn crate_path(mut path: ast::Path) -> Option<Vec<ast::NameRef>> {
124 let mut res = Vec::new();
125 loop {
126 let segment = path.segment()?;
127 match segment.kind()? {
128 ast::PathSegmentKind::Name(name) => res.push(name),
129 ast::PathSegmentKind::CrateKw => break,
130 ast::PathSegmentKind::SelfKw | ast::PathSegmentKind::SuperKw => return None,
131 }
132 path = qualifier(path)?;
133 }
134 res.reverse();
135 return Some(res);
136
137 fn qualifier(path: ast::Path) -> Option<ast::Path> {
138 if let Some(q) = path.qualifier() {
139 return Some(q);
140 }
141 // TODO: this bottom up traversal is not too precise.
142 // Should we handle do a top-down analysiss, recording results?
143 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
144 let use_tree = use_tree_list.parent_use_tree();
145 use_tree.path()
146 }
147}
148
149fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
150 let mut shadowed = FxHashSet::default();
151 acc.extend(
152 scopes
153 .scope_chain(name_ref.syntax())
154 .flat_map(|scope| scopes.entries(scope).iter())
155 .filter(|entry| shadowed.insert(entry.name()))
156 .map(|entry| CompletionItem {
157 label: entry.name().to_string(),
158 lookup: None,
159 snippet: None,
160 }),
161 );
162 if scopes.self_param.is_some() {
163 acc.push(CompletionItem {
164 label: "self".to_string(),
165 lookup: None,
166 snippet: None,
167 })
168 }
169}
170
171fn complete_path(
172 acc: &mut Vec<CompletionItem>,
173 db: &RootDatabase,
174 source_root_id: SourceRootId,
175 module_tree: &ModuleTree,
176 module_id: ModuleId,
177 crate_path: Vec<ast::NameRef>,
178) -> Cancelable<()> {
179 let target_module_id = match find_target_module(module_tree, module_id, crate_path) {
180 None => return Ok(()),
181 Some(it) => it,
182 };
183 let module_scope = db.module_scope(source_root_id, target_module_id)?;
184 let completions = module_scope.entries().iter().map(|entry| CompletionItem {
185 label: entry.name().to_string(),
186 lookup: None,
187 snippet: None,
188 });
189 acc.extend(completions);
190 Ok(())
191}
192
193fn find_target_module(
194 module_tree: &ModuleTree,
195 module_id: ModuleId,
196 mut crate_path: Vec<ast::NameRef>,
197) -> Option<ModuleId> {
198 crate_path.pop();
199 let mut target_module = module_id.root(&module_tree);
200 for name in crate_path {
201 target_module = target_module.child(module_tree, name.text().as_str())?;
202 }
203 Some(target_module)
204}
205
206fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) {
207 acc.push(CompletionItem {
208 label: "tfn".to_string(),
209 lookup: None,
210 snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()),
211 });
212 acc.push(CompletionItem {
213 label: "pub(crate)".to_string(),
214 lookup: None,
215 snippet: Some("pub(crate) $0".to_string()),
216 })
217}
218
219fn complete_expr_keywords(
220 file: &SourceFileNode,
221 fn_def: ast::FnDef,
222 name_ref: ast::NameRef,
223 acc: &mut Vec<CompletionItem>,
224) {
225 acc.push(keyword("if", "if $0 {}"));
226 acc.push(keyword("match", "match $0 {}"));
227 acc.push(keyword("while", "while $0 {}"));
228 acc.push(keyword("loop", "loop {$0}"));
229
230 if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) {
231 if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) {
232 if if_expr.syntax().range().end() < name_ref.syntax().range().start() {
233 acc.push(keyword("else", "else {$0}"));
234 acc.push(keyword("else if", "else if $0 {}"));
235 }
236 }
237 }
238 if is_in_loop_body(name_ref) {
239 acc.push(keyword("continue", "continue"));
240 acc.push(keyword("break", "break"));
241 }
242 acc.extend(complete_return(fn_def, name_ref));
243}
244
245fn is_in_loop_body(name_ref: ast::NameRef) -> bool {
246 for node in name_ref.syntax().ancestors() {
247 if node.kind() == FN_DEF || node.kind() == LAMBDA_EXPR {
248 break;
249 }
250 let loop_body = visitor()
251 .visit::<ast::ForExpr, _>(LoopBodyOwner::loop_body)
252 .visit::<ast::WhileExpr, _>(LoopBodyOwner::loop_body)
253 .visit::<ast::LoopExpr, _>(LoopBodyOwner::loop_body)
254 .accept(node);
255 if let Some(Some(body)) = loop_body {
256 if name_ref
257 .syntax()
258 .range()
259 .is_subrange(&body.syntax().range())
260 {
261 return true;
262 }
263 }
264 }
265 false
266}
267
268fn complete_return(fn_def: ast::FnDef, name_ref: ast::NameRef) -> Option<CompletionItem> {
269 // let is_last_in_block = name_ref.syntax().ancestors().filter_map(ast::Expr::cast)
270 // .next()
271 // .and_then(|it| it.syntax().parent())
272 // .and_then(ast::Block::cast)
273 // .is_some();
274
275 // if is_last_in_block {
276 // return None;
277 // }
278
279 let is_stmt = match name_ref
280 .syntax()
281 .ancestors()
282 .filter_map(ast::ExprStmt::cast)
283 .next()
284 {
285 None => false,
286 Some(expr_stmt) => expr_stmt.syntax().range() == name_ref.syntax().range(),
287 };
288 let snip = match (is_stmt, fn_def.ret_type().is_some()) {
289 (true, true) => "return $0;",
290 (true, false) => "return;",
291 (false, true) => "return $0",
292 (false, false) => "return",
293 };
294 Some(keyword("return", snip))
295}
296
297fn keyword(kw: &str, snip: &str) -> CompletionItem {
298 CompletionItem {
299 label: kw.to_string(),
300 lookup: None,
301 snippet: Some(snip.to_string()),
302 }
303}
304
305fn complete_expr_snippets(acc: &mut Vec<CompletionItem>) {
306 acc.push(CompletionItem {
307 label: "pd".to_string(),
308 lookup: None,
309 snippet: Some("eprintln!(\"$0 = {:?}\", $0);".to_string()),
310 });
311 acc.push(CompletionItem {
312 label: "ppd".to_string(),
313 lookup: None,
314 snippet: Some("eprintln!(\"$0 = {:#?}\", $0);".to_string()),
315 });
316}
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index 627512553..194f1a6b0 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,7 +1,7 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_editor::LineIndex; 3use ra_editor::LineIndex;
4use ra_syntax::{File, SyntaxNode}; 4use ra_syntax::{SourceFileNode, SyntaxNode};
5use salsa::{self, Database}; 5use salsa::{self, Database};
6 6
7use crate::{ 7use crate::{
@@ -85,7 +85,7 @@ salsa::database_storage! {
85 85
86salsa::query_group! { 86salsa::query_group! {
87 pub(crate) trait SyntaxDatabase: crate::input::FilesDatabase { 87 pub(crate) trait SyntaxDatabase: crate::input::FilesDatabase {
88 fn file_syntax(file_id: FileId) -> File { 88 fn file_syntax(file_id: FileId) -> SourceFileNode {
89 type FileSyntaxQuery; 89 type FileSyntaxQuery;
90 } 90 }
91 fn file_lines(file_id: FileId) -> Arc<LineIndex> { 91 fn file_lines(file_id: FileId) -> Arc<LineIndex> {
@@ -103,9 +103,9 @@ salsa::query_group! {
103 } 103 }
104} 104}
105 105
106fn file_syntax(db: &impl SyntaxDatabase, file_id: FileId) -> File { 106fn file_syntax(db: &impl SyntaxDatabase, file_id: FileId) -> SourceFileNode {
107 let text = db.file_text(file_id); 107 let text = db.file_text(file_id);
108 File::parse(&*text) 108 SourceFileNode::parse(&*text)
109} 109}
110fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> { 110fn file_lines(db: &impl SyntaxDatabase, file_id: FileId) -> Arc<LineIndex> {
111 let text = db.file_text(file_id); 111 let text = db.file_text(file_id);
diff --git a/crates/ra_analysis/src/descriptors/function/scope.rs b/crates/ra_analysis/src/descriptors/function/scope.rs
index 62b46ffba..bbe16947c 100644
--- a/crates/ra_analysis/src/descriptors/function/scope.rs
+++ b/crates/ra_analysis/src/descriptors/function/scope.rs
@@ -272,7 +272,7 @@ pub fn resolve_local_name<'a>(
272#[cfg(test)] 272#[cfg(test)]
273mod tests { 273mod tests {
274 use ra_editor::find_node_at_offset; 274 use ra_editor::find_node_at_offset;
275 use ra_syntax::File; 275 use ra_syntax::SourceFileNode;
276 use test_utils::extract_offset; 276 use test_utils::extract_offset;
277 277
278 use super::*; 278 use super::*;
@@ -287,7 +287,7 @@ mod tests {
287 buf.push_str(&code[off..]); 287 buf.push_str(&code[off..]);
288 buf 288 buf
289 }; 289 };
290 let file = File::parse(&code); 290 let file = SourceFileNode::parse(&code);
291 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); 291 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
292 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 292 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
293 let scopes = FnScopes::new(fn_def); 293 let scopes = FnScopes::new(fn_def);
@@ -376,7 +376,7 @@ mod tests {
376 376
377 fn do_check_local_name(code: &str, expected_offset: u32) { 377 fn do_check_local_name(code: &str, expected_offset: u32) {
378 let (off, code) = extract_offset(code); 378 let (off, code) = extract_offset(code);
379 let file = File::parse(&code); 379 let file = SourceFileNode::parse(&code);
380 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); 380 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
381 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); 381 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
382 382
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs
index b5c232ea4..ade96ddc0 100644
--- a/crates/ra_analysis/src/descriptors/module/imp.rs
+++ b/crates/ra_analysis/src/descriptors/module/imp.rs
@@ -41,8 +41,8 @@ pub(crate) fn submodules(
41 db::check_canceled(db)?; 41 db::check_canceled(db)?;
42 let file_id = source.file_id(); 42 let file_id = source.file_id();
43 let submodules = match source.resolve(db) { 43 let submodules = match source.resolve(db) {
44 ModuleSourceNode::Root(it) => collect_submodules(file_id, it.borrowed()), 44 ModuleSourceNode::SourceFile(it) => collect_submodules(file_id, it.borrowed()),
45 ModuleSourceNode::Inline(it) => it 45 ModuleSourceNode::Module(it) => it
46 .borrowed() 46 .borrowed()
47 .item_list() 47 .item_list()
48 .map(|it| collect_submodules(file_id, it)) 48 .map(|it| collect_submodules(file_id, it))
@@ -89,8 +89,8 @@ pub(crate) fn module_scope(
89 let tree = db.module_tree(source_root_id)?; 89 let tree = db.module_tree(source_root_id)?;
90 let source = module_id.source(&tree).resolve(db); 90 let source = module_id.source(&tree).resolve(db);
91 let res = match source { 91 let res = match source {
92 ModuleSourceNode::Root(root) => ModuleScope::new(root.borrowed().items()), 92 ModuleSourceNode::SourceFile(it) => ModuleScope::new(it.borrowed().items()),
93 ModuleSourceNode::Inline(inline) => match inline.borrowed().item_list() { 93 ModuleSourceNode::Module(it) => match it.borrowed().item_list() {
94 Some(items) => ModuleScope::new(items.items()), 94 Some(items) => ModuleScope::new(items.items()),
95 None => ModuleScope::new(std::iter::empty()), 95 None => ModuleScope::new(std::iter::empty()),
96 }, 96 },
@@ -121,7 +121,7 @@ fn create_module_tree<'a>(
121 121
122 let source_root = db.source_root(source_root); 122 let source_root = db.source_root(source_root);
123 for &file_id in source_root.files.iter() { 123 for &file_id in source_root.files.iter() {
124 let source = ModuleSource::File(file_id); 124 let source = ModuleSource::SourceFile(file_id);
125 if visited.contains(&source) { 125 if visited.contains(&source) {
126 continue; // TODO: use explicit crate_roots here 126 continue; // TODO: use explicit crate_roots here
127 } 127 }
@@ -181,7 +181,7 @@ fn build_subtree(
181 visited, 181 visited,
182 roots, 182 roots,
183 Some(link), 183 Some(link),
184 ModuleSource::File(file_id), 184 ModuleSource::SourceFile(file_id),
185 ), 185 ),
186 }) 186 })
187 .collect::<Cancelable<Vec<_>>>()?; 187 .collect::<Cancelable<Vec<_>>>()?;
@@ -213,8 +213,8 @@ fn resolve_submodule(
213 file_resolver: &FileResolverImp, 213 file_resolver: &FileResolverImp,
214) -> (Vec<FileId>, Option<Problem>) { 214) -> (Vec<FileId>, Option<Problem>) {
215 let file_id = match source { 215 let file_id = match source {
216 ModuleSource::File(it) => it, 216 ModuleSource::SourceFile(it) => it,
217 ModuleSource::Inline(..) => { 217 ModuleSource::Module(..) => {
218 // TODO 218 // TODO
219 return (Vec::new(), None); 219 return (Vec::new(), None);
220 } 220 }
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs
index 03330240d..bc1148b22 100644
--- a/crates/ra_analysis/src/descriptors/module/mod.rs
+++ b/crates/ra_analysis/src/descriptors/module/mod.rs
@@ -3,7 +3,7 @@ pub(crate) mod scope;
3 3
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, AstNode, NameOwner}, 5 ast::{self, AstNode, NameOwner},
6 SmolStr, SyntaxNode, 6 SmolStr, SyntaxNode, SyntaxNodeRef,
7}; 7};
8use relative_path::RelativePathBuf; 8use relative_path::RelativePathBuf;
9 9
@@ -41,19 +41,18 @@ impl ModuleTree {
41 41
42/// `ModuleSource` is the syntax tree element that produced this module: 42/// `ModuleSource` is the syntax tree element that produced this module:
43/// either a file, or an inlinde module. 43/// either a file, or an inlinde module.
44/// TODO: we don't produce Inline modules yet
45#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 44#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
46pub(crate) enum ModuleSource { 45pub(crate) enum ModuleSource {
47 File(FileId), 46 SourceFile(FileId),
48 #[allow(dead_code)] 47 #[allow(dead_code)]
49 Inline(SyntaxPtr), 48 Module(SyntaxPtr),
50} 49}
51 50
52/// An owned syntax node for a module. Unlike `ModuleSource`, 51/// An owned syntax node for a module. Unlike `ModuleSource`,
53/// this holds onto the AST for the whole file. 52/// this holds onto the AST for the whole file.
54enum ModuleSourceNode { 53enum ModuleSourceNode {
55 Root(ast::RootNode), 54 SourceFile(ast::SourceFileNode),
56 Inline(ast::ModuleNode), 55 Module(ast::ModuleNode),
57} 56}
58 57
59#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] 58#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
@@ -135,14 +134,14 @@ impl LinkId {
135 ) -> ast::ModuleNode { 134 ) -> ast::ModuleNode {
136 let owner = self.owner(tree); 135 let owner = self.owner(tree);
137 match owner.source(tree).resolve(db) { 136 match owner.source(tree).resolve(db) {
138 ModuleSourceNode::Root(root) => { 137 ModuleSourceNode::SourceFile(root) => {
139 let ast = imp::modules(root.borrowed()) 138 let ast = imp::modules(root.borrowed())
140 .find(|(name, _)| name == &tree.link(self).name) 139 .find(|(name, _)| name == &tree.link(self).name)
141 .unwrap() 140 .unwrap()
142 .1; 141 .1;
143 ast.owned() 142 ast.owned()
144 } 143 }
145 ModuleSourceNode::Inline(it) => it, 144 ModuleSourceNode::Module(it) => it,
146 } 145 }
147 } 146 }
148} 147}
@@ -155,37 +154,47 @@ struct ModuleData {
155} 154}
156 155
157impl ModuleSource { 156impl ModuleSource {
157 pub(crate) fn for_node(file_id: FileId, node: SyntaxNodeRef) -> ModuleSource {
158 for node in node.ancestors() {
159 if let Some(m) = ast::Module::cast(node) {
160 if !m.has_semi() {
161 return ModuleSource::new_inline(file_id, m);
162 }
163 }
164 }
165 ModuleSource::SourceFile(file_id)
166 }
158 pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource { 167 pub(crate) fn new_inline(file_id: FileId, module: ast::Module) -> ModuleSource {
159 assert!(!module.has_semi()); 168 assert!(!module.has_semi());
160 let ptr = SyntaxPtr::new(file_id, module.syntax()); 169 let ptr = SyntaxPtr::new(file_id, module.syntax());
161 ModuleSource::Inline(ptr) 170 ModuleSource::Module(ptr)
162 } 171 }
163 172
164 pub(crate) fn as_file(self) -> Option<FileId> { 173 pub(crate) fn as_file(self) -> Option<FileId> {
165 match self { 174 match self {
166 ModuleSource::File(f) => Some(f), 175 ModuleSource::SourceFile(f) => Some(f),
167 ModuleSource::Inline(..) => None, 176 ModuleSource::Module(..) => None,
168 } 177 }
169 } 178 }
170 179
171 pub(crate) fn file_id(self) -> FileId { 180 pub(crate) fn file_id(self) -> FileId {
172 match self { 181 match self {
173 ModuleSource::File(f) => f, 182 ModuleSource::SourceFile(f) => f,
174 ModuleSource::Inline(ptr) => ptr.file_id(), 183 ModuleSource::Module(ptr) => ptr.file_id(),
175 } 184 }
176 } 185 }
177 186
178 fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode { 187 fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode {
179 match self { 188 match self {
180 ModuleSource::File(file_id) => { 189 ModuleSource::SourceFile(file_id) => {
181 let syntax = db.file_syntax(file_id); 190 let syntax = db.file_syntax(file_id);
182 ModuleSourceNode::Root(syntax.ast().owned()) 191 ModuleSourceNode::SourceFile(syntax.ast().owned())
183 } 192 }
184 ModuleSource::Inline(ptr) => { 193 ModuleSource::Module(ptr) => {
185 let syntax = db.resolve_syntax_ptr(ptr); 194 let syntax = db.resolve_syntax_ptr(ptr);
186 let syntax = syntax.borrowed(); 195 let syntax = syntax.borrowed();
187 let module = ast::Module::cast(syntax).unwrap(); 196 let module = ast::Module::cast(syntax).unwrap();
188 ModuleSourceNode::Inline(module.owned()) 197 ModuleSourceNode::Module(module.owned())
189 } 198 }
190 } 199 }
191 } 200 }
diff --git a/crates/ra_analysis/src/descriptors/module/scope.rs b/crates/ra_analysis/src/descriptors/module/scope.rs
index 215b31f8e..4490228e4 100644
--- a/crates/ra_analysis/src/descriptors/module/scope.rs
+++ b/crates/ra_analysis/src/descriptors/module/scope.rs
@@ -25,7 +25,7 @@ enum EntryKind {
25} 25}
26 26
27impl ModuleScope { 27impl ModuleScope {
28 pub(crate) fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope { 28 pub(super) fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope {
29 let mut entries = Vec::new(); 29 let mut entries = Vec::new();
30 for item in items { 30 for item in items {
31 let entry = match item { 31 let entry = match item {
@@ -95,10 +95,10 @@ fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) {
95#[cfg(test)] 95#[cfg(test)]
96mod tests { 96mod tests {
97 use super::*; 97 use super::*;
98 use ra_syntax::{ast::ModuleItemOwner, File}; 98 use ra_syntax::{ast::ModuleItemOwner, SourceFileNode};
99 99
100 fn do_check(code: &str, expected: &[&str]) { 100 fn do_check(code: &str, expected: &[&str]) {
101 let file = File::parse(&code); 101 let file = SourceFileNode::parse(&code);
102 let scope = ModuleScope::new(file.ast().items()); 102 let scope = ModuleScope::new(file.ast().items());
103 let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>(); 103 let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>();
104 assert_eq!(expected, actual.as_slice()); 104 assert_eq!(expected, actual.as_slice());
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 819827b95..74c248a96 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -7,7 +7,7 @@ use std::{
7use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit}; 7use ra_editor::{self, find_node_at_offset, FileSymbol, LineIndex, LocalEdit};
8use ra_syntax::{ 8use ra_syntax::{
9 ast::{self, ArgListOwner, Expr, NameOwner}, 9 ast::{self, ArgListOwner, Expr, NameOwner},
10 AstNode, File, SmolStr, 10 AstNode, SourceFileNode, SmolStr,
11 SyntaxKind::*, 11 SyntaxKind::*,
12 SyntaxNodeRef, TextRange, TextUnit, 12 SyntaxNodeRef, TextRange, TextUnit,
13}; 13};
@@ -17,7 +17,7 @@ use rustc_hash::FxHashSet;
17use salsa::{Database, ParallelDatabase}; 17use salsa::{Database, ParallelDatabase};
18 18
19use crate::{ 19use crate::{
20 completion::{resolve_based_completion, scope_completion, CompletionItem}, 20 completion::{completions, CompletionItem},
21 db::{self, FileSyntaxQuery, SyntaxDatabase}, 21 db::{self, FileSyntaxQuery, SyntaxDatabase},
22 descriptors::{ 22 descriptors::{
23 function::{FnDescriptor, FnId}, 23 function::{FnDescriptor, FnId},
@@ -27,7 +27,7 @@ use crate::{
27 input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, 27 input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE},
28 symbol_index::SymbolIndex, 28 symbol_index::SymbolIndex,
29 AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver, 29 AnalysisChange, Cancelable, CrateGraph, CrateId, Diagnostic, FileId, FileResolver,
30 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileEdit, 30 FileSystemEdit, FilePosition, Query, SourceChange, SourceFileNodeEdit,
31}; 31};
32 32
33#[derive(Clone, Debug)] 33#[derive(Clone, Debug)]
@@ -180,7 +180,7 @@ impl fmt::Debug for AnalysisImpl {
180} 180}
181 181
182impl AnalysisImpl { 182impl AnalysisImpl {
183 pub fn file_syntax(&self, file_id: FileId) -> File { 183 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode {
184 self.db.file_syntax(file_id) 184 self.db.file_syntax(file_id)
185 } 185 }
186 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { 186 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> {
@@ -226,7 +226,7 @@ impl AnalysisImpl {
226 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) 226 let module_source = match find_node_at_offset::<ast::Module>(file.syntax(), position.offset)
227 { 227 {
228 Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m), 228 Some(m) if !m.has_semi() => ModuleSource::new_inline(position.file_id, m),
229 _ => ModuleSource::File(position.file_id), 229 _ => ModuleSource::SourceFile(position.file_id),
230 }; 230 };
231 231
232 let res = module_tree 232 let res = module_tree
@@ -254,7 +254,7 @@ impl AnalysisImpl {
254 let module_tree = self.module_tree(file_id)?; 254 let module_tree = self.module_tree(file_id)?;
255 let crate_graph = self.db.crate_graph(); 255 let crate_graph = self.db.crate_graph();
256 let res = module_tree 256 let res = module_tree
257 .modules_for_source(ModuleSource::File(file_id)) 257 .modules_for_source(ModuleSource::SourceFile(file_id))
258 .into_iter() 258 .into_iter()
259 .map(|it| it.root(&module_tree)) 259 .map(|it| it.root(&module_tree))
260 .filter_map(|it| it.source(&module_tree).as_file()) 260 .filter_map(|it| it.source(&module_tree).as_file())
@@ -267,18 +267,7 @@ impl AnalysisImpl {
267 self.db.crate_graph().crate_roots[&crate_id] 267 self.db.crate_graph().crate_roots[&crate_id]
268 } 268 }
269 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { 269 pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> {
270 let mut res = Vec::new(); 270 completions(&self.db, position)
271 let mut has_completions = false;
272 if let Some(scope_based) = scope_completion(&self.db, position) {
273 res.extend(scope_based);
274 has_completions = true;
275 }
276 if let Some(scope_based) = resolve_based_completion(&self.db, position)? {
277 res.extend(scope_based);
278 has_completions = true;
279 }
280 let res = if has_completions { Some(res) } else { None };
281 Ok(res)
282 } 271 }
283 pub fn approximately_resolve_symbol( 272 pub fn approximately_resolve_symbol(
284 &self, 273 &self,
@@ -364,6 +353,16 @@ impl AnalysisImpl {
364 ret 353 ret
365 } 354 }
366 355
356 pub fn doc_comment_for(
357 &self,
358 file_id: FileId,
359 symbol: FileSymbol,
360 ) -> Cancelable<Option<String>> {
361 let file = self.db.file_syntax(file_id);
362
363 Ok(symbol.docs(&file))
364 }
365
367 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { 366 pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> {
368 let module_tree = self.module_tree(file_id)?; 367 let module_tree = self.module_tree(file_id)?;
369 let syntax = self.db.file_syntax(file_id); 368 let syntax = self.db.file_syntax(file_id);
@@ -376,7 +375,7 @@ impl AnalysisImpl {
376 fix: None, 375 fix: None,
377 }) 376 })
378 .collect::<Vec<_>>(); 377 .collect::<Vec<_>>();
379 if let Some(m) = module_tree.any_module_for_source(ModuleSource::File(file_id)) { 378 if let Some(m) = module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) {
380 for (name_node, problem) in m.problems(&module_tree, &*self.db) { 379 for (name_node, problem) in m.problems(&module_tree, &*self.db) {
381 let diag = match problem { 380 let diag = match problem {
382 Problem::UnresolvedModule { candidate } => { 381 Problem::UnresolvedModule { candidate } => {
@@ -538,7 +537,7 @@ impl AnalysisImpl {
538 Some(name) => name.text(), 537 Some(name) => name.text(),
539 None => return Vec::new(), 538 None => return Vec::new(),
540 }; 539 };
541 let module_id = match module_tree.any_module_for_source(ModuleSource::File(file_id)) { 540 let module_id = match module_tree.any_module_for_source(ModuleSource::SourceFile(file_id)) {
542 Some(id) => id, 541 Some(id) => id,
543 None => return Vec::new(), 542 None => return Vec::new(),
544 }; 543 };
@@ -552,7 +551,7 @@ impl AnalysisImpl {
552 551
553impl SourceChange { 552impl SourceChange {
554 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange { 553 pub(crate) fn from_local_edit(file_id: FileId, label: &str, edit: LocalEdit) -> SourceChange {
555 let file_edit = SourceFileEdit { 554 let file_edit = SourceFileNodeEdit {
556 file_id, 555 file_id,
557 edits: edit.edit.into_atoms(), 556 edits: edit.edit.into_atoms(),
558 }; 557 };
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 0ea9ebee7..ab0e3cb0c 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -1,5 +1,5 @@
1//! ra_analyzer crate is the brain of Rust analyzer. It relies on the `salsa` 1//! ra_analyzer crate is the brain of Rust analyzer. It relies on the `salsa`
2//! crate, which provides and incremental on-deman database of facts. 2//! crate, which provides and incremental on-demand database of facts.
3 3
4extern crate fst; 4extern crate fst;
5extern crate ra_editor; 5extern crate ra_editor;
@@ -20,7 +20,7 @@ pub mod mock_analysis;
20 20
21use std::{fmt, sync::Arc}; 21use std::{fmt, sync::Arc};
22 22
23use ra_syntax::{AtomEdit, File, TextRange, TextUnit}; 23use ra_syntax::{AtomEdit, SourceFileNode, TextRange, TextUnit};
24use rayon::prelude::*; 24use rayon::prelude::*;
25use relative_path::RelativePathBuf; 25use relative_path::RelativePathBuf;
26 26
@@ -128,13 +128,13 @@ pub struct FilePosition {
128#[derive(Debug)] 128#[derive(Debug)]
129pub struct SourceChange { 129pub struct SourceChange {
130 pub label: String, 130 pub label: String,
131 pub source_file_edits: Vec<SourceFileEdit>, 131 pub source_file_edits: Vec<SourceFileNodeEdit>,
132 pub file_system_edits: Vec<FileSystemEdit>, 132 pub file_system_edits: Vec<FileSystemEdit>,
133 pub cursor_position: Option<FilePosition>, 133 pub cursor_position: Option<FilePosition>,
134} 134}
135 135
136#[derive(Debug)] 136#[derive(Debug)]
137pub struct SourceFileEdit { 137pub struct SourceFileNodeEdit {
138 pub file_id: FileId, 138 pub file_id: FileId,
139 pub edits: Vec<AtomEdit>, 139 pub edits: Vec<AtomEdit>,
140} 140}
@@ -204,16 +204,16 @@ pub struct Analysis {
204} 204}
205 205
206impl Analysis { 206impl Analysis {
207 pub fn file_syntax(&self, file_id: FileId) -> File { 207 pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode {
208 self.imp.file_syntax(file_id).clone() 208 self.imp.file_syntax(file_id).clone()
209 } 209 }
210 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { 210 pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> {
211 self.imp.file_line_index(file_id) 211 self.imp.file_line_index(file_id)
212 } 212 }
213 pub fn extend_selection(&self, file: &File, range: TextRange) -> TextRange { 213 pub fn extend_selection(&self, file: &SourceFileNode, range: TextRange) -> TextRange {
214 ra_editor::extend_selection(file, range).unwrap_or(range) 214 ra_editor::extend_selection(file, range).unwrap_or(range)
215 } 215 }
216 pub fn matching_brace(&self, file: &File, offset: TextUnit) -> Option<TextUnit> { 216 pub fn matching_brace(&self, file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> {
217 ra_editor::matching_brace(file, offset) 217 ra_editor::matching_brace(file, offset)
218 } 218 }
219 pub fn syntax_tree(&self, file_id: FileId) -> String { 219 pub fn syntax_tree(&self, file_id: FileId) -> String {
@@ -258,6 +258,13 @@ impl Analysis {
258 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 258 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
259 Ok(self.imp.find_all_refs(position)) 259 Ok(self.imp.find_all_refs(position))
260 } 260 }
261 pub fn doc_comment_for(
262 &self,
263 file_id: FileId,
264 symbol: FileSymbol,
265 ) -> Cancelable<Option<String>> {
266 self.imp.doc_comment_for(file_id, symbol)
267 }
261 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 268 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> {
262 self.imp.parent_module(position) 269 self.imp.parent_module(position)
263 } 270 }
@@ -302,7 +309,7 @@ pub struct LibraryData {
302impl LibraryData { 309impl LibraryData {
303 pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData { 310 pub fn prepare(files: Vec<(FileId, String)>, file_resolver: Arc<FileResolver>) -> LibraryData {
304 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, text)| { 311 let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, text)| {
305 let file = File::parse(text); 312 let file = SourceFileNode::parse(text);
306 (*file_id, file) 313 (*file_id, file)
307 })); 314 }));
308 LibraryData { 315 LibraryData {
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index b57ad5d33..3a0667ecd 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -6,7 +6,7 @@ use std::{
6use fst::{self, Streamer}; 6use fst::{self, Streamer};
7use ra_editor::{file_symbols, FileSymbol}; 7use ra_editor::{file_symbols, FileSymbol};
8use ra_syntax::{ 8use ra_syntax::{
9 File, 9 SourceFileNode,
10 SyntaxKind::{self, *}, 10 SyntaxKind::{self, *},
11}; 11};
12use rayon::prelude::*; 12use rayon::prelude::*;
@@ -34,7 +34,9 @@ impl Hash for SymbolIndex {
34} 34}
35 35
36impl SymbolIndex { 36impl SymbolIndex {
37 pub(crate) fn for_files(files: impl ParallelIterator<Item = (FileId, File)>) -> SymbolIndex { 37 pub(crate) fn for_files(
38 files: impl ParallelIterator<Item = (FileId, SourceFileNode)>,
39 ) -> SymbolIndex {
38 let mut symbols = files 40 let mut symbols = files
39 .flat_map(|(file_id, file)| { 41 .flat_map(|(file_id, file)| {
40 file_symbols(&file) 42 file_symbols(&file)
@@ -51,7 +53,7 @@ impl SymbolIndex {
51 SymbolIndex { symbols, map } 53 SymbolIndex { symbols, map }
52 } 54 }
53 55
54 pub(crate) fn for_file(file_id: FileId, file: File) -> SymbolIndex { 56 pub(crate) fn for_file(file_id: FileId, file: SourceFileNode) -> SymbolIndex {
55 SymbolIndex::for_files(rayon::iter::once((file_id, file))) 57 SymbolIndex::for_files(rayon::iter::once((file_id, file)))
56 } 58 }
57} 59}
diff --git a/crates/ra_analysis/src/syntax_ptr.rs b/crates/ra_analysis/src/syntax_ptr.rs
index 4afb1fc93..194b94584 100644
--- a/crates/ra_analysis/src/syntax_ptr.rs
+++ b/crates/ra_analysis/src/syntax_ptr.rs
@@ -1,4 +1,4 @@
1use ra_syntax::{File, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange}; 1use ra_syntax::{SourceFileNode, SyntaxKind, SyntaxNode, SyntaxNodeRef, TextRange};
2 2
3use crate::db::SyntaxDatabase; 3use crate::db::SyntaxDatabase;
4use crate::FileId; 4use crate::FileId;
@@ -43,7 +43,7 @@ impl LocalSyntaxPtr {
43 } 43 }
44 } 44 }
45 45
46 pub(crate) fn resolve(self, file: &File) -> SyntaxNode { 46 pub(crate) fn resolve(self, file: &SourceFileNode) -> SyntaxNode {
47 let mut curr = file.syntax(); 47 let mut curr = file.syntax();
48 loop { 48 loop {
49 if curr.range() == self.range && curr.kind() == self.kind { 49 if curr.range() == self.range && curr.kind() == self.kind {
@@ -62,12 +62,17 @@ impl LocalSyntaxPtr {
62 local: self, 62 local: self,
63 } 63 }
64 } 64 }
65
66 // Seems unfortunate to expose
67 pub(crate) fn range(self) -> TextRange {
68 self.range
69 }
65} 70}
66 71
67#[test] 72#[test]
68fn test_local_syntax_ptr() { 73fn test_local_syntax_ptr() {
69 use ra_syntax::{ast, AstNode}; 74 use ra_syntax::{ast, AstNode};
70 let file = File::parse("struct Foo { f: u32, }"); 75 let file = SourceFileNode::parse("struct Foo { f: u32, }");
71 let field = file 76 let field = file
72 .syntax() 77 .syntax()
73 .descendants() 78 .descendants()
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index c605d34f0..719c166b5 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -452,3 +452,44 @@ fn test_complete_crate_path() {
452 &completions, 452 &completions,
453 ); 453 );
454} 454}
455
456#[test]
457fn test_complete_crate_path_with_braces() {
458 let (analysis, position) = analysis_and_position(
459 "
460 //- /lib.rs
461 mod foo;
462 struct Spam;
463 //- /foo.rs
464 use crate::{Sp<|>};
465 ",
466 );
467 let completions = analysis.completions(position).unwrap().unwrap();
468 assert_eq_dbg(
469 r#"[CompletionItem { label: "foo", lookup: None, snippet: None },
470 CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
471 &completions,
472 );
473}
474
475#[test]
476fn test_complete_crate_path_in_nested_tree() {
477 let (analysis, position) = analysis_and_position(
478 "
479 //- /lib.rs
480 mod foo;
481 pub mod bar {
482 pub mod baz {
483 pub struct Spam;
484 }
485 }
486 //- /foo.rs
487 use crate::{bar::{baz::Sp<|>}};
488 ",
489 );
490 let completions = analysis.completions(position).unwrap().unwrap();
491 assert_eq_dbg(
492 r#"[CompletionItem { label: "Spam", lookup: None, snippet: None }]"#,
493 &completions,
494 );
495}
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 239d846b3..5ca86df4d 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -11,7 +11,7 @@ use std::{fs, io::Read, path::Path, time::Instant};
11use clap::{App, Arg, SubCommand}; 11use clap::{App, Arg, SubCommand};
12use join_to_string::join; 12use join_to_string::join;
13use ra_editor::{extend_selection, file_structure, syntax_tree}; 13use ra_editor::{extend_selection, file_structure, syntax_tree};
14use ra_syntax::{File, TextRange}; 14use ra_syntax::{SourceFileNode, TextRange};
15use tools::collect_tests; 15use tools::collect_tests;
16 16
17type Result<T> = ::std::result::Result<T, failure::Error>; 17type Result<T> = ::std::result::Result<T, failure::Error>;
@@ -79,9 +79,9 @@ fn main() -> Result<()> {
79 Ok(()) 79 Ok(())
80} 80}
81 81
82fn file() -> Result<File> { 82fn file() -> Result<SourceFileNode> {
83 let text = read_stdin()?; 83 let text = read_stdin()?;
84 Ok(File::parse(&text)) 84 Ok(SourceFileNode::parse(&text))
85} 85}
86 86
87fn read_stdin() -> Result<String> { 87fn read_stdin() -> Result<String> {
@@ -100,12 +100,12 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> {
100 None => bail!("No test found at line {} at {}", line, file.display()), 100 None => bail!("No test found at line {} at {}", line, file.display()),
101 Some((_start_line, test)) => test, 101 Some((_start_line, test)) => test,
102 }; 102 };
103 let file = File::parse(&test.text); 103 let file = SourceFileNode::parse(&test.text);
104 let tree = syntax_tree(&file); 104 let tree = syntax_tree(&file);
105 Ok((test.text, tree)) 105 Ok((test.text, tree))
106} 106}
107 107
108fn selections(file: &File, start: u32, end: u32) -> String { 108fn selections(file: &SourceFileNode, start: u32, end: u32) -> String {
109 let mut ranges = Vec::new(); 109 let mut ranges = Vec::new();
110 let mut cur = Some(TextRange::from_to((start - 1).into(), (end - 1).into())); 110 let mut cur = Some(TextRange::from_to((start - 1).into(), (end - 1).into()));
111 while let Some(r) = cur { 111 while let Some(r) = cur {
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs
index ef6df0d53..0139b19d3 100644
--- a/crates/ra_editor/src/code_actions.rs
+++ b/crates/ra_editor/src/code_actions.rs
@@ -3,7 +3,7 @@ use join_to_string::join;
3use ra_syntax::{ 3use ra_syntax::{
4 algo::{find_covering_node, find_leaf_at_offset}, 4 algo::{find_covering_node, find_leaf_at_offset},
5 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, 5 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner},
6 Direction, File, 6 Direction, SourceFileNode,
7 SyntaxKind::{COMMA, WHITESPACE}, 7 SyntaxKind::{COMMA, WHITESPACE},
8 SyntaxNodeRef, TextRange, TextUnit, 8 SyntaxNodeRef, TextRange, TextUnit,
9}; 9};
@@ -16,7 +16,10 @@ pub struct LocalEdit {
16 pub cursor_position: Option<TextUnit>, 16 pub cursor_position: Option<TextUnit>,
17} 17}
18 18
19pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> LocalEdit + 'a> { 19pub fn flip_comma<'a>(
20 file: &'a SourceFileNode,
21 offset: TextUnit,
22) -> Option<impl FnOnce() -> LocalEdit + 'a> {
20 let syntax = file.syntax(); 23 let syntax = file.syntax();
21 24
22 let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?; 25 let comma = find_leaf_at_offset(syntax, offset).find(|leaf| leaf.kind() == COMMA)?;
@@ -33,7 +36,10 @@ pub fn flip_comma<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
33 }) 36 })
34} 37}
35 38
36pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> LocalEdit + 'a> { 39pub fn add_derive<'a>(
40 file: &'a SourceFileNode,
41 offset: TextUnit,
42) -> Option<impl FnOnce() -> LocalEdit + 'a> {
37 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?; 43 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
38 Some(move || { 44 Some(move || {
39 let derive_attr = nominal 45 let derive_attr = nominal
@@ -58,7 +64,10 @@ pub fn add_derive<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce()
58 }) 64 })
59} 65}
60 66
61pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> LocalEdit + 'a> { 67pub fn add_impl<'a>(
68 file: &'a SourceFileNode,
69 offset: TextUnit,
70) -> Option<impl FnOnce() -> LocalEdit + 'a> {
62 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?; 71 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
63 let name = nominal.name()?; 72 let name = nominal.name()?;
64 73
@@ -98,7 +107,7 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() ->
98} 107}
99 108
100pub fn introduce_variable<'a>( 109pub fn introduce_variable<'a>(
101 file: &'a File, 110 file: &'a SourceFileNode,
102 range: TextRange, 111 range: TextRange,
103) -> Option<impl FnOnce() -> LocalEdit + 'a> { 112) -> Option<impl FnOnce() -> LocalEdit + 'a> {
104 let node = find_covering_node(file.syntax(), range); 113 let node = find_covering_node(file.syntax(), range);
diff --git a/crates/ra_editor/src/extend_selection.rs b/crates/ra_editor/src/extend_selection.rs
index 9d8df25c3..8f11d5364 100644
--- a/crates/ra_editor/src/extend_selection.rs
+++ b/crates/ra_editor/src/extend_selection.rs
@@ -1,11 +1,11 @@
1use ra_syntax::{ 1use ra_syntax::{
2 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, 2 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset},
3 Direction, File, 3 Direction, SourceFileNode,
4 SyntaxKind::*, 4 SyntaxKind::*,
5 SyntaxNodeRef, TextRange, TextUnit, 5 SyntaxNodeRef, TextRange, TextUnit,
6}; 6};
7 7
8pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> { 8pub fn extend_selection(file: &SourceFileNode, range: TextRange) -> Option<TextRange> {
9 let syntax = file.syntax(); 9 let syntax = file.syntax();
10 extend(syntax.borrowed(), range) 10 extend(syntax.borrowed(), range)
11} 11}
@@ -120,7 +120,7 @@ mod tests {
120 120
121 fn do_check(before: &str, afters: &[&str]) { 121 fn do_check(before: &str, afters: &[&str]) {
122 let (cursor, before) = extract_offset(before); 122 let (cursor, before) = extract_offset(before);
123 let file = File::parse(&before); 123 let file = SourceFileNode::parse(&before);
124 let mut range = TextRange::offset_len(cursor, 0.into()); 124 let mut range = TextRange::offset_len(cursor, 0.into());
125 for &after in afters { 125 for &after in afters {
126 range = extend_selection(&file, range).unwrap(); 126 range = extend_selection(&file, range).unwrap();
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs
index 0803c8891..2a8fa3cda 100644
--- a/crates/ra_editor/src/folding_ranges.rs
+++ b/crates/ra_editor/src/folding_ranges.rs
@@ -1,7 +1,7 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast, AstNode, Direction, File, 4 ast, AstNode, Direction, SourceFileNode,
5 SyntaxKind::{self, *}, 5 SyntaxKind::{self, *},
6 SyntaxNodeRef, TextRange, 6 SyntaxNodeRef, TextRange,
7}; 7};
@@ -18,7 +18,7 @@ pub struct Fold {
18 pub kind: FoldKind, 18 pub kind: FoldKind,
19} 19}
20 20
21pub fn folding_ranges(file: &File) -> Vec<Fold> { 21pub fn folding_ranges(file: &SourceFileNode) -> Vec<Fold> {
22 let mut res = vec![]; 22 let mut res = vec![];
23 let mut visited_comments = FxHashSet::default(); 23 let mut visited_comments = FxHashSet::default();
24 let mut visited_imports = FxHashSet::default(); 24 let mut visited_imports = FxHashSet::default();
@@ -171,7 +171,7 @@ mod tests {
171 171
172 fn do_check(text: &str, fold_kinds: &[FoldKind]) { 172 fn do_check(text: &str, fold_kinds: &[FoldKind]) {
173 let (ranges, text) = extract_ranges(text); 173 let (ranges, text) = extract_ranges(text);
174 let file = File::parse(&text); 174 let file = SourceFileNode::parse(&text);
175 let folds = folding_ranges(&file); 175 let folds = folding_ranges(&file);
176 176
177 assert_eq!( 177 assert_eq!(
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs
index f92181b86..ff4e8303d 100644
--- a/crates/ra_editor/src/lib.rs
+++ b/crates/ra_editor/src/lib.rs
@@ -30,7 +30,7 @@ pub use ra_syntax::AtomEdit;
30use ra_syntax::{ 30use ra_syntax::{
31 algo::find_leaf_at_offset, 31 algo::find_leaf_at_offset,
32 ast::{self, AstNode, NameOwner}, 32 ast::{self, AstNode, NameOwner},
33 File, 33 SourceFileNode,
34 Location, 34 Location,
35 SyntaxKind::{self, *}, 35 SyntaxKind::{self, *},
36 SyntaxNodeRef, TextRange, TextUnit, 36 SyntaxNodeRef, TextRange, TextUnit,
@@ -60,7 +60,7 @@ pub enum RunnableKind {
60 Bin, 60 Bin,
61} 61}
62 62
63pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> { 63pub fn matching_brace(file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> {
64 const BRACES: &[SyntaxKind] = &[ 64 const BRACES: &[SyntaxKind] = &[
65 L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE, 65 L_CURLY, R_CURLY, L_BRACK, R_BRACK, L_PAREN, R_PAREN, L_ANGLE, R_ANGLE,
66 ]; 66 ];
@@ -78,7 +78,7 @@ pub fn matching_brace(file: &File, offset: TextUnit) -> Option<TextUnit> {
78 Some(matching_node.range().start()) 78 Some(matching_node.range().start())
79} 79}
80 80
81pub fn highlight(file: &File) -> Vec<HighlightedRange> { 81pub fn highlight(file: &SourceFileNode) -> Vec<HighlightedRange> {
82 let mut res = Vec::new(); 82 let mut res = Vec::new();
83 for node in file.syntax().descendants() { 83 for node in file.syntax().descendants() {
84 let tag = match node.kind() { 84 let tag = match node.kind() {
@@ -100,7 +100,7 @@ pub fn highlight(file: &File) -> Vec<HighlightedRange> {
100 res 100 res
101} 101}
102 102
103pub fn diagnostics(file: &File) -> Vec<Diagnostic> { 103pub fn diagnostics(file: &SourceFileNode) -> Vec<Diagnostic> {
104 fn location_to_range(location: Location) -> TextRange { 104 fn location_to_range(location: Location) -> TextRange {
105 match location { 105 match location {
106 Location::Offset(offset) => TextRange::offset_len(offset, 1.into()), 106 Location::Offset(offset) => TextRange::offset_len(offset, 1.into()),
@@ -117,11 +117,11 @@ pub fn diagnostics(file: &File) -> Vec<Diagnostic> {
117 .collect() 117 .collect()
118} 118}
119 119
120pub fn syntax_tree(file: &File) -> String { 120pub fn syntax_tree(file: &SourceFileNode) -> String {
121 ::ra_syntax::utils::dump_tree(file.syntax()) 121 ::ra_syntax::utils::dump_tree(file.syntax())
122} 122}
123 123
124pub fn runnables(file: &File) -> Vec<Runnable> { 124pub fn runnables(file: &SourceFileNode) -> Vec<Runnable> {
125 file.syntax() 125 file.syntax()
126 .descendants() 126 .descendants()
127 .filter_map(ast::FnDef::cast) 127 .filter_map(ast::FnDef::cast)
@@ -163,7 +163,7 @@ mod tests {
163 163
164 #[test] 164 #[test]
165 fn test_highlighting() { 165 fn test_highlighting() {
166 let file = File::parse( 166 let file = SourceFileNode::parse(
167 r#" 167 r#"
168// comment 168// comment
169fn main() {} 169fn main() {}
@@ -184,7 +184,7 @@ fn main() {}
184 184
185 #[test] 185 #[test]
186 fn test_runnables() { 186 fn test_runnables() {
187 let file = File::parse( 187 let file = SourceFileNode::parse(
188 r#" 188 r#"
189fn main() {} 189fn main() {}
190 190
@@ -209,7 +209,7 @@ fn test_foo() {}
209 fn test_matching_brace() { 209 fn test_matching_brace() {
210 fn do_check(before: &str, after: &str) { 210 fn do_check(before: &str, after: &str) {
211 let (pos, before) = extract_offset(before); 211 let (pos, before) = extract_offset(before);
212 let file = File::parse(&before); 212 let file = SourceFileNode::parse(&before);
213 let new_pos = match matching_brace(&file, pos) { 213 let new_pos = match matching_brace(&file, pos) {
214 None => pos, 214 None => pos,
215 Some(pos) => pos, 215 Some(pos) => pos,
diff --git a/crates/ra_editor/src/line_index.rs b/crates/ra_editor/src/line_index.rs
index 9abbb0d09..aab7e4081 100644
--- a/crates/ra_editor/src/line_index.rs
+++ b/crates/ra_editor/src/line_index.rs
@@ -1,43 +1,124 @@
1use crate::TextUnit; 1use crate::TextUnit;
2use rustc_hash::FxHashMap;
2use superslice::Ext; 3use superslice::Ext;
3 4
4#[derive(Clone, Debug, Hash, PartialEq, Eq)] 5#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct LineIndex { 6pub struct LineIndex {
6 newlines: Vec<TextUnit>, 7 newlines: Vec<TextUnit>,
8 utf16_lines: FxHashMap<u32, Vec<Utf16Char>>,
7} 9}
8 10
9#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub struct LineCol { 12pub struct LineCol {
11 pub line: u32, 13 pub line: u32,
12 pub col: TextUnit, 14 pub col_utf16: u32,
15}
16
17#[derive(Clone, Debug, Hash, PartialEq, Eq)]
18struct Utf16Char {
19 start: TextUnit,
20 end: TextUnit,
21}
22
23impl Utf16Char {
24 fn len(&self) -> TextUnit {
25 self.end - self.start
26 }
13} 27}
14 28
15impl LineIndex { 29impl LineIndex {
16 pub fn new(text: &str) -> LineIndex { 30 pub fn new(text: &str) -> LineIndex {
31 let mut utf16_lines = FxHashMap::default();
32 let mut utf16_chars = Vec::new();
33
17 let mut newlines = vec![0.into()]; 34 let mut newlines = vec![0.into()];
18 let mut curr = 0.into(); 35 let mut curr_row = 0.into();
36 let mut curr_col = 0.into();
37 let mut line = 0;
19 for c in text.chars() { 38 for c in text.chars() {
20 curr += TextUnit::of_char(c); 39 curr_row += TextUnit::of_char(c);
21 if c == '\n' { 40 if c == '\n' {
22 newlines.push(curr); 41 newlines.push(curr_row);
42
43 // Save any utf-16 characters seen in the previous line
44 if utf16_chars.len() > 0 {
45 utf16_lines.insert(line, utf16_chars);
46 utf16_chars = Vec::new();
47 }
48
49 // Prepare for processing the next line
50 curr_col = 0.into();
51 line += 1;
52 continue;
23 } 53 }
54
55 let char_len = TextUnit::of_char(c);
56 if char_len.to_usize() > 1 {
57 utf16_chars.push(Utf16Char {
58 start: curr_col,
59 end: curr_col + char_len,
60 });
61 }
62
63 curr_col += char_len;
64 }
65 LineIndex {
66 newlines,
67 utf16_lines,
24 } 68 }
25 LineIndex { newlines }
26 } 69 }
27 70
28 pub fn line_col(&self, offset: TextUnit) -> LineCol { 71 pub fn line_col(&self, offset: TextUnit) -> LineCol {
29 let line = self.newlines.upper_bound(&offset) - 1; 72 let line = self.newlines.upper_bound(&offset) - 1;
30 let line_start_offset = self.newlines[line]; 73 let line_start_offset = self.newlines[line];
31 let col = offset - line_start_offset; 74 let col = offset - line_start_offset;
75
32 LineCol { 76 LineCol {
33 line: line as u32, 77 line: line as u32,
34 col, 78 col_utf16: self.utf8_to_utf16_col(line as u32, col) as u32,
35 } 79 }
36 } 80 }
37 81
38 pub fn offset(&self, line_col: LineCol) -> TextUnit { 82 pub fn offset(&self, line_col: LineCol) -> TextUnit {
39 //TODO: return Result 83 //TODO: return Result
40 self.newlines[line_col.line as usize] + line_col.col 84 let col = self.utf16_to_utf8_col(line_col.line, line_col.col_utf16);
85 self.newlines[line_col.line as usize] + col
86 }
87
88 fn utf8_to_utf16_col(&self, line: u32, mut col: TextUnit) -> usize {
89 if let Some(utf16_chars) = self.utf16_lines.get(&line) {
90 let mut correction = TextUnit::from_usize(0);
91 for c in utf16_chars {
92 if col >= c.end {
93 correction += c.len() - TextUnit::from_usize(1);
94 } else {
95 // From here on, all utf16 characters come *after* the character we are mapping,
96 // so we don't need to take them into account
97 break;
98 }
99 }
100
101 col -= correction;
102 }
103
104 col.to_usize()
105 }
106
107 fn utf16_to_utf8_col(&self, line: u32, col: u32) -> TextUnit {
108 let mut col: TextUnit = col.into();
109 if let Some(utf16_chars) = self.utf16_lines.get(&line) {
110 for c in utf16_chars {
111 if col >= c.start {
112 col += c.len() - TextUnit::from_usize(1);
113 } else {
114 // From here on, all utf16 characters come *after* the character we are mapping,
115 // so we don't need to take them into account
116 break;
117 }
118 }
119 }
120
121 col
41 } 122 }
42} 123}
43 124
@@ -49,63 +130,63 @@ fn test_line_index() {
49 index.line_col(0.into()), 130 index.line_col(0.into()),
50 LineCol { 131 LineCol {
51 line: 0, 132 line: 0,
52 col: 0.into() 133 col_utf16: 0
53 } 134 }
54 ); 135 );
55 assert_eq!( 136 assert_eq!(
56 index.line_col(1.into()), 137 index.line_col(1.into()),
57 LineCol { 138 LineCol {
58 line: 0, 139 line: 0,
59 col: 1.into() 140 col_utf16: 1
60 } 141 }
61 ); 142 );
62 assert_eq!( 143 assert_eq!(
63 index.line_col(5.into()), 144 index.line_col(5.into()),
64 LineCol { 145 LineCol {
65 line: 0, 146 line: 0,
66 col: 5.into() 147 col_utf16: 5
67 } 148 }
68 ); 149 );
69 assert_eq!( 150 assert_eq!(
70 index.line_col(6.into()), 151 index.line_col(6.into()),
71 LineCol { 152 LineCol {
72 line: 1, 153 line: 1,
73 col: 0.into() 154 col_utf16: 0
74 } 155 }
75 ); 156 );
76 assert_eq!( 157 assert_eq!(
77 index.line_col(7.into()), 158 index.line_col(7.into()),
78 LineCol { 159 LineCol {
79 line: 1, 160 line: 1,
80 col: 1.into() 161 col_utf16: 1
81 } 162 }
82 ); 163 );
83 assert_eq!( 164 assert_eq!(
84 index.line_col(8.into()), 165 index.line_col(8.into()),
85 LineCol { 166 LineCol {
86 line: 1, 167 line: 1,
87 col: 2.into() 168 col_utf16: 2
88 } 169 }
89 ); 170 );
90 assert_eq!( 171 assert_eq!(
91 index.line_col(10.into()), 172 index.line_col(10.into()),
92 LineCol { 173 LineCol {
93 line: 1, 174 line: 1,
94 col: 4.into() 175 col_utf16: 4
95 } 176 }
96 ); 177 );
97 assert_eq!( 178 assert_eq!(
98 index.line_col(11.into()), 179 index.line_col(11.into()),
99 LineCol { 180 LineCol {
100 line: 1, 181 line: 1,
101 col: 5.into() 182 col_utf16: 5
102 } 183 }
103 ); 184 );
104 assert_eq!( 185 assert_eq!(
105 index.line_col(12.into()), 186 index.line_col(12.into()),
106 LineCol { 187 LineCol {
107 line: 1, 188 line: 1,
108 col: 6.into() 189 col_utf16: 6
109 } 190 }
110 ); 191 );
111 192
@@ -115,35 +196,129 @@ fn test_line_index() {
115 index.line_col(0.into()), 196 index.line_col(0.into()),
116 LineCol { 197 LineCol {
117 line: 0, 198 line: 0,
118 col: 0.into() 199 col_utf16: 0
119 } 200 }
120 ); 201 );
121 assert_eq!( 202 assert_eq!(
122 index.line_col(1.into()), 203 index.line_col(1.into()),
123 LineCol { 204 LineCol {
124 line: 1, 205 line: 1,
125 col: 0.into() 206 col_utf16: 0
126 } 207 }
127 ); 208 );
128 assert_eq!( 209 assert_eq!(
129 index.line_col(2.into()), 210 index.line_col(2.into()),
130 LineCol { 211 LineCol {
131 line: 1, 212 line: 1,
132 col: 1.into() 213 col_utf16: 1
133 } 214 }
134 ); 215 );
135 assert_eq!( 216 assert_eq!(
136 index.line_col(6.into()), 217 index.line_col(6.into()),
137 LineCol { 218 LineCol {
138 line: 1, 219 line: 1,
139 col: 5.into() 220 col_utf16: 5
140 } 221 }
141 ); 222 );
142 assert_eq!( 223 assert_eq!(
143 index.line_col(7.into()), 224 index.line_col(7.into()),
144 LineCol { 225 LineCol {
145 line: 2, 226 line: 2,
146 col: 0.into() 227 col_utf16: 0
147 } 228 }
148 ); 229 );
149} 230}
231
232#[cfg(test)]
233mod test_utf8_utf16_conv {
234 use super::*;
235
236 #[test]
237 fn test_char_len() {
238 assert_eq!('メ'.len_utf8(), 3);
239 assert_eq!('メ'.len_utf16(), 1);
240 }
241
242 #[test]
243 fn test_empty_index() {
244 let col_index = LineIndex::new(
245 "
246const C: char = 'x';
247",
248 );
249 assert_eq!(col_index.utf16_lines.len(), 0);
250 }
251
252 #[test]
253 fn test_single_char() {
254 let col_index = LineIndex::new(
255 "
256const C: char = 'メ';
257",
258 );
259
260 assert_eq!(col_index.utf16_lines.len(), 1);
261 assert_eq!(col_index.utf16_lines[&1].len(), 1);
262 assert_eq!(
263 col_index.utf16_lines[&1][0],
264 Utf16Char {
265 start: 17.into(),
266 end: 20.into()
267 }
268 );
269
270 // UTF-8 to UTF-16, no changes
271 assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
272
273 // UTF-8 to UTF-16
274 assert_eq!(col_index.utf8_to_utf16_col(1, 22.into()), 20);
275
276 // UTF-16 to UTF-8, no changes
277 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextUnit::from(15));
278
279 // UTF-16 to UTF-8
280 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextUnit::from(21));
281 }
282
283 #[test]
284 fn test_string() {
285 let col_index = LineIndex::new(
286 "
287const C: char = \"メ メ\";
288",
289 );
290
291 assert_eq!(col_index.utf16_lines.len(), 1);
292 assert_eq!(col_index.utf16_lines[&1].len(), 2);
293 assert_eq!(
294 col_index.utf16_lines[&1][0],
295 Utf16Char {
296 start: 17.into(),
297 end: 20.into()
298 }
299 );
300 assert_eq!(
301 col_index.utf16_lines[&1][1],
302 Utf16Char {
303 start: 21.into(),
304 end: 24.into()
305 }
306 );
307
308 // UTF-8 to UTF-16
309 assert_eq!(col_index.utf8_to_utf16_col(1, 15.into()), 15);
310
311 assert_eq!(col_index.utf8_to_utf16_col(1, 21.into()), 19);
312 assert_eq!(col_index.utf8_to_utf16_col(1, 25.into()), 21);
313
314 assert!(col_index.utf8_to_utf16_col(2, 15.into()) == 15);
315
316 // UTF-16 to UTF-8
317 assert_eq!(col_index.utf16_to_utf8_col(1, 15), TextUnit::from_usize(15));
318
319 assert_eq!(col_index.utf16_to_utf8_col(1, 18), TextUnit::from_usize(20));
320 assert_eq!(col_index.utf16_to_utf8_col(1, 19), TextUnit::from_usize(23));
321
322 assert_eq!(col_index.utf16_to_utf8_col(2, 15), TextUnit::from_usize(15));
323 }
324}
diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs
index 4e602d0e3..6d3b0514a 100644
--- a/crates/ra_editor/src/symbols.rs
+++ b/crates/ra_editor/src/symbols.rs
@@ -2,8 +2,8 @@ use crate::TextRange;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 algo::visit::{visitor, Visitor}, 4 algo::visit::{visitor, Visitor},
5 ast::{self, NameOwner}, 5 ast::{self, DocCommentsOwner, NameOwner},
6 AstNode, File, SmolStr, SyntaxKind, SyntaxNodeRef, WalkEvent, 6 AstNode, SourceFileNode, SmolStr, SyntaxKind, SyntaxNodeRef, WalkEvent,
7}; 7};
8 8
9#[derive(Debug, Clone)] 9#[derive(Debug, Clone)]
@@ -22,7 +22,37 @@ pub struct FileSymbol {
22 pub kind: SyntaxKind, 22 pub kind: SyntaxKind,
23} 23}
24 24
25pub fn file_symbols(file: &File) -> Vec<FileSymbol> { 25impl FileSymbol {
26 pub fn docs(&self, file: &SourceFileNode) -> Option<String> {
27 file.syntax()
28 .descendants()
29 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
30 .filter_map(|node: SyntaxNodeRef| {
31 fn doc_comments<'a, N: DocCommentsOwner<'a>>(node: N) -> Option<String> {
32 let comments = node.doc_comment_text();
33 if comments.is_empty() {
34 None
35 } else {
36 Some(comments)
37 }
38 }
39
40 visitor()
41 .visit(doc_comments::<ast::FnDef>)
42 .visit(doc_comments::<ast::StructDef>)
43 .visit(doc_comments::<ast::EnumDef>)
44 .visit(doc_comments::<ast::TraitDef>)
45 .visit(doc_comments::<ast::Module>)
46 .visit(doc_comments::<ast::TypeDef>)
47 .visit(doc_comments::<ast::ConstDef>)
48 .visit(doc_comments::<ast::StaticDef>)
49 .accept(node)?
50 })
51 .nth(0)
52 }
53}
54
55pub fn file_symbols(file: &SourceFileNode) -> Vec<FileSymbol> {
26 file.syntax().descendants().filter_map(to_symbol).collect() 56 file.syntax().descendants().filter_map(to_symbol).collect()
27} 57}
28 58
@@ -47,7 +77,7 @@ fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
47 .accept(node)? 77 .accept(node)?
48} 78}
49 79
50pub fn file_structure(file: &File) -> Vec<StructureNode> { 80pub fn file_structure(file: &SourceFileNode) -> Vec<StructureNode> {
51 let mut res = Vec::new(); 81 let mut res = Vec::new();
52 let mut stack = Vec::new(); 82 let mut stack = Vec::new();
53 83
@@ -123,7 +153,7 @@ mod tests {
123 153
124 #[test] 154 #[test]
125 fn test_file_structure() { 155 fn test_file_structure() {
126 let file = File::parse( 156 let file = SourceFileNode::parse(
127 r#" 157 r#"
128struct Foo { 158struct Foo {
129 x: i32 159 x: i32
diff --git a/crates/ra_editor/src/test_utils.rs b/crates/ra_editor/src/test_utils.rs
index bc3d700f6..cbeb6433b 100644
--- a/crates/ra_editor/src/test_utils.rs
+++ b/crates/ra_editor/src/test_utils.rs
@@ -1,10 +1,14 @@
1use crate::LocalEdit; 1use crate::LocalEdit;
2pub use crate::_test_utils::*; 2pub use crate::_test_utils::*;
3use ra_syntax::{File, TextRange, TextUnit}; 3use ra_syntax::{SourceFileNode, TextRange, TextUnit};
4 4
5pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>>(before: &str, after: &str, f: F) { 5pub fn check_action<F: Fn(&SourceFileNode, TextUnit) -> Option<LocalEdit>>(
6 before: &str,
7 after: &str,
8 f: F,
9) {
6 let (before_cursor_pos, before) = extract_offset(before); 10 let (before_cursor_pos, before) = extract_offset(before);
7 let file = File::parse(&before); 11 let file = SourceFileNode::parse(&before);
8 let result = f(&file, before_cursor_pos).expect("code action is not applicable"); 12 let result = f(&file, before_cursor_pos).expect("code action is not applicable");
9 let actual = result.edit.apply(&before); 13 let actual = result.edit.apply(&before);
10 let actual_cursor_pos = match result.cursor_position { 14 let actual_cursor_pos = match result.cursor_position {
@@ -15,13 +19,13 @@ pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>>(before: &str, a
15 assert_eq_text!(after, &actual); 19 assert_eq_text!(after, &actual);
16} 20}
17 21
18pub fn check_action_range<F: Fn(&File, TextRange) -> Option<LocalEdit>>( 22pub fn check_action_range<F: Fn(&SourceFileNode, TextRange) -> Option<LocalEdit>>(
19 before: &str, 23 before: &str,
20 after: &str, 24 after: &str,
21 f: F, 25 f: F,
22) { 26) {
23 let (range, before) = extract_range(before); 27 let (range, before) = extract_range(before);
24 let file = File::parse(&before); 28 let file = SourceFileNode::parse(&before);
25 let result = f(&file, range).expect("code action is not applicable"); 29 let result = f(&file, range).expect("code action is not applicable");
26 let actual = result.edit.apply(&before); 30 let actual = result.edit.apply(&before);
27 let actual_cursor_pos = match result.cursor_position { 31 let actual_cursor_pos = match result.cursor_position {
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs
index 5a457d148..f894d8392 100644
--- a/crates/ra_editor/src/typing.rs
+++ b/crates/ra_editor/src/typing.rs
@@ -4,14 +4,14 @@ use ra_syntax::{
4 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset}, 4 algo::{find_covering_node, find_leaf_at_offset, LeafAtOffset},
5 ast, 5 ast,
6 text_utils::{contains_offset_nonstrict, intersect}, 6 text_utils::{contains_offset_nonstrict, intersect},
7 AstNode, File, SyntaxKind, 7 AstNode, SourceFileNode, SyntaxKind,
8 SyntaxKind::*, 8 SyntaxKind::*,
9 SyntaxNodeRef, TextRange, TextUnit, 9 SyntaxNodeRef, TextRange, TextUnit,
10}; 10};
11 11
12use crate::{find_node_at_offset, EditBuilder, LocalEdit}; 12use crate::{find_node_at_offset, EditBuilder, LocalEdit};
13 13
14pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { 14pub fn join_lines(file: &SourceFileNode, range: TextRange) -> LocalEdit {
15 let range = if range.is_empty() { 15 let range = if range.is_empty() {
16 let syntax = file.syntax(); 16 let syntax = file.syntax();
17 let text = syntax.text().slice(range.start()..); 17 let text = syntax.text().slice(range.start()..);
@@ -55,7 +55,7 @@ pub fn join_lines(file: &File, range: TextRange) -> LocalEdit {
55 } 55 }
56} 56}
57 57
58pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> { 58pub fn on_enter(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit> {
59 let comment = find_leaf_at_offset(file.syntax(), offset) 59 let comment = find_leaf_at_offset(file.syntax(), offset)
60 .left_biased() 60 .left_biased()
61 .and_then(ast::Comment::cast)?; 61 .and_then(ast::Comment::cast)?;
@@ -80,7 +80,7 @@ pub fn on_enter(file: &File, offset: TextUnit) -> Option<LocalEdit> {
80 }) 80 })
81} 81}
82 82
83fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> { 83fn node_indent<'a>(file: &'a SourceFileNode, node: SyntaxNodeRef) -> Option<&'a str> {
84 let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) { 84 let ws = match find_leaf_at_offset(file.syntax(), node.range().start()) {
85 LeafAtOffset::Between(l, r) => { 85 LeafAtOffset::Between(l, r) => {
86 assert!(r == node); 86 assert!(r == node);
@@ -100,7 +100,7 @@ fn node_indent<'a>(file: &'a File, node: SyntaxNodeRef) -> Option<&'a str> {
100 Some(&text[pos..]) 100 Some(&text[pos..])
101} 101}
102 102
103pub fn on_eq_typed(file: &File, offset: TextUnit) -> Option<LocalEdit> { 103pub fn on_eq_typed(file: &SourceFileNode, offset: TextUnit) -> Option<LocalEdit> {
104 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; 104 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
105 if let_stmt.has_semi() { 105 if let_stmt.has_semi() {
106 return None; 106 return None;
@@ -390,7 +390,7 @@ fn foo() {
390 390
391 fn check_join_lines_sel(before: &str, after: &str) { 391 fn check_join_lines_sel(before: &str, after: &str) {
392 let (sel, before) = extract_range(before); 392 let (sel, before) = extract_range(before);
393 let file = File::parse(&before); 393 let file = SourceFileNode::parse(&before);
394 let result = join_lines(&file, sel); 394 let result = join_lines(&file, sel);
395 let actual = result.edit.apply(&before); 395 let actual = result.edit.apply(&before);
396 assert_eq_text!(after, &actual); 396 assert_eq_text!(after, &actual);
@@ -469,7 +469,7 @@ pub fn handle_find_matching_brace() {
469 fn test_on_eq_typed() { 469 fn test_on_eq_typed() {
470 fn do_check(before: &str, after: &str) { 470 fn do_check(before: &str, after: &str) {
471 let (offset, before) = extract_offset(before); 471 let (offset, before) = extract_offset(before);
472 let file = File::parse(&before); 472 let file = SourceFileNode::parse(&before);
473 let result = on_eq_typed(&file, offset).unwrap(); 473 let result = on_eq_typed(&file, offset).unwrap();
474 let actual = result.edit.apply(&before); 474 let actual = result.edit.apply(&before);
475 assert_eq_text!(after, &actual); 475 assert_eq_text!(after, &actual);
@@ -513,7 +513,7 @@ fn foo() {
513 fn test_on_enter() { 513 fn test_on_enter() {
514 fn apply_on_enter(before: &str) -> Option<String> { 514 fn apply_on_enter(before: &str) -> Option<String> {
515 let (offset, before) = extract_offset(before); 515 let (offset, before) = extract_offset(before);
516 let file = File::parse(&before); 516 let file = SourceFileNode::parse(&before);
517 let result = on_enter(&file, offset)?; 517 let result = on_enter(&file, offset)?;
518 let actual = result.edit.apply(&before); 518 let actual = result.edit.apply(&before);
519 let actual = add_cursor(&actual, result.cursor_position.unwrap()); 519 let actual = add_cursor(&actual, result.cursor_position.unwrap());
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index f29dafc17..79d86f9b2 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -14,7 +14,7 @@ serde = "1.0.71"
14serde_derive = "1.0.71" 14serde_derive = "1.0.71"
15drop_bomb = "0.1.0" 15drop_bomb = "0.1.0"
16crossbeam-channel = "0.2.4" 16crossbeam-channel = "0.2.4"
17flexi_logger = "0.9.1" 17flexi_logger = "0.10.0"
18log = "0.4.3" 18log = "0.4.3"
19url_serde = "0.2.0" 19url_serde = "0.2.0"
20languageserver-types = "0.51.0" 20languageserver-types = "0.51.0"
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index 0d02c8073..bcf857fce 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -16,7 +16,7 @@ pub fn server_capabilities() -> ServerCapabilities {
16 save: None, 16 save: None,
17 }, 17 },
18 )), 18 )),
19 hover_provider: None, 19 hover_provider: Some(true),
20 completion_provider: Some(CompletionOptions { 20 completion_provider: Some(CompletionOptions {
21 resolve_provider: None, 21 resolve_provider: None,
22 trigger_characters: None, 22 trigger_characters: None,
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index fa04f4b00..5d5a0c55e 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -2,7 +2,7 @@ use languageserver_types::{
2 Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier, 2 Location, Position, Range, SymbolKind, TextDocumentEdit, TextDocumentIdentifier,
3 TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier, 3 TextDocumentItem, TextDocumentPositionParams, TextEdit, Url, VersionedTextDocumentIdentifier,
4}; 4};
5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileEdit, FilePosition}; 5use ra_analysis::{FileId, FileSystemEdit, SourceChange, SourceFileNodeEdit, FilePosition};
6use ra_editor::{AtomEdit, Edit, LineCol, LineIndex}; 6use ra_editor::{AtomEdit, Edit, LineCol, LineIndex};
7use ra_syntax::{SyntaxKind, TextRange, TextUnit}; 7use ra_syntax::{SyntaxKind, TextRange, TextUnit};
8 8
@@ -49,10 +49,9 @@ impl ConvWith for Position {
49 type Output = TextUnit; 49 type Output = TextUnit;
50 50
51 fn conv_with(self, line_index: &LineIndex) -> TextUnit { 51 fn conv_with(self, line_index: &LineIndex) -> TextUnit {
52 // TODO: UTF-16
53 let line_col = LineCol { 52 let line_col = LineCol {
54 line: self.line as u32, 53 line: self.line as u32,
55 col: (self.character as u32).into(), 54 col_utf16: self.character as u32,
56 }; 55 };
57 line_index.offset(line_col) 56 line_index.offset(line_col)
58 } 57 }
@@ -64,8 +63,10 @@ impl ConvWith for TextUnit {
64 63
65 fn conv_with(self, line_index: &LineIndex) -> Position { 64 fn conv_with(self, line_index: &LineIndex) -> Position {
66 let line_col = line_index.line_col(self); 65 let line_col = line_index.line_col(self);
67 // TODO: UTF-16 66 Position::new(
68 Position::new(u64::from(line_col.line), u64::from(u32::from(line_col.col))) 67 u64::from(line_col.line),
68 u64::from(u32::from(line_col.col_utf16)),
69 )
69 } 70 }
70} 71}
71 72
@@ -203,8 +204,10 @@ impl TryConvWith for SourceChange {
203 .map(|it| it.edits.as_slice()) 204 .map(|it| it.edits.as_slice())
204 .unwrap_or(&[]); 205 .unwrap_or(&[]);
205 let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits); 206 let line_col = translate_offset_with_edit(&*line_index, pos.offset, edits);
206 let position = 207 let position = Position::new(
207 Position::new(u64::from(line_col.line), u64::from(u32::from(line_col.col))); 208 u64::from(line_col.line),
209 u64::from(u32::from(line_col.col_utf16)),
210 );
208 Some(TextDocumentPositionParams { 211 Some(TextDocumentPositionParams {
209 text_document: TextDocumentIdentifier::new(pos.file_id.try_conv_with(world)?), 212 text_document: TextDocumentIdentifier::new(pos.file_id.try_conv_with(world)?),
210 position, 213 position,
@@ -247,17 +250,17 @@ fn translate_offset_with_edit(
247 if in_edit_line_col.line == 0 { 250 if in_edit_line_col.line == 0 {
248 LineCol { 251 LineCol {
249 line: edit_line_col.line, 252 line: edit_line_col.line,
250 col: edit_line_col.col + in_edit_line_col.col, 253 col_utf16: edit_line_col.col_utf16 + in_edit_line_col.col_utf16,
251 } 254 }
252 } else { 255 } else {
253 LineCol { 256 LineCol {
254 line: edit_line_col.line + in_edit_line_col.line, 257 line: edit_line_col.line + in_edit_line_col.line,
255 col: in_edit_line_col.col, 258 col_utf16: in_edit_line_col.col_utf16,
256 } 259 }
257 } 260 }
258} 261}
259 262
260impl TryConvWith for SourceFileEdit { 263impl TryConvWith for SourceFileNodeEdit {
261 type Ctx = ServerWorld; 264 type Ctx = ServerWorld;
262 type Output = TextDocumentEdit; 265 type Output = TextDocumentEdit;
263 fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> { 266 fn try_conv_with(self, world: &ServerWorld) -> Result<TextDocumentEdit> {
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index c07eb0140..26bcddd8e 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -2,10 +2,14 @@
2extern crate log; 2extern crate log;
3#[macro_use] 3#[macro_use]
4extern crate failure; 4extern crate failure;
5#[macro_use]
6extern crate serde_derive;
7extern crate serde;
5extern crate flexi_logger; 8extern crate flexi_logger;
6extern crate gen_lsp_server; 9extern crate gen_lsp_server;
7extern crate ra_lsp_server; 10extern crate ra_lsp_server;
8 11
12use serde::Deserialize;
9use flexi_logger::{Duplicate, Logger}; 13use flexi_logger::{Duplicate, Logger};
10use gen_lsp_server::{run_server, stdio_transport}; 14use gen_lsp_server::{run_server, stdio_transport};
11use ra_lsp_server::Result; 15use ra_lsp_server::Result;
@@ -30,6 +34,12 @@ fn main() -> Result<()> {
30 } 34 }
31} 35}
32 36
37#[derive(Deserialize)]
38#[serde(rename_all = "camelCase")]
39struct InitializationOptions {
40 publish_decorations: bool,
41}
42
33fn main_inner() -> Result<()> { 43fn main_inner() -> Result<()> {
34 let (receiver, sender, threads) = stdio_transport(); 44 let (receiver, sender, threads) = stdio_transport();
35 let cwd = ::std::env::current_dir()?; 45 let cwd = ::std::env::current_dir()?;
@@ -42,7 +52,12 @@ fn main_inner() -> Result<()> {
42 .root_uri 52 .root_uri
43 .and_then(|it| it.to_file_path().ok()) 53 .and_then(|it| it.to_file_path().ok())
44 .unwrap_or(cwd); 54 .unwrap_or(cwd);
45 ra_lsp_server::main_loop(false, root, r, s) 55 let publish_decorations = params
56 .initialization_options
57 .and_then(|v| InitializationOptions::deserialize(v).ok())
58 .map(|it| it.publish_decorations)
59 == Some(true);
60 ra_lsp_server::main_loop(false, root, publish_decorations, r, s)
46 }, 61 },
47 )?; 62 )?;
48 info!("shutting down IO..."); 63 info!("shutting down IO...");
@@ -50,3 +65,27 @@ fn main_inner() -> Result<()> {
50 info!("... IO is down"); 65 info!("... IO is down");
51 Ok(()) 66 Ok(())
52} 67}
68
69/*
70 (let ((backend (eglot-xref-backend)))
71 (mapcar
72 (lambda (xref)
73 (let ((loc (xref-item-location xref)))
74 (propertize
75 (concat
76 (when (xref-file-location-p loc)
77 (with-slots (file line column) loc
78 (format "%s:%s:%s:"
79 (propertize (file-relative-name file)
80 'face 'compilation-info)
81 (propertize (format "%s" line)
82 'face 'compilation-line
83 )
84 column)))
85 (xref-item-summary xref))
86 'xref xref)))
87 (xref-backend-apropos backend "Analysis"))
88 )
89
90
91*/
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 5314a333e..c872b0dc4 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -4,9 +4,9 @@ use gen_lsp_server::ErrorCode;
4use languageserver_types::{ 4use languageserver_types::{
5 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic, 5 CodeActionResponse, Command, CompletionItem, CompletionItemKind, Diagnostic,
6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, 6 DiagnosticSeverity, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind,
7 FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, Position, 7 FoldingRangeParams, InsertTextFormat, Location, MarkupContent, MarkupKind, MarkedString, Position,
8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit, 8 PrepareRenameResponse, RenameParams, SymbolInformation, TextDocumentIdentifier, TextEdit,
9 WorkspaceEdit, ParameterInformation, SignatureInformation, 9 WorkspaceEdit, ParameterInformation, SignatureInformation, Hover, HoverContents,
10}; 10};
11use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition}; 11use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FilePosition};
12use ra_syntax::text_utils::contains_offset_nonstrict; 12use ra_syntax::text_utils::contains_offset_nonstrict;
@@ -478,6 +478,30 @@ pub fn handle_signature_help(
478 } 478 }
479} 479}
480 480
481pub fn handle_hover(
482 world: ServerWorld,
483 params: req::TextDocumentPositionParams,
484) -> Result<Option<Hover>> {
485 let position = params.try_conv_with(&world)?;
486 let line_index = world.analysis().file_line_index(position.file_id);
487
488 for (file_id, symbol) in world.analysis().approximately_resolve_symbol(position)? {
489 let range = symbol.node_range.conv_with(&line_index);
490 let comment = world.analysis.doc_comment_for(file_id, symbol)?;
491
492 if comment.is_some() {
493 let contents = HoverContents::Scalar(MarkedString::String(comment.unwrap()));
494
495 return Ok(Some(Hover {
496 contents,
497 range: Some(range),
498 }));
499 }
500 }
501
502 Ok(None)
503}
504
481pub fn handle_prepare_rename( 505pub fn handle_prepare_rename(
482 world: ServerWorld, 506 world: ServerWorld,
483 params: req::TextDocumentPositionParams, 507 params: req::TextDocumentPositionParams,
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs
index 229d1b0f7..78d93741a 100644
--- a/crates/ra_lsp_server/src/main_loop/mod.rs
+++ b/crates/ra_lsp_server/src/main_loop/mod.rs
@@ -48,6 +48,7 @@ enum Task {
48pub fn main_loop( 48pub fn main_loop(
49 internal_mode: bool, 49 internal_mode: bool,
50 root: PathBuf, 50 root: PathBuf,
51 publish_decorations: bool,
51 msg_receiver: &Receiver<RawMessage>, 52 msg_receiver: &Receiver<RawMessage>,
52 msg_sender: &Sender<RawMessage>, 53 msg_sender: &Sender<RawMessage>,
53) -> Result<()> { 54) -> Result<()> {
@@ -67,6 +68,7 @@ pub fn main_loop(
67 let mut subs = Subscriptions::new(); 68 let mut subs = Subscriptions::new();
68 let main_res = main_loop_inner( 69 let main_res = main_loop_inner(
69 internal_mode, 70 internal_mode,
71 publish_decorations,
70 root, 72 root,
71 &pool, 73 &pool,
72 msg_sender, 74 msg_sender,
@@ -99,6 +101,7 @@ pub fn main_loop(
99 101
100fn main_loop_inner( 102fn main_loop_inner(
101 internal_mode: bool, 103 internal_mode: bool,
104 publish_decorations: bool,
102 ws_root: PathBuf, 105 ws_root: PathBuf,
103 pool: &ThreadPool, 106 pool: &ThreadPool,
104 msg_sender: &Sender<RawMessage>, 107 msg_sender: &Sender<RawMessage>,
@@ -210,6 +213,7 @@ fn main_loop_inner(
210 update_file_notifications_on_threadpool( 213 update_file_notifications_on_threadpool(
211 pool, 214 pool,
212 state.snapshot(), 215 state.snapshot(),
216 publish_decorations,
213 task_sender.clone(), 217 task_sender.clone(),
214 subs.subscriptions(), 218 subs.subscriptions(),
215 ) 219 )
@@ -259,6 +263,7 @@ fn on_request(
259 .on::<req::CodeActionRequest>(handlers::handle_code_action)? 263 .on::<req::CodeActionRequest>(handlers::handle_code_action)?
260 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? 264 .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)?
261 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)? 265 .on::<req::SignatureHelpRequest>(handlers::handle_signature_help)?
266 .on::<req::HoverRequest>(handlers::handle_hover)?
262 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)? 267 .on::<req::PrepareRenameRequest>(handlers::handle_prepare_rename)?
263 .on::<req::Rename>(handlers::handle_rename)? 268 .on::<req::Rename>(handlers::handle_rename)?
264 .on::<req::References>(handlers::handle_references)? 269 .on::<req::References>(handlers::handle_references)?
@@ -415,6 +420,7 @@ impl<'a> PoolDispatcher<'a> {
415fn update_file_notifications_on_threadpool( 420fn update_file_notifications_on_threadpool(
416 pool: &ThreadPool, 421 pool: &ThreadPool,
417 world: ServerWorld, 422 world: ServerWorld,
423 publish_decorations: bool,
418 sender: Sender<Task>, 424 sender: Sender<Task>,
419 subscriptions: Vec<FileId>, 425 subscriptions: Vec<FileId>,
420) { 426) {
@@ -431,15 +437,17 @@ fn update_file_notifications_on_threadpool(
431 sender.send(Task::Notify(not)); 437 sender.send(Task::Notify(not));
432 } 438 }
433 } 439 }
434 match handlers::publish_decorations(&world, file_id) { 440 if publish_decorations {
435 Err(e) => { 441 match handlers::publish_decorations(&world, file_id) {
436 if !is_canceled(&e) { 442 Err(e) => {
437 error!("failed to compute decorations: {:?}", e); 443 if !is_canceled(&e) {
444 error!("failed to compute decorations: {:?}", e);
445 }
446 }
447 Ok(params) => {
448 let not = RawNotification::new::<req::PublishDecorations>(&params);
449 sender.send(Task::Notify(not))
438 } 450 }
439 }
440 Ok(params) => {
441 let not = RawNotification::new::<req::PublishDecorations>(&params);
442 sender.send(Task::Notify(not))
443 } 451 }
444 } 452 }
445 } 453 }
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index b90d21135..88d379bfa 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -55,7 +55,7 @@ impl Server {
55 "test server", 55 "test server",
56 128, 56 128,
57 move |mut msg_receiver, mut msg_sender| { 57 move |mut msg_receiver, mut msg_sender| {
58 main_loop(true, path, &mut msg_receiver, &mut msg_sender).unwrap() 58 main_loop(true, path, true, &mut msg_receiver, &mut msg_sender).unwrap()
59 }, 59 },
60 ); 60 );
61 let res = Server { 61 let res = Server {
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 97d259570..54ee72386 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -8,6 +8,7 @@ description = "Comment and whitespace preserving parser for the Rust langauge"
8repository = "https://github.com/rust-analyzer/rust-analyzer" 8repository = "https://github.com/rust-analyzer/rust-analyzer"
9 9
10[dependencies] 10[dependencies]
11arrayvec = "0.4.7"
11unicode-xid = "0.1.0" 12unicode-xid = "0.1.0"
12itertools = "0.7.8" 13itertools = "0.7.8"
13drop_bomb = "0.1.4" 14drop_bomb = "0.1.4"
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 420d9090c..bf056131e 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -9,6 +9,8 @@
9 9
10#![cfg_attr(rustfmt, rustfmt_skip)] 10#![cfg_attr(rustfmt, rustfmt_skip)]
11 11
12use std::hash::{Hash, Hasher};
13
12use crate::{ 14use crate::{
13 ast, 15 ast,
14 SyntaxNode, SyntaxNodeRef, AstNode, 16 SyntaxNode, SyntaxNodeRef, AstNode,
@@ -17,12 +19,20 @@ use crate::{
17}; 19};
18 20
19// ArgList 21// ArgList
20#[derive(Debug, Clone, Copy)] 22#[derive(Debug, Clone, Copy,)]
21pub struct ArgListNode<R: TreeRoot<RaTypes> = OwnedRoot> { 23pub struct ArgListNode<R: TreeRoot<RaTypes> = OwnedRoot> {
22 syntax: SyntaxNode<R>, 24 pub(crate) syntax: SyntaxNode<R>,
23} 25}
24pub type ArgList<'a> = ArgListNode<RefRoot<'a>>; 26pub type ArgList<'a> = ArgListNode<RefRoot<'a>>;
25 27
28impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ArgListNode<R1>> for ArgListNode<R2> {
29 fn eq(&self, other: &ArgListNode<R1>) -> bool { self.syntax == other.syntax }
30}
31impl<R: TreeRoot<RaTypes>> Eq for ArgListNode<R> {}
32impl<R: TreeRoot<RaTypes>> Hash for ArgListNode<R> {
33 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
34}
35
26impl<'a> AstNode<'a> for ArgList<'a> { 36impl<'a> AstNode<'a> for ArgList<'a> {
27 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 37 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
28 match syntax.kind() { 38 match syntax.kind() {
@@ -50,12 +60,20 @@ impl<'a> ArgList<'a> {
50} 60}
51 61
52// ArrayExpr 62// ArrayExpr
53#[derive(Debug, Clone, Copy)] 63#[derive(Debug, Clone, Copy,)]
54pub struct ArrayExprNode<R: TreeRoot<RaTypes> = OwnedRoot> { 64pub struct ArrayExprNode<R: TreeRoot<RaTypes> = OwnedRoot> {
55 syntax: SyntaxNode<R>, 65 pub(crate) syntax: SyntaxNode<R>,
56} 66}
57pub type ArrayExpr<'a> = ArrayExprNode<RefRoot<'a>>; 67pub type ArrayExpr<'a> = ArrayExprNode<RefRoot<'a>>;
58 68
69impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ArrayExprNode<R1>> for ArrayExprNode<R2> {
70 fn eq(&self, other: &ArrayExprNode<R1>) -> bool { self.syntax == other.syntax }
71}
72impl<R: TreeRoot<RaTypes>> Eq for ArrayExprNode<R> {}
73impl<R: TreeRoot<RaTypes>> Hash for ArrayExprNode<R> {
74 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
75}
76
59impl<'a> AstNode<'a> for ArrayExpr<'a> { 77impl<'a> AstNode<'a> for ArrayExpr<'a> {
60 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 78 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
61 match syntax.kind() { 79 match syntax.kind() {
@@ -79,12 +97,20 @@ impl<R: TreeRoot<RaTypes>> ArrayExprNode<R> {
79impl<'a> ArrayExpr<'a> {} 97impl<'a> ArrayExpr<'a> {}
80 98
81// ArrayType 99// ArrayType
82#[derive(Debug, Clone, Copy)] 100#[derive(Debug, Clone, Copy,)]
83pub struct ArrayTypeNode<R: TreeRoot<RaTypes> = OwnedRoot> { 101pub struct ArrayTypeNode<R: TreeRoot<RaTypes> = OwnedRoot> {
84 syntax: SyntaxNode<R>, 102 pub(crate) syntax: SyntaxNode<R>,
85} 103}
86pub type ArrayType<'a> = ArrayTypeNode<RefRoot<'a>>; 104pub type ArrayType<'a> = ArrayTypeNode<RefRoot<'a>>;
87 105
106impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ArrayTypeNode<R1>> for ArrayTypeNode<R2> {
107 fn eq(&self, other: &ArrayTypeNode<R1>) -> bool { self.syntax == other.syntax }
108}
109impl<R: TreeRoot<RaTypes>> Eq for ArrayTypeNode<R> {}
110impl<R: TreeRoot<RaTypes>> Hash for ArrayTypeNode<R> {
111 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
112}
113
88impl<'a> AstNode<'a> for ArrayType<'a> { 114impl<'a> AstNode<'a> for ArrayType<'a> {
89 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 115 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
90 match syntax.kind() { 116 match syntax.kind() {
@@ -108,12 +134,20 @@ impl<R: TreeRoot<RaTypes>> ArrayTypeNode<R> {
108impl<'a> ArrayType<'a> {} 134impl<'a> ArrayType<'a> {}
109 135
110// Attr 136// Attr
111#[derive(Debug, Clone, Copy)] 137#[derive(Debug, Clone, Copy,)]
112pub struct AttrNode<R: TreeRoot<RaTypes> = OwnedRoot> { 138pub struct AttrNode<R: TreeRoot<RaTypes> = OwnedRoot> {
113 syntax: SyntaxNode<R>, 139 pub(crate) syntax: SyntaxNode<R>,
114} 140}
115pub type Attr<'a> = AttrNode<RefRoot<'a>>; 141pub type Attr<'a> = AttrNode<RefRoot<'a>>;
116 142
143impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<AttrNode<R1>> for AttrNode<R2> {
144 fn eq(&self, other: &AttrNode<R1>) -> bool { self.syntax == other.syntax }
145}
146impl<R: TreeRoot<RaTypes>> Eq for AttrNode<R> {}
147impl<R: TreeRoot<RaTypes>> Hash for AttrNode<R> {
148 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
149}
150
117impl<'a> AstNode<'a> for Attr<'a> { 151impl<'a> AstNode<'a> for Attr<'a> {
118 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 152 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
119 match syntax.kind() { 153 match syntax.kind() {
@@ -141,12 +175,20 @@ impl<'a> Attr<'a> {
141} 175}
142 176
143// BinExpr 177// BinExpr
144#[derive(Debug, Clone, Copy)] 178#[derive(Debug, Clone, Copy,)]
145pub struct BinExprNode<R: TreeRoot<RaTypes> = OwnedRoot> { 179pub struct BinExprNode<R: TreeRoot<RaTypes> = OwnedRoot> {
146 syntax: SyntaxNode<R>, 180 pub(crate) syntax: SyntaxNode<R>,
147} 181}
148pub type BinExpr<'a> = BinExprNode<RefRoot<'a>>; 182pub type BinExpr<'a> = BinExprNode<RefRoot<'a>>;
149 183
184impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<BinExprNode<R1>> for BinExprNode<R2> {
185 fn eq(&self, other: &BinExprNode<R1>) -> bool { self.syntax == other.syntax }
186}
187impl<R: TreeRoot<RaTypes>> Eq for BinExprNode<R> {}
188impl<R: TreeRoot<RaTypes>> Hash for BinExprNode<R> {
189 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
190}
191
150impl<'a> AstNode<'a> for BinExpr<'a> { 192impl<'a> AstNode<'a> for BinExpr<'a> {
151 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 193 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
152 match syntax.kind() { 194 match syntax.kind() {
@@ -170,12 +212,20 @@ impl<R: TreeRoot<RaTypes>> BinExprNode<R> {
170impl<'a> BinExpr<'a> {} 212impl<'a> BinExpr<'a> {}
171 213
172// BindPat 214// BindPat
173#[derive(Debug, Clone, Copy)] 215#[derive(Debug, Clone, Copy,)]
174pub struct BindPatNode<R: TreeRoot<RaTypes> = OwnedRoot> { 216pub struct BindPatNode<R: TreeRoot<RaTypes> = OwnedRoot> {
175 syntax: SyntaxNode<R>, 217 pub(crate) syntax: SyntaxNode<R>,
176} 218}
177pub type BindPat<'a> = BindPatNode<RefRoot<'a>>; 219pub type BindPat<'a> = BindPatNode<RefRoot<'a>>;
178 220
221impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<BindPatNode<R1>> for BindPatNode<R2> {
222 fn eq(&self, other: &BindPatNode<R1>) -> bool { self.syntax == other.syntax }
223}
224impl<R: TreeRoot<RaTypes>> Eq for BindPatNode<R> {}
225impl<R: TreeRoot<RaTypes>> Hash for BindPatNode<R> {
226 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
227}
228
179impl<'a> AstNode<'a> for BindPat<'a> { 229impl<'a> AstNode<'a> for BindPat<'a> {
180 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 230 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
181 match syntax.kind() { 231 match syntax.kind() {
@@ -200,12 +250,20 @@ impl<'a> ast::NameOwner<'a> for BindPat<'a> {}
200impl<'a> BindPat<'a> {} 250impl<'a> BindPat<'a> {}
201 251
202// Block 252// Block
203#[derive(Debug, Clone, Copy)] 253#[derive(Debug, Clone, Copy,)]
204pub struct BlockNode<R: TreeRoot<RaTypes> = OwnedRoot> { 254pub struct BlockNode<R: TreeRoot<RaTypes> = OwnedRoot> {
205 syntax: SyntaxNode<R>, 255 pub(crate) syntax: SyntaxNode<R>,
206} 256}
207pub type Block<'a> = BlockNode<RefRoot<'a>>; 257pub type Block<'a> = BlockNode<RefRoot<'a>>;
208 258
259impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<BlockNode<R1>> for BlockNode<R2> {
260 fn eq(&self, other: &BlockNode<R1>) -> bool { self.syntax == other.syntax }
261}
262impl<R: TreeRoot<RaTypes>> Eq for BlockNode<R> {}
263impl<R: TreeRoot<RaTypes>> Hash for BlockNode<R> {
264 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
265}
266
209impl<'a> AstNode<'a> for Block<'a> { 267impl<'a> AstNode<'a> for Block<'a> {
210 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 268 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
211 match syntax.kind() { 269 match syntax.kind() {
@@ -237,12 +295,20 @@ impl<'a> Block<'a> {
237} 295}
238 296
239// BlockExpr 297// BlockExpr
240#[derive(Debug, Clone, Copy)] 298#[derive(Debug, Clone, Copy,)]
241pub struct BlockExprNode<R: TreeRoot<RaTypes> = OwnedRoot> { 299pub struct BlockExprNode<R: TreeRoot<RaTypes> = OwnedRoot> {
242 syntax: SyntaxNode<R>, 300 pub(crate) syntax: SyntaxNode<R>,
243} 301}
244pub type BlockExpr<'a> = BlockExprNode<RefRoot<'a>>; 302pub type BlockExpr<'a> = BlockExprNode<RefRoot<'a>>;
245 303
304impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<BlockExprNode<R1>> for BlockExprNode<R2> {
305 fn eq(&self, other: &BlockExprNode<R1>) -> bool { self.syntax == other.syntax }
306}
307impl<R: TreeRoot<RaTypes>> Eq for BlockExprNode<R> {}
308impl<R: TreeRoot<RaTypes>> Hash for BlockExprNode<R> {
309 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
310}
311
246impl<'a> AstNode<'a> for BlockExpr<'a> { 312impl<'a> AstNode<'a> for BlockExpr<'a> {
247 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 313 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
248 match syntax.kind() { 314 match syntax.kind() {
@@ -270,12 +336,20 @@ impl<'a> BlockExpr<'a> {
270} 336}
271 337
272// BreakExpr 338// BreakExpr
273#[derive(Debug, Clone, Copy)] 339#[derive(Debug, Clone, Copy,)]
274pub struct BreakExprNode<R: TreeRoot<RaTypes> = OwnedRoot> { 340pub struct BreakExprNode<R: TreeRoot<RaTypes> = OwnedRoot> {
275 syntax: SyntaxNode<R>, 341 pub(crate) syntax: SyntaxNode<R>,
276} 342}
277pub type BreakExpr<'a> = BreakExprNode<RefRoot<'a>>; 343pub type BreakExpr<'a> = BreakExprNode<RefRoot<'a>>;
278 344
345impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<BreakExprNode<R1>> for BreakExprNode<R2> {
346 fn eq(&self, other: &BreakExprNode<R1>) -> bool { self.syntax == other.syntax }
347}
348impl<R: TreeRoot<RaTypes>> Eq for BreakExprNode<R> {}
349impl<R: TreeRoot<RaTypes>> Hash for BreakExprNode<R> {
350 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
351}
352
279impl<'a> AstNode<'a> for BreakExpr<'a> { 353impl<'a> AstNode<'a> for BreakExpr<'a> {
280 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 354 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
281 match syntax.kind() { 355 match syntax.kind() {
@@ -298,13 +372,95 @@ impl<R: TreeRoot<RaTypes>> BreakExprNode<R> {
298 372
299impl<'a> BreakExpr<'a> {} 373impl<'a> BreakExpr<'a> {}
300 374
375// Byte
376#[derive(Debug, Clone, Copy,)]
377pub struct ByteNode<R: TreeRoot<RaTypes> = OwnedRoot> {
378 pub(crate) syntax: SyntaxNode<R>,
379}
380pub type Byte<'a> = ByteNode<RefRoot<'a>>;
381
382impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ByteNode<R1>> for ByteNode<R2> {
383 fn eq(&self, other: &ByteNode<R1>) -> bool { self.syntax == other.syntax }
384}
385impl<R: TreeRoot<RaTypes>> Eq for ByteNode<R> {}
386impl<R: TreeRoot<RaTypes>> Hash for ByteNode<R> {
387 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
388}
389
390impl<'a> AstNode<'a> for Byte<'a> {
391 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
392 match syntax.kind() {
393 BYTE => Some(Byte { syntax }),
394 _ => None,
395 }
396 }
397 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
398}
399
400impl<R: TreeRoot<RaTypes>> ByteNode<R> {
401 pub fn borrowed(&self) -> Byte {
402 ByteNode { syntax: self.syntax.borrowed() }
403 }
404 pub fn owned(&self) -> ByteNode {
405 ByteNode { syntax: self.syntax.owned() }
406 }
407}
408
409
410impl<'a> Byte<'a> {}
411
412// ByteString
413#[derive(Debug, Clone, Copy,)]
414pub struct ByteStringNode<R: TreeRoot<RaTypes> = OwnedRoot> {
415 pub(crate) syntax: SyntaxNode<R>,
416}
417pub type ByteString<'a> = ByteStringNode<RefRoot<'a>>;
418
419impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ByteStringNode<R1>> for ByteStringNode<R2> {
420 fn eq(&self, other: &ByteStringNode<R1>) -> bool { self.syntax == other.syntax }
421}
422impl<R: TreeRoot<RaTypes>> Eq for ByteStringNode<R> {}
423impl<R: TreeRoot<RaTypes>> Hash for ByteStringNode<R> {
424 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
425}
426
427impl<'a> AstNode<'a> for ByteString<'a> {
428 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
429 match syntax.kind() {
430 BYTE_STRING => Some(ByteString { syntax }),
431 _ => None,
432 }
433 }
434 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
435}
436
437impl<R: TreeRoot<RaTypes>> ByteStringNode<R> {
438 pub fn borrowed(&self) -> ByteString {
439 ByteStringNode { syntax: self.syntax.borrowed() }
440 }
441 pub fn owned(&self) -> ByteStringNode {
442 ByteStringNode { syntax: self.syntax.owned() }
443 }
444}
445
446
447impl<'a> ByteString<'a> {}
448
301// CallExpr 449// CallExpr
302#[derive(Debug, Clone, Copy)] 450#[derive(Debug, Clone, Copy,)]
303pub struct CallExprNode<R: TreeRoot<RaTypes> = OwnedRoot> { 451pub struct CallExprNode<R: TreeRoot<RaTypes> = OwnedRoot> {
304 syntax: SyntaxNode<R>, 452 pub(crate) syntax: SyntaxNode<R>,
305} 453}
306pub type CallExpr<'a> = CallExprNode<RefRoot<'a>>; 454pub type CallExpr<'a> = CallExprNode<RefRoot<'a>>;
307 455
456impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<CallExprNode<R1>> for CallExprNode<R2> {
457 fn eq(&self, other: &CallExprNode<R1>) -> bool { self.syntax == other.syntax }
458}
459impl<R: TreeRoot<RaTypes>> Eq for CallExprNode<R> {}
460impl<R: TreeRoot<RaTypes>> Hash for CallExprNode<R> {
461 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
462}
463
308impl<'a> AstNode<'a> for CallExpr<'a> { 464impl<'a> AstNode<'a> for CallExpr<'a> {
309 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 465 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
310 match syntax.kind() { 466 match syntax.kind() {
@@ -333,12 +489,20 @@ impl<'a> CallExpr<'a> {
333} 489}
334 490
335// CastExpr 491// CastExpr
336#[derive(Debug, Clone, Copy)] 492#[derive(Debug, Clone, Copy,)]
337pub struct CastExprNode<R: TreeRoot<RaTypes> = OwnedRoot> { 493pub struct CastExprNode<R: TreeRoot<RaTypes> = OwnedRoot> {
338 syntax: SyntaxNode<R>, 494 pub(crate) syntax: SyntaxNode<R>,
339} 495}
340pub type CastExpr<'a> = CastExprNode<RefRoot<'a>>; 496pub type CastExpr<'a> = CastExprNode<RefRoot<'a>>;
341 497
498impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<CastExprNode<R1>> for CastExprNode<R2> {
499 fn eq(&self, other: &CastExprNode<R1>) -> bool { self.syntax == other.syntax }
500}
501impl<R: TreeRoot<RaTypes>> Eq for CastExprNode<R> {}
502impl<R: TreeRoot<RaTypes>> Hash for CastExprNode<R> {
503 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
504}
505
342impl<'a> AstNode<'a> for CastExpr<'a> { 506impl<'a> AstNode<'a> for CastExpr<'a> {
343 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 507 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
344 match syntax.kind() { 508 match syntax.kind() {
@@ -362,12 +526,20 @@ impl<R: TreeRoot<RaTypes>> CastExprNode<R> {
362impl<'a> CastExpr<'a> {} 526impl<'a> CastExpr<'a> {}
363 527
364// Char 528// Char
365#[derive(Debug, Clone, Copy)] 529#[derive(Debug, Clone, Copy,)]
366pub struct CharNode<R: TreeRoot<RaTypes> = OwnedRoot> { 530pub struct CharNode<R: TreeRoot<RaTypes> = OwnedRoot> {
367 syntax: SyntaxNode<R>, 531 pub(crate) syntax: SyntaxNode<R>,
368} 532}
369pub type Char<'a> = CharNode<RefRoot<'a>>; 533pub type Char<'a> = CharNode<RefRoot<'a>>;
370 534
535impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<CharNode<R1>> for CharNode<R2> {
536 fn eq(&self, other: &CharNode<R1>) -> bool { self.syntax == other.syntax }
537}
538impl<R: TreeRoot<RaTypes>> Eq for CharNode<R> {}
539impl<R: TreeRoot<RaTypes>> Hash for CharNode<R> {
540 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
541}
542
371impl<'a> AstNode<'a> for Char<'a> { 543impl<'a> AstNode<'a> for Char<'a> {
372 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 544 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
373 match syntax.kind() { 545 match syntax.kind() {
@@ -391,12 +563,20 @@ impl<R: TreeRoot<RaTypes>> CharNode<R> {
391impl<'a> Char<'a> {} 563impl<'a> Char<'a> {}
392 564
393// Comment 565// Comment
394#[derive(Debug, Clone, Copy)] 566#[derive(Debug, Clone, Copy,)]
395pub struct CommentNode<R: TreeRoot<RaTypes> = OwnedRoot> { 567pub struct CommentNode<R: TreeRoot<RaTypes> = OwnedRoot> {
396 syntax: SyntaxNode<R>, 568 pub(crate) syntax: SyntaxNode<R>,
397} 569}
398pub type Comment<'a> = CommentNode<RefRoot<'a>>; 570pub type Comment<'a> = CommentNode<RefRoot<'a>>;
399 571
572impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<CommentNode<R1>> for CommentNode<R2> {
573 fn eq(&self, other: &CommentNode<R1>) -> bool { self.syntax == other.syntax }
574}
575impl<R: TreeRoot<RaTypes>> Eq for CommentNode<R> {}
576impl<R: TreeRoot<RaTypes>> Hash for CommentNode<R> {
577 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
578}
579
400impl<'a> AstNode<'a> for Comment<'a> { 580impl<'a> AstNode<'a> for Comment<'a> {
401 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 581 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
402 match syntax.kind() { 582 match syntax.kind() {
@@ -420,12 +600,20 @@ impl<R: TreeRoot<RaTypes>> CommentNode<R> {
420impl<'a> Comment<'a> {} 600impl<'a> Comment<'a> {}
421 601
422// Condition 602// Condition
423#[derive(Debug, Clone, Copy)] 603#[derive(Debug, Clone, Copy,)]
424pub struct ConditionNode<R: TreeRoot<RaTypes> = OwnedRoot> { 604pub struct ConditionNode<R: TreeRoot<RaTypes> = OwnedRoot> {
425 syntax: SyntaxNode<R>, 605 pub(crate) syntax: SyntaxNode<R>,
426} 606}
427pub type Condition<'a> = ConditionNode<RefRoot<'a>>; 607pub type Condition<'a> = ConditionNode<RefRoot<'a>>;
428 608
609impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ConditionNode<R1>> for ConditionNode<R2> {
610 fn eq(&self, other: &ConditionNode<R1>) -> bool { self.syntax == other.syntax }
611}
612impl<R: TreeRoot<RaTypes>> Eq for ConditionNode<R> {}
613impl<R: TreeRoot<RaTypes>> Hash for ConditionNode<R> {
614 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
615}
616
429impl<'a> AstNode<'a> for Condition<'a> { 617impl<'a> AstNode<'a> for Condition<'a> {
430 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 618 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
431 match syntax.kind() { 619 match syntax.kind() {
@@ -457,12 +645,20 @@ impl<'a> Condition<'a> {
457} 645}
458 646
459// ConstDef 647// ConstDef
460#[derive(Debug, Clone, Copy)] 648#[derive(Debug, Clone, Copy,)]
461pub struct ConstDefNode<R: TreeRoot<RaTypes> = OwnedRoot> { 649pub struct ConstDefNode<R: TreeRoot<RaTypes> = OwnedRoot> {
462 syntax: SyntaxNode<R>, 650 pub(crate) syntax: SyntaxNode<R>,
463} 651}
464pub type ConstDef<'a> = ConstDefNode<RefRoot<'a>>; 652pub type ConstDef<'a> = ConstDefNode<RefRoot<'a>>;
465 653
654impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ConstDefNode<R1>> for ConstDefNode<R2> {
655 fn eq(&self, other: &ConstDefNode<R1>) -> bool { self.syntax == other.syntax }
656}
657impl<R: TreeRoot<RaTypes>> Eq for ConstDefNode<R> {}
658impl<R: TreeRoot<RaTypes>> Hash for ConstDefNode<R> {
659 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
660}
661
466impl<'a> AstNode<'a> for ConstDef<'a> { 662impl<'a> AstNode<'a> for ConstDef<'a> {
467 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 663 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
468 match syntax.kind() { 664 match syntax.kind() {
@@ -486,15 +682,24 @@ impl<R: TreeRoot<RaTypes>> ConstDefNode<R> {
486impl<'a> ast::NameOwner<'a> for ConstDef<'a> {} 682impl<'a> ast::NameOwner<'a> for ConstDef<'a> {}
487impl<'a> ast::TypeParamsOwner<'a> for ConstDef<'a> {} 683impl<'a> ast::TypeParamsOwner<'a> for ConstDef<'a> {}
488impl<'a> ast::AttrsOwner<'a> for ConstDef<'a> {} 684impl<'a> ast::AttrsOwner<'a> for ConstDef<'a> {}
685impl<'a> ast::DocCommentsOwner<'a> for ConstDef<'a> {}
489impl<'a> ConstDef<'a> {} 686impl<'a> ConstDef<'a> {}
490 687
491// ContinueExpr 688// ContinueExpr
492#[derive(Debug, Clone, Copy)] 689#[derive(Debug, Clone, Copy,)]
493pub struct ContinueExprNode<R: TreeRoot<RaTypes> = OwnedRoot> { 690pub struct ContinueExprNode<R: TreeRoot<RaTypes> = OwnedRoot> {
494 syntax: SyntaxNode<R>, 691 pub(crate) syntax: SyntaxNode<R>,
495} 692}
496pub type ContinueExpr<'a> = ContinueExprNode<RefRoot<'a>>; 693pub type ContinueExpr<'a> = ContinueExprNode<RefRoot<'a>>;
497 694
695impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ContinueExprNode<R1>> for ContinueExprNode<R2> {
696 fn eq(&self, other: &ContinueExprNode<R1>) -> bool { self.syntax == other.syntax }
697}
698impl<R: TreeRoot<RaTypes>> Eq for ContinueExprNode<R> {}
699impl<R: TreeRoot<RaTypes>> Hash for ContinueExprNode<R> {
700 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
701}
702
498impl<'a> AstNode<'a> for ContinueExpr<'a> { 703impl<'a> AstNode<'a> for ContinueExpr<'a> {
499 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 704 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
500 match syntax.kind() { 705 match syntax.kind() {
@@ -518,12 +723,20 @@ impl<R: TreeRoot<RaTypes>> ContinueExprNode<R> {
518impl<'a> ContinueExpr<'a> {} 723impl<'a> ContinueExpr<'a> {}
519 724
520// DynTraitType 725// DynTraitType
521#[derive(Debug, Clone, Copy)] 726#[derive(Debug, Clone, Copy,)]
522pub struct DynTraitTypeNode<R: TreeRoot<RaTypes> = OwnedRoot> { 727pub struct DynTraitTypeNode<R: TreeRoot<RaTypes> = OwnedRoot> {
523 syntax: SyntaxNode<R>, 728 pub(crate) syntax: SyntaxNode<R>,
524} 729}
525pub type DynTraitType<'a> = DynTraitTypeNode<RefRoot<'a>>; 730pub type DynTraitType<'a> = DynTraitTypeNode<RefRoot<'a>>;
526 731
732impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<DynTraitTypeNode<R1>> for DynTraitTypeNode<R2> {
733 fn eq(&self, other: &DynTraitTypeNode<R1>) -> bool { self.syntax == other.syntax }
734}
735impl<R: TreeRoot<RaTypes>> Eq for DynTraitTypeNode<R> {}
736impl<R: TreeRoot<RaTypes>> Hash for DynTraitTypeNode<R> {
737 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
738}
739
527impl<'a> AstNode<'a> for DynTraitType<'a> { 740impl<'a> AstNode<'a> for DynTraitType<'a> {
528 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 741 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
529 match syntax.kind() { 742 match syntax.kind() {
@@ -547,12 +760,20 @@ impl<R: TreeRoot<RaTypes>> DynTraitTypeNode<R> {
547impl<'a> DynTraitType<'a> {} 760impl<'a> DynTraitType<'a> {}
548 761
549// EnumDef 762// EnumDef
550#[derive(Debug, Clone, Copy)] 763#[derive(Debug, Clone, Copy,)]
551pub struct EnumDefNode<R: TreeRoot<RaTypes> = OwnedRoot> { 764pub struct EnumDefNode<R: TreeRoot<RaTypes> = OwnedRoot> {
552 syntax: SyntaxNode<R>, 765 pub(crate) syntax: SyntaxNode<R>,
553} 766}
554pub type EnumDef<'a> = EnumDefNode<RefRoot<'a>>; 767pub type EnumDef<'a> = EnumDefNode<RefRoot<'a>>;
555 768
769impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<EnumDefNode<R1>> for EnumDefNode<R2> {
770 fn eq(&self, other: &EnumDefNode<R1>) -> bool { self.syntax == other.syntax }
771}
772impl<R: TreeRoot<RaTypes>> Eq for EnumDefNode<R> {}
773impl<R: TreeRoot<RaTypes>> Hash for EnumDefNode<R> {
774 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
775}
776
556impl<'a> AstNode<'a> for EnumDef<'a> { 777impl<'a> AstNode<'a> for EnumDef<'a> {
557 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 778 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
558 match syntax.kind() { 779 match syntax.kind() {
@@ -576,10 +797,11 @@ impl<R: TreeRoot<RaTypes>> EnumDefNode<R> {
576impl<'a> ast::NameOwner<'a> for EnumDef<'a> {} 797impl<'a> ast::NameOwner<'a> for EnumDef<'a> {}
577impl<'a> ast::TypeParamsOwner<'a> for EnumDef<'a> {} 798impl<'a> ast::TypeParamsOwner<'a> for EnumDef<'a> {}
578impl<'a> ast::AttrsOwner<'a> for EnumDef<'a> {} 799impl<'a> ast::AttrsOwner<'a> for EnumDef<'a> {}
800impl<'a> ast::DocCommentsOwner<'a> for EnumDef<'a> {}
579impl<'a> EnumDef<'a> {} 801impl<'a> EnumDef<'a> {}
580 802
581// Expr 803// Expr
582#[derive(Debug, Clone, Copy)] 804#[derive(Debug, Clone, Copy, PartialEq, Eq)]
583pub enum Expr<'a> { 805pub enum Expr<'a> {
584 TupleExpr(TupleExpr<'a>), 806 TupleExpr(TupleExpr<'a>),
585 ArrayExpr(ArrayExpr<'a>), 807 ArrayExpr(ArrayExpr<'a>),
@@ -694,12 +916,20 @@ impl<'a> AstNode<'a> for Expr<'a> {
694impl<'a> Expr<'a> {} 916impl<'a> Expr<'a> {}
695 917
696// ExprStmt 918// ExprStmt
697#[derive(Debug, Clone, Copy)] 919#[derive(Debug, Clone, Copy,)]
698pub struct ExprStmtNode<R: TreeRoot<RaTypes> = OwnedRoot> { 920pub struct ExprStmtNode<R: TreeRoot<RaTypes> = OwnedRoot> {
699 syntax: SyntaxNode<R>, 921 pub(crate) syntax: SyntaxNode<R>,
700} 922}
701pub type ExprStmt<'a> = ExprStmtNode<RefRoot<'a>>; 923pub type ExprStmt<'a> = ExprStmtNode<RefRoot<'a>>;
702 924
925impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ExprStmtNode<R1>> for ExprStmtNode<R2> {
926 fn eq(&self, other: &ExprStmtNode<R1>) -> bool { self.syntax == other.syntax }
927}
928impl<R: TreeRoot<RaTypes>> Eq for ExprStmtNode<R> {}
929impl<R: TreeRoot<RaTypes>> Hash for ExprStmtNode<R> {
930 fn hash<H: Hasher>(&self, state: &mut H) { self.syntax.hash(state) }
931}
932
703impl<'a> AstNode<'a> for ExprStmt<'a> { 933impl<'a> AstNode<'a> for ExprStmt<'a> {
704 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> { 934 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
705 match syntax.kind() { 935 match syntax.kind() {
@@ -727,12 +957,20 @@ impl<'a> ExprStmt<'a> {
727} 957}
728 958
729// ExternCrateItem 959// ExternCrateItem
730#[derive(Debug, Clone, Copy)] 960#[derive(Debug, Clone, Copy,)]
731pub struct ExternCrateItemNode<R: TreeRoot<RaTypes> = OwnedRoot> { 961pub struct ExternCrateItemNode<R: TreeRoot<RaTypes> = OwnedRoot> {
732 syntax: SyntaxNode<R>, 962 pub(crate) syntax: SyntaxNode<R>,
733} 963}
734pub type ExternCrateItem<'a> = ExternCrateItemNode<RefRoot<'a>>; 964pub type ExternCrateItem<'a> = ExternCrateItemNode<RefRoot<'a>>;
735 965
966impl<R1: TreeRoot<RaTypes>, R2: TreeRoot<RaTypes>> PartialEq<ExternCrateItemNode<R1>> for ExternCrateItemNode<R2> {
967 fn eq(&self, other: &ExternCrateItemNode<R1>) -> bool { self.syntax == other.syntax }
968}
969impl<R: TreeRoot<RaTypes>> Eq for ExternCrateItemNode<R> {}