From 3d6129dccd36d754876672263ace3aa4ce56d655 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 16 Aug 2024 02:36:24 +0300 Subject: [PATCH] Properly account for editions in names This PR touches a lot of parts. But the main changes are changing `hir_expand::Name` to be raw edition-dependently and only when necessary (unrelated to how the user originally wrote the identifier), and changing `is_keyword()` and `is_raw_identifier()` to be edition-aware (this was done in #17896, but the FIXMEs were fixed here). It is possible that I missed some cases, but most IDE parts should properly escape (or not escape) identifiers now. The rules of thumb are: - If we show the identifier to the user, its rawness should be determined by the edition of the edited crate. This is nice for IDE features, but really important for changes we insert to the source code. - For tests, I chose `Edition::CURRENT` (so we only have to (maybe) update tests when an edition becomes stable, to avoid churn). - For debugging tools (helper methods and logs), I used `Edition::LATEST`. --- .../rust-analyzer/crates/hir-def/src/body.rs | 14 +- .../crates/hir-def/src/body/pretty.rs | 65 +++-- .../crates/hir-def/src/body/tests.rs | 6 +- .../crates/hir-def/src/find_path.rs | 7 +- .../crates/hir-def/src/hir/format_args.rs | 2 +- .../crates/hir-def/src/hir/type_ref.rs | 13 +- .../crates/hir-def/src/import_map.rs | 16 +- .../crates/hir-def/src/item_scope.rs | 3 +- .../crates/hir-def/src/item_tree.rs | 6 +- .../crates/hir-def/src/item_tree/pretty.rs | 86 +++--- .../crates/hir-def/src/item_tree/tests.rs | 3 +- .../crates/hir-def/src/nameres.rs | 6 +- .../crates/hir-def/src/nameres/collector.rs | 10 +- .../hir-def/src/nameres/tests/macros.rs | 5 +- .../src/nameres/tests/mod_resolution.rs | 8 +- .../rust-analyzer/crates/hir-def/src/path.rs | 19 +- .../crates/hir-def/src/pretty.rs | 84 +++--- .../crates/hir-expand/src/eager.rs | 3 +- .../crates/hir-expand/src/mod_path.rs | 46 +-- .../crates/hir-expand/src/name.rs | 93 +++---- .../crates/hir-ty/src/chalk_db.rs | 18 +- .../crates/hir-ty/src/consteval/tests.rs | 10 +- .../hir-ty/src/diagnostics/decl_check.rs | 70 +++-- .../crates/hir-ty/src/diagnostics/expr.rs | 30 +- .../hir-ty/src/diagnostics/match_check.rs | 35 ++- .../crates/hir-ty/src/display.rs | 116 +++++--- .../crates/hir-ty/src/infer/closure.rs | 4 +- .../crates/hir-ty/src/layout/tests.rs | 13 +- .../rust-analyzer/crates/hir-ty/src/lib.rs | 9 +- .../rust-analyzer/crates/hir-ty/src/mir.rs | 5 +- .../crates/hir-ty/src/mir/eval.rs | 17 +- .../crates/hir-ty/src/mir/eval/shim.rs | 6 +- .../crates/hir-ty/src/mir/eval/tests.rs | 6 +- .../crates/hir-ty/src/mir/lower.rs | 62 +++-- .../hir-ty/src/mir/lower/pattern_matching.rs | 3 +- .../crates/hir-ty/src/mir/pretty.rs | 48 ++-- .../rust-analyzer/crates/hir-ty/src/tls.rs | 19 +- .../rust-analyzer/crates/hir-ty/src/traits.rs | 3 +- .../rust-analyzer/crates/hir/src/attrs.rs | 8 +- .../rust-analyzer/crates/hir/src/display.rs | 69 ++--- src/tools/rust-analyzer/crates/hir/src/lib.rs | 84 ++++-- .../rust-analyzer/crates/hir/src/symbols.rs | 16 +- .../crates/hir/src/term_search/expr.rs | 55 ++-- .../src/handlers/add_missing_impl_members.rs | 23 +- .../src/handlers/add_missing_match_arms.rs | 3 +- .../ide-assists/src/handlers/auto_import.rs | 9 +- .../ide-assists/src/handlers/bool_to_enum.rs | 6 +- .../src/handlers/convert_bool_then.rs | 2 +- .../src/handlers/convert_into_to_from.rs | 5 +- .../handlers/convert_iter_for_each_to_for.rs | 12 +- .../convert_tuple_return_type_to_struct.rs | 2 +- .../handlers/destructure_struct_binding.rs | 8 +- .../src/handlers/expand_glob_import.rs | 4 +- .../src/handlers/extract_function.rs | 69 +++-- .../extract_struct_from_enum_variant.rs | 14 +- .../handlers/fill_record_pattern_fields.rs | 3 +- .../src/handlers/fix_visibility.rs | 14 +- .../src/handlers/generate_delegate_methods.rs | 3 +- .../src/handlers/generate_delegate_trait.rs | 23 +- .../src/handlers/generate_deref.rs | 12 +- .../generate_documentation_template.rs | 9 +- .../src/handlers/generate_function.rs | 24 +- .../src/handlers/generate_getter_or_setter.rs | 2 +- .../ide-assists/src/handlers/generate_new.rs | 5 +- .../src/handlers/inline_const_as_literal.rs | 11 +- .../src/handlers/move_const_to_impl.rs | 10 +- .../src/handlers/move_from_mod_rs.rs | 2 +- .../src/handlers/move_module_to_file.rs | 2 +- .../src/handlers/move_to_mod_rs.rs | 2 +- .../src/handlers/qualify_method_call.rs | 2 + .../ide-assists/src/handlers/qualify_path.rs | 22 +- .../src/handlers/reorder_fields.rs | 13 +- .../src/handlers/reorder_impl_items.rs | 5 +- .../replace_derive_with_manual_impl.rs | 5 +- .../replace_qualified_name_with_use.rs | 38 +-- .../ide-assists/src/handlers/term_search.rs | 6 +- .../src/handlers/toggle_async_sugar.rs | 3 +- .../crates/ide-assists/src/utils.rs | 20 +- .../ide-assists/src/utils/suggest_name.rs | 19 +- .../crates/ide-completion/src/completions.rs | 13 +- .../src/completions/attribute.rs | 29 +- .../src/completions/attribute/cfg.rs | 13 +- .../src/completions/attribute/derive.rs | 10 +- .../src/completions/attribute/lint.rs | 3 +- .../src/completions/attribute/macro_use.rs | 3 +- .../src/completions/attribute/repr.rs | 7 +- .../ide-completion/src/completions/dot.rs | 1 + .../src/completions/env_vars.rs | 2 +- .../src/completions/extern_abi.rs | 9 +- .../src/completions/extern_crate.rs | 3 +- .../src/completions/flyimport.rs | 2 +- .../src/completions/fn_param.rs | 8 +- .../src/completions/format_string.rs | 6 +- .../src/completions/item_list/trait_impl.rs | 14 +- .../src/completions/lifetime.rs | 2 +- .../ide-completion/src/completions/mod_.rs | 9 +- .../ide-completion/src/completions/postfix.rs | 13 +- .../ide-completion/src/completions/record.rs | 2 + .../ide-completion/src/completions/snippet.rs | 3 +- .../ide-completion/src/completions/use_.rs | 6 +- .../crates/ide-completion/src/context.rs | 9 +- .../ide-completion/src/context/analysis.rs | 2 +- .../crates/ide-completion/src/item.rs | 11 +- .../crates/ide-completion/src/lib.rs | 9 +- .../crates/ide-completion/src/render.rs | 70 +++-- .../ide-completion/src/render/const_.rs | 13 +- .../ide-completion/src/render/function.rs | 44 +-- .../ide-completion/src/render/literal.rs | 12 +- .../ide-completion/src/render/macro_.rs | 9 +- .../ide-completion/src/render/pattern.rs | 35 ++- .../ide-completion/src/render/type_alias.rs | 18 +- .../src/render/union_literal.rs | 34 ++- .../ide-completion/src/render/variant.rs | 20 +- .../crates/ide-completion/src/tests.rs | 34 ++- .../src/tests/raw_identifiers.rs | 84 ++++++ .../rust-analyzer/crates/ide-db/src/defs.rs | 81 +++--- .../crates/ide-db/src/famous_defs.rs | 9 +- .../crates/ide-db/src/helpers.rs | 12 +- .../ide-db/src/imports/import_assets.rs | 6 +- .../crates/ide-db/src/path_transform.rs | 18 +- .../rust-analyzer/crates/ide-db/src/rename.rs | 74 +++-- .../insert_whitespace_into_node.rs | 5 +- .../ide-db/src/syntax_helpers/node_ext.rs | 8 +- .../rust-analyzer/crates/ide-db/src/traits.rs | 21 +- .../crates/ide-db/src/ty_filter.rs | 7 +- .../ide-db/src/use_trivial_constructor.rs | 4 +- .../src/handlers/expected_function.rs | 2 +- .../src/handlers/json_is_not_rust.rs | 15 +- .../src/handlers/missing_fields.rs | 24 +- .../src/handlers/moved_out_of_ref.rs | 2 +- .../src/handlers/mutability_errors.rs | 2 +- .../src/handlers/private_assoc_item.rs | 2 +- .../src/handlers/private_field.rs | 4 +- .../handlers/trait_impl_missing_assoc_item.rs | 2 +- .../trait_impl_redundant_assoc_item.rs | 10 +- .../src/handlers/type_mismatch.rs | 12 +- .../src/handlers/typed_hole.rs | 5 +- .../src/handlers/undeclared_label.rs | 2 +- .../src/handlers/unlinked_file.rs | 11 +- .../src/handlers/unreachable_label.rs | 2 +- .../src/handlers/unresolved_field.rs | 4 +- .../src/handlers/unresolved_macro_call.rs | 2 +- .../src/handlers/unresolved_method.rs | 9 +- .../src/handlers/unused_variables.rs | 18 +- .../crates/ide-diagnostics/src/lib.rs | 49 +++- .../crates/ide-ssr/src/matching.rs | 10 +- .../crates/ide-ssr/src/replacing.rs | 8 +- .../rust-analyzer/crates/ide/src/doc_links.rs | 63 +++-- .../crates/ide/src/expand_macro.rs | 10 +- .../crates/ide/src/goto_definition.rs | 4 +- .../crates/ide/src/highlight_related.rs | 4 +- .../rust-analyzer/crates/ide/src/hover.rs | 63 +++-- .../crates/ide/src/hover/render.rs | 153 +++++----- .../crates/ide/src/hover/tests.rs | 72 +++++ .../crates/ide/src/inlay_hints.rs | 14 +- .../crates/ide/src/inlay_hints/adjustment.rs | 6 +- .../crates/ide/src/inlay_hints/bind_pat.rs | 4 +- .../crates/ide/src/inlay_hints/chaining.rs | 4 +- .../ide/src/inlay_hints/closing_brace.rs | 8 +- .../crates/ide/src/inlay_hints/closure_ret.rs | 4 +- .../ide/src/inlay_hints/implicit_drop.rs | 4 +- .../crates/ide/src/inlay_hints/param_name.rs | 4 +- .../rust-analyzer/crates/ide/src/moniker.rs | 45 +-- .../crates/ide/src/navigation_target.rs | 100 ++++--- .../crates/ide/src/references.rs | 5 +- .../rust-analyzer/crates/ide/src/rename.rs | 261 ++++++++++++++++-- .../rust-analyzer/crates/ide/src/runnables.rs | 44 +-- .../crates/ide/src/signature_help.rs | 103 ++++--- .../crates/ide/src/static_index.rs | 16 +- .../crates/ide/src/syntax_highlighting.rs | 4 +- .../ide/src/syntax_highlighting/highlight.rs | 8 +- .../ide/src/syntax_highlighting/macro_.rs | 3 +- .../crates/ide/src/view_item_tree.rs | 2 +- .../crates/ide/src/view_memory_layout.rs | 16 +- .../crates/parser/src/syntax_kind.rs | 9 + .../crates/rust-analyzer/src/cli.rs | 4 +- .../rust-analyzer/src/cli/analysis_stats.rs | 77 ++++-- .../crates/syntax-bridge/src/lib.rs | 5 +- .../rust-analyzer/crates/syntax/src/utils.rs | 1 + 179 files changed, 2485 insertions(+), 1250 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index a988317e046e..f5fe8f877013 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -14,7 +14,7 @@ use hir_expand::{name::Name, ExpandError, InFile}; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use span::MacroFileId; +use span::{Edition, MacroFileId}; use syntax::{ast, AstPtr, SyntaxNodePtr}; use triomphe::Arc; @@ -201,8 +201,13 @@ impl Body { self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block))) } - pub fn pretty_print(&self, db: &dyn DefDatabase, owner: DefWithBodyId) -> String { - pretty::print_body_hir(db, self, owner) + pub fn pretty_print( + &self, + db: &dyn DefDatabase, + owner: DefWithBodyId, + edition: Edition, + ) -> String { + pretty::print_body_hir(db, self, owner, edition) } pub fn pretty_print_expr( @@ -210,8 +215,9 @@ impl Body { db: &dyn DefDatabase, owner: DefWithBodyId, expr: ExprId, + edition: Edition, ) -> String { - pretty::print_expr_hir(db, self, owner, expr) + pretty::print_expr_hir(db, self, owner, expr, edition) } fn new( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index edaee60937d1..55740a68acd6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -3,6 +3,7 @@ use std::fmt::{self, Write}; use itertools::Itertools; +use span::Edition; use crate::{ hir::{ @@ -15,20 +16,26 @@ use crate::{ use super::*; -pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String { +pub(super) fn print_body_hir( + db: &dyn DefDatabase, + body: &Body, + owner: DefWithBodyId, + edition: Edition, +) -> String { let header = match owner { - DefWithBodyId::FunctionId(it) => { - it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db.upcast()))) - } + DefWithBodyId::FunctionId(it) => it + .lookup(db) + .id + .resolved(db, |it| format!("fn {}", it.name.display(db.upcast(), edition))), DefWithBodyId::StaticId(it) => it .lookup(db) .id - .resolved(db, |it| format!("static {} = ", it.name.display(db.upcast()))), + .resolved(db, |it| format!("static {} = ", it.name.display(db.upcast(), edition))), DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| { format!( "const {} = ", match &it.name { - Some(name) => name.display(db.upcast()).to_string(), + Some(name) => name.display(db.upcast(), edition).to_string(), None => "_".to_owned(), } ) @@ -39,13 +46,13 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo let enum_loc = loc.parent.lookup(db); format!( "enum {}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), - loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition), + loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition), ) } }; - let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false }; + let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false, edition }; if let DefWithBodyId::FunctionId(it) = owner { p.buf.push('('); let function_data = &db.function_data(it); @@ -86,8 +93,10 @@ pub(super) fn print_expr_hir( body: &Body, _owner: DefWithBodyId, expr: ExprId, + edition: Edition, ) -> String { - let mut p = Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false }; + let mut p = + Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false, edition }; p.print_expr(expr); p.buf } @@ -113,6 +122,7 @@ struct Printer<'a> { buf: String, indent_level: usize, needs_indent: bool, + edition: Edition, } impl Write for Printer<'_> { @@ -173,13 +183,14 @@ impl Printer<'_> { Expr::OffsetOf(offset_of) => { w!(self, "builtin#offset_of("); self.print_type_ref(&offset_of.container); + let edition = self.edition; w!( self, ", {})", offset_of .fields .iter() - .format_with(".", |field, f| f(&field.display(self.db.upcast()))) + .format_with(".", |field, f| f(&field.display(self.db.upcast(), edition))) ); } Expr::Path(path) => self.print_path(path), @@ -201,7 +212,7 @@ impl Printer<'_> { } Expr::Loop { body, label } => { if let Some(lbl) = label { - w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast())); + w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast(), self.edition)); } w!(self, "loop "); self.print_expr(*body); @@ -221,10 +232,11 @@ impl Printer<'_> { } Expr::MethodCall { receiver, method_name, args, generic_args } => { self.print_expr(*receiver); - w!(self, ".{}", method_name.display(self.db.upcast())); + w!(self, ".{}", method_name.display(self.db.upcast(), self.edition)); if let Some(args) = generic_args { w!(self, "::<"); - print_generic_args(self.db, args, self).unwrap(); + let edition = self.edition; + print_generic_args(self.db, args, self, edition).unwrap(); w!(self, ">"); } w!(self, "("); @@ -259,13 +271,13 @@ impl Printer<'_> { Expr::Continue { label } => { w!(self, "continue"); if let Some(lbl) = label { - w!(self, " {}", self.body[*lbl].name.display(self.db.upcast())); + w!(self, " {}", self.body[*lbl].name.display(self.db.upcast(), self.edition)); } } Expr::Break { expr, label } => { w!(self, "break"); if let Some(lbl) = label { - w!(self, " {}", self.body[*lbl].name.display(self.db.upcast())); + w!(self, " {}", self.body[*lbl].name.display(self.db.upcast(), self.edition)); } if let Some(expr) = expr { self.whitespace(); @@ -307,9 +319,10 @@ impl Printer<'_> { } w!(self, "{{"); + let edition = self.edition; self.indented(|p| { for field in &**fields { - w!(p, "{}: ", field.name.display(self.db.upcast())); + w!(p, "{}: ", field.name.display(self.db.upcast(), edition)); p.print_expr(field.expr); wln!(p, ","); } @@ -326,7 +339,7 @@ impl Printer<'_> { } Expr::Field { expr, name } => { self.print_expr(*expr); - w!(self, ".{}", name.display(self.db.upcast())); + w!(self, ".{}", name.display(self.db.upcast(), self.edition)); } Expr::Await { expr } => { self.print_expr(*expr); @@ -464,8 +477,9 @@ impl Printer<'_> { } Expr::Literal(lit) => self.print_literal(lit), Expr::Block { id: _, statements, tail, label } => { - let label = - label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db.upcast()))); + let label = label.map(|lbl| { + format!("{}: ", self.body[lbl].name.display(self.db.upcast(), self.edition)) + }); self.print_block(label.as_deref(), statements, tail); } Expr::Unsafe { id: _, statements, tail } => { @@ -539,9 +553,10 @@ impl Printer<'_> { } w!(self, " {{"); + let edition = self.edition; self.indented(|p| { for arg in args.iter() { - w!(p, "{}: ", arg.name.display(self.db.upcast())); + w!(p, "{}: ", arg.name.display(self.db.upcast(), edition)); p.print_pat(arg.pat); wln!(p, ","); } @@ -686,11 +701,13 @@ impl Printer<'_> { } fn print_type_ref(&mut self, ty: &TypeRef) { - print_type_ref(self.db, ty, self).unwrap(); + let edition = self.edition; + print_type_ref(self.db, ty, self, edition).unwrap(); } fn print_path(&mut self, path: &Path) { - print_path(self.db, path, self).unwrap(); + let edition = self.edition; + print_path(self.db, path, self, edition).unwrap(); } fn print_binding(&mut self, id: BindingId) { @@ -701,6 +718,6 @@ impl Printer<'_> { BindingAnnotation::Ref => "ref ", BindingAnnotation::RefMut => "ref mut ", }; - w!(self, "{}{}", mode, name.display(self.db.upcast())); + w!(self, "{}{}", mode, name.display(self.db.upcast(), self.edition)); } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index 0011d3a20c2a..38fc01d8fca5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -219,7 +219,7 @@ fn main() { }, ); }"#]] - .assert_eq(&body.pretty_print(&db, def)) + .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } #[test] @@ -285,7 +285,7 @@ impl SsrError { ), ); }"#]] - .assert_eq(&body.pretty_print(&db, def)) + .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } #[test] @@ -333,5 +333,5 @@ fn f(a: i32, b: u32) -> String { ); }; }"#]] - .assert_eq(&body.pretty_print(&db, def)) + .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index 5a3a3e918979..f5e03e5281e2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -651,6 +651,7 @@ mod tests { use expect_test::{expect, Expect}; use hir_expand::db::ExpandDatabase; use itertools::Itertools; + use span::Edition; use stdx::format_to; use syntax::ast::AstNode; use test_fixture::WithFixture; @@ -717,8 +718,10 @@ mod tests { "{:7}(imports {}): {}\n", format!("{:?}", prefix), if ignore_local_imports { '✖' } else { '✔' }, - found_path - .map_or_else(|| "".to_owned(), |it| it.display(&db).to_string()), + found_path.map_or_else( + || "".to_owned(), + |it| it.display(&db, Edition::CURRENT).to_string() + ), ); } expect.assert_eq(&res); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index 390e7da677f6..e1c3bd25bcf0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -250,7 +250,7 @@ pub(crate) fn parse( } } ArgRef::Name(name, span) => { - let name = Name::new(name, tt::IdentIsRaw::No, call_ctx); + let name = Name::new(name, call_ctx); if let Some((index, _)) = args.by_name(&name) { record_usage(name, span); // Name found in `args`, so we resolve it to its index. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index 8f618b2d3034..b74cd90f6933 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -10,6 +10,7 @@ use hir_expand::{ AstId, }; use intern::{sym, Interned, Symbol}; +use span::Edition; use syntax::ast::{self, HasGenericArgs, HasName, IsString}; use crate::{ @@ -419,18 +420,22 @@ impl ConstRef { param.default_val().map(|default| Self::from_const_arg(lower_ctx, Some(default))) } - pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a { - struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef); + pub fn display<'a>( + &'a self, + db: &'a dyn ExpandDatabase, + edition: Edition, + ) -> impl fmt::Display + 'a { + struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef, Edition); impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.1 { ConstRef::Scalar(s) => s.fmt(f), - ConstRef::Path(n) => n.display(self.0).fmt(f), + ConstRef::Path(n) => n.display(self.0, self.2).fmt(f), ConstRef::Complex(_) => f.write_str("{const}"), } } } - Display(db, self) + Display(db, self, edition) } // We special case literals and single identifiers, to speed up things. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index 8cc022e4c60f..9574e5d9cd37 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -8,6 +8,7 @@ use hir_expand::name::Name; use itertools::Itertools; use rustc_hash::FxHashSet; use smallvec::SmallVec; +use span::Edition; use stdx::{format_to, TupleExt}; use syntax::ToSmolStr; use triomphe::Arc; @@ -66,7 +67,12 @@ impl ImportMap { for (k, v) in self.item_to_info_map.iter() { format_to!(out, "{:?} ({:?}) -> ", k, v.1); for v in &v.0 { - format_to!(out, "{}:{:?}, ", v.name.display(db.upcast()), v.container); + format_to!( + out, + "{}:{:?}, ", + v.name.display(db.upcast(), Edition::CURRENT), + v.container + ); } format_to!(out, "\n"); } @@ -83,7 +89,7 @@ impl ImportMap { // We've only collected items, whose name cannot be tuple field so unwrapping is fine. .flat_map(|(&item, (info, _))| { info.iter().enumerate().map(move |(idx, info)| { - (item, info.name.display(db.upcast()).to_smolstr(), idx as u32) + (item, info.name.unescaped().display(db.upcast()).to_smolstr(), idx as u32) }) }) .collect(); @@ -461,7 +467,7 @@ fn search_maps( query.search_mode.check( &query.query, query.case_sensitive, - &info.name.display(db.upcast()).to_smolstr(), + &info.name.unescaped().display(db.upcast()).to_smolstr(), ) }); res.extend(iter.map(TupleExt::head)); @@ -577,7 +583,7 @@ mod tests { Some(format!( "{}::{}", render_path(db, &trait_info[0]), - assoc_item_name.display(db.upcast()) + assoc_item_name.display(db.upcast(), Edition::CURRENT) )) } @@ -616,7 +622,7 @@ mod tests { module = parent; } - segments.iter().rev().map(|it| it.display(db.upcast())).join("::") + segments.iter().rev().map(|it| it.display(db.upcast(), Edition::CURRENT)).join("::") } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index df6b1f55c1d9..89b011094a46 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -9,6 +9,7 @@ use la_arena::Idx; use once_cell::sync::Lazy; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; +use span::Edition; use stdx::format_to; use syntax::ast; @@ -706,7 +707,7 @@ impl ItemScope { format_to!( buf, "{}:", - name.map_or("_".to_owned(), |name| name.display(db).to_string()) + name.map_or("_".to_owned(), |name| name.display(db, Edition::LATEST).to_string()) ); if let Some((.., i)) = def.types { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 28eebb286ed4..517f40ebd1c5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -51,7 +51,7 @@ use la_arena::{Arena, Idx, RawIdx}; use once_cell::sync::OnceCell; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use span::{AstIdNode, FileAstId, SyntaxContextId}; +use span::{AstIdNode, Edition, FileAstId, SyntaxContextId}; use stdx::never; use syntax::{ast, match_ast, SyntaxKind}; use triomphe::Arc; @@ -199,8 +199,8 @@ impl ItemTree { Attrs::filter(db, krate, self.raw_attrs(of).clone()) } - pub fn pretty_print(&self, db: &dyn DefDatabase) -> String { - pretty::print_item_tree(db, self) + pub fn pretty_print(&self, db: &dyn DefDatabase, edition: Edition) -> String { + pretty::print_item_tree(db, self, edition) } fn data(&self) -> &ItemTreeData { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index 740759e6e394..b5a65abce869 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Write}; use la_arena::{Idx, RawIdx}; -use span::ErasedFileAstId; +use span::{Edition, ErasedFileAstId}; use crate::{ generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, @@ -18,8 +18,9 @@ use crate::{ visibility::RawVisibility, }; -pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String { - let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true }; +pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Edition) -> String { + let mut p = + Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition }; if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) { p.print_attrs(attrs, true, "\n"); @@ -56,6 +57,7 @@ struct Printer<'a> { buf: String, indent_level: usize, needs_indent: bool, + edition: Edition, } impl Printer<'_> { @@ -97,7 +99,7 @@ impl Printer<'_> { self, "#{}[{}{}]{}", inner, - attr.path.display(self.db.upcast()), + attr.path.display(self.db.upcast(), self.edition), attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(), separated_by, ); @@ -113,13 +115,14 @@ impl Printer<'_> { fn print_visibility(&mut self, vis: RawVisibilityId) { match &self.tree[vis] { RawVisibility::Module(path, _expl) => { - w!(self, "pub({}) ", path.display(self.db.upcast())) + w!(self, "pub({}) ", path.display(self.db.upcast(), self.edition)) } RawVisibility::Public => w!(self, "pub "), }; } fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) { + let edition = self.edition; match kind { FieldsShape::Record => { self.whitespace(); @@ -131,7 +134,7 @@ impl Printer<'_> { "\n", ); this.print_visibility(*visibility); - w!(this, "{}: ", name.display(self.db.upcast())); + w!(this, "{}: ", name.display(self.db.upcast(), edition)); this.print_type_ref(type_ref); wln!(this, ","); } @@ -147,7 +150,7 @@ impl Printer<'_> { "\n", ); this.print_visibility(*visibility); - w!(this, "{}: ", name.display(self.db.upcast())); + w!(this, "{}: ", name.display(self.db.upcast(), edition)); this.print_type_ref(type_ref); wln!(this, ","); } @@ -186,20 +189,20 @@ impl Printer<'_> { fn print_use_tree(&mut self, use_tree: &UseTree) { match &use_tree.kind { UseTreeKind::Single { path, alias } => { - w!(self, "{}", path.display(self.db.upcast())); + w!(self, "{}", path.display(self.db.upcast(), self.edition)); if let Some(alias) = alias { - w!(self, " as {}", alias); + w!(self, " as {}", alias.display(self.edition)); } } UseTreeKind::Glob { path } => { if let Some(path) = path { - w!(self, "{}::", path.display(self.db.upcast())); + w!(self, "{}::", path.display(self.db.upcast(), self.edition)); } w!(self, "*"); } UseTreeKind::Prefixed { prefix, list } => { if let Some(prefix) = prefix { - w!(self, "{}::", prefix.display(self.db.upcast())); + w!(self, "{}::", prefix.display(self.db.upcast(), self.edition)); } w!(self, "{{"); for (i, tree) in list.iter().enumerate() { @@ -229,9 +232,9 @@ impl Printer<'_> { let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "extern crate {}", name.display(self.db.upcast())); + w!(self, "extern crate {}", name.display(self.db.upcast(), self.edition)); if let Some(alias) = alias { - w!(self, " as {}", alias); + w!(self, " as {}", alias.display(self.edition)); } wln!(self, ";"); } @@ -278,7 +281,7 @@ impl Printer<'_> { if let Some(abi) = abi { w!(self, "extern \"{}\" ", abi); } - w!(self, "fn {}", name.display(self.db.upcast())); + w!(self, "fn {}", name.display(self.db.upcast(), self.edition)); self.print_generic_params(explicit_generic_params, it.into()); w!(self, "("); if !params.is_empty() { @@ -314,7 +317,7 @@ impl Printer<'_> { &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "struct {}", name.display(self.db.upcast())); + w!(self, "struct {}", name.display(self.db.upcast(), self.edition)); self.print_generic_params(generic_params, it.into()); self.print_fields_and_where_clause( FieldParent::Struct(it), @@ -332,7 +335,7 @@ impl Printer<'_> { let Union { name, visibility, fields, generic_params, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "union {}", name.display(self.db.upcast())); + w!(self, "union {}", name.display(self.db.upcast(), self.edition)); self.print_generic_params(generic_params, it.into()); self.print_fields_and_where_clause( FieldParent::Union(it), @@ -346,15 +349,16 @@ impl Printer<'_> { let Enum { name, visibility, variants, generic_params, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "enum {}", name.display(self.db.upcast())); + w!(self, "enum {}", name.display(self.db.upcast(), self.edition)); self.print_generic_params(generic_params, it.into()); self.print_where_clause_and_opening_brace(generic_params); + let edition = self.edition; self.indented(|this| { for variant in FileItemTreeId::range_iter(variants.clone()) { let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant]; this.print_ast_id(ast_id.erase()); this.print_attrs_of(variant, "\n"); - w!(this, "{}", name.display(self.db.upcast())); + w!(this, "{}", name.display(self.db.upcast(), edition)); this.print_fields(FieldParent::Variant(variant), *kind, fields); wln!(this, ","); } @@ -367,7 +371,7 @@ impl Printer<'_> { self.print_visibility(*visibility); w!(self, "const "); match name { - Some(name) => w!(self, "{}", name.display(self.db.upcast())), + Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)), None => w!(self, "_"), } w!(self, ": "); @@ -382,7 +386,7 @@ impl Printer<'_> { if *mutable { w!(self, "mut "); } - w!(self, "{}: ", name.display(self.db.upcast())); + w!(self, "{}: ", name.display(self.db.upcast(), self.edition)); self.print_type_ref(type_ref); w!(self, " = _;"); wln!(self); @@ -398,7 +402,7 @@ impl Printer<'_> { if *is_auto { w!(self, "auto "); } - w!(self, "trait {}", name.display(self.db.upcast())); + w!(self, "trait {}", name.display(self.db.upcast(), self.edition)); self.print_generic_params(generic_params, it.into()); self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { @@ -412,7 +416,7 @@ impl Printer<'_> { let TraitAlias { name, visibility, generic_params, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "trait {}", name.display(self.db.upcast())); + w!(self, "trait {}", name.display(self.db.upcast(), self.edition)); self.print_generic_params(generic_params, it.into()); w!(self, " = "); self.print_where_clause(generic_params); @@ -457,7 +461,7 @@ impl Printer<'_> { &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "type {}", name.display(self.db.upcast())); + w!(self, "type {}", name.display(self.db.upcast(), self.edition)); self.print_generic_params(generic_params, it.into()); if !bounds.is_empty() { w!(self, ": "); @@ -475,7 +479,7 @@ impl Printer<'_> { let Mod { name, visibility, kind, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - w!(self, "mod {}", name.display(self.db.upcast())); + w!(self, "mod {}", name.display(self.db.upcast(), self.edition)); match kind { ModKind::Inline { items } => { w!(self, " {{"); @@ -500,18 +504,22 @@ impl Printer<'_> { ctxt, expand_to ); - wln!(self, "{}!(...);", path.display(self.db.upcast())); + wln!(self, "{}!(...);", path.display(self.db.upcast(), self.edition)); } ModItem::MacroRules(it) => { let MacroRules { name, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); - wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db.upcast())); + wln!( + self, + "macro_rules! {} {{ ... }}", + name.display(self.db.upcast(), self.edition) + ); } ModItem::Macro2(it) => { let Macro2 { name, visibility, ast_id } = &self.tree[it]; self.print_ast_id(ast_id.erase()); self.print_visibility(*visibility); - wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast())); + wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast(), self.edition)); } } @@ -519,15 +527,18 @@ impl Printer<'_> { } fn print_type_ref(&mut self, type_ref: &TypeRef) { - print_type_ref(self.db, type_ref, self).unwrap(); + let edition = self.edition; + print_type_ref(self.db, type_ref, self, edition).unwrap(); } fn print_type_bounds(&mut self, bounds: &[Interned]) { - print_type_bounds(self.db, bounds, self).unwrap(); + let edition = self.edition; + print_type_bounds(self.db, bounds, self, edition).unwrap(); } fn print_path(&mut self, path: &Path) { - print_path(self.db, path, self).unwrap(); + let edition = self.edition; + print_path(self.db, path, self, edition).unwrap(); } fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) { @@ -543,7 +554,7 @@ impl Printer<'_> { } first = false; self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " "); - w!(self, "{}", lt.name.display(self.db.upcast())); + w!(self, "{}", lt.name.display(self.db.upcast(), self.edition)); } for (idx, x) in params.iter_type_or_consts() { if !first { @@ -553,11 +564,11 @@ impl Printer<'_> { self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " "); match x { TypeOrConstParamData::TypeParamData(ty) => match &ty.name { - Some(name) => w!(self, "{}", name.display(self.db.upcast())), + Some(name) => w!(self, "{}", name.display(self.db.upcast(), self.edition)), None => w!(self, "_anon_{}", idx.into_raw()), }, TypeOrConstParamData::ConstParamData(konst) => { - w!(self, "const {}: ", konst.name.display(self.db.upcast())); + w!(self, "const {}: ", konst.name.display(self.db.upcast(), self.edition)); self.print_type_ref(&konst.ty); } } @@ -580,6 +591,7 @@ impl Printer<'_> { } w!(self, "\nwhere"); + let edition = self.edition; self.indented(|this| { for (i, pred) in params.where_predicates().enumerate() { if i != 0 { @@ -592,8 +604,8 @@ impl Printer<'_> { wln!( this, "{}: {},", - target.name.display(self.db.upcast()), - bound.name.display(self.db.upcast()) + target.name.display(self.db.upcast(), edition), + bound.name.display(self.db.upcast(), edition) ); continue; } @@ -603,7 +615,7 @@ impl Printer<'_> { if i != 0 { w!(this, ", "); } - w!(this, "{}", lt.display(self.db.upcast())); + w!(this, "{}", lt.display(self.db.upcast(), edition)); } w!(this, "> "); (target, bound) @@ -613,7 +625,7 @@ impl Printer<'_> { match target { WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty), WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { - Some(name) => w!(this, "{}", name.display(self.db.upcast())), + Some(name) => w!(this, "{}", name.display(self.db.upcast(), edition)), None => w!(this, "_anon_{}", id.into_raw()), }, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index c6930401a6f5..5c07369f4b5b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -1,4 +1,5 @@ use expect_test::{expect, Expect}; +use span::Edition; use test_fixture::WithFixture; use crate::{db::DefDatabase, test_db::TestDB}; @@ -6,7 +7,7 @@ use crate::{db::DefDatabase, test_db::TestDB}; fn check(ra_fixture: &str, expect: Expect) { let (db, file_id) = TestDB::with_single_file(ra_fixture); let item_tree = db.file_item_tree(file_id.into()); - let pretty = item_tree.pretty_print(&db); + let pretty = item_tree.pretty_print(&db, Edition::CURRENT); expect.assert_eq(&pretty); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index 8825e4633632..11601c683e1e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -328,6 +328,10 @@ impl DefMap { /// The module id of a crate or block root. pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0)); + pub fn edition(&self) -> Edition { + self.data.edition + } + pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc { let crate_graph = db.crate_graph(); let krate = &crate_graph[crate_id]; @@ -550,7 +554,7 @@ impl DefMap { for (name, child) in map.modules[module].children.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) { - let path = format!("{path}::{}", name.display(db.upcast())); + let path = format!("{path}::{}", name.display(db.upcast(), Edition::LATEST)); buf.push('\n'); go(buf, db, map, &path, *child); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index debc5a44326e..22eb5a174d39 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -548,7 +548,7 @@ impl DefCollector<'_> { types => { tracing::debug!( "could not resolve prelude path `{}` to module (resolved to {:?})", - path.display(self.db.upcast()), + path.display(self.db.upcast(), Edition::LATEST), types ); } @@ -768,7 +768,7 @@ impl DefCollector<'_> { } fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { - let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast())) + let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast(), Edition::LATEST)) .entered(); tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition); match import.source { @@ -2151,7 +2151,7 @@ impl ModCollector<'_, '_> { } tracing::debug!( "non-builtin attribute {}", - attr.path.display(self.def_collector.db.upcast()) + attr.path.display(self.def_collector.db.upcast(), Edition::LATEST) ); let ast_id = AstIdWithPath::new( @@ -2286,8 +2286,8 @@ impl ModCollector<'_, '_> { stdx::always!( name == mac.name, "built-in macro {} has #[rustc_builtin_macro] which declares different name {}", - mac.name.display(self.def_collector.db.upcast()), - name.display(self.def_collector.db.upcast()) + mac.name.display(self.def_collector.db.upcast(), Edition::LATEST), + name.display(self.def_collector.db.upcast(), Edition::LATEST), ); helpers_opt = Some(helpers); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs index 390c934f6dac..a05c4dcf9bd7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs @@ -1,6 +1,7 @@ use expect_test::expect; use itertools::Itertools; +use span::Edition; use super::*; @@ -1100,7 +1101,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream { assert_eq!(def_map.data.exported_derives.len(), 1); match def_map.data.exported_derives.values().next() { Some(helpers) => match &**helpers { - [attr] => assert_eq!(attr.display(&db).to_string(), "helper_attr"), + [attr] => assert_eq!(attr.display(&db, Edition::CURRENT).to_string(), "helper_attr"), _ => unreachable!(), }, _ => unreachable!(), @@ -1456,7 +1457,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a } let actual = def_map .macro_use_prelude .keys() - .map(|name| name.display(&db).to_string()) + .map(|name| name.display(&db, Edition::CURRENT).to_string()) .sorted() .join("\n"); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs index 1327d9aa62e1..071b55c83d8d 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs @@ -144,14 +144,14 @@ pub struct Baz; crate::r#async Bar: t v - foo: t r#async: t - - crate::r#async::foo - Foo: t v + foo: t crate::r#async::r#async Baz: t v + + crate::r#async::foo + Foo: t v "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs index f90bc954a9b3..077863c0c939 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs @@ -13,7 +13,8 @@ use crate::{ }; use hir_expand::name::Name; use intern::Interned; -use syntax::{ast, ToSmolStr}; +use span::Edition; +use syntax::ast; pub use hir_expand::mod_path::{path, ModPath, PathKind}; @@ -25,11 +26,21 @@ pub enum ImportAlias { Alias(Name), } -impl Display for ImportAlias { +impl ImportAlias { + pub fn display(&self, edition: Edition) -> impl Display + '_ { + ImportAliasDisplay { value: self, edition } + } +} + +struct ImportAliasDisplay<'a> { + value: &'a ImportAlias, + edition: Edition, +} +impl Display for ImportAliasDisplay<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { + match self.value { ImportAlias::Underscore => f.write_str("_"), - ImportAlias::Alias(name) => f.write_str(&name.display_no_db().to_smolstr()), + ImportAlias::Alias(name) => Display::fmt(&name.display_no_db(self.edition), f), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs index 3ee88b536fc4..d5ef17a91fb2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs @@ -5,6 +5,7 @@ use std::fmt::{self, Write}; use hir_expand::mod_path::PathKind; use intern::Interned; use itertools::Itertools; +use span::Edition; use crate::{ db::DefDatabase, @@ -13,46 +14,51 @@ use crate::{ type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef}, }; -pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result { +pub(crate) fn print_path( + db: &dyn DefDatabase, + path: &Path, + buf: &mut dyn Write, + edition: Edition, +) -> fmt::Result { if let Path::LangItem(it, s) = path { write!(buf, "builtin#lang(")?; match *it { LangItemTarget::ImplDef(it) => write!(buf, "{it:?}")?, LangItemTarget::EnumId(it) => { - write!(buf, "{}", db.enum_data(it).name.display(db.upcast()))? + write!(buf, "{}", db.enum_data(it).name.display(db.upcast(), edition))? } LangItemTarget::Function(it) => { - write!(buf, "{}", db.function_data(it).name.display(db.upcast()))? + write!(buf, "{}", db.function_data(it).name.display(db.upcast(), edition))? } LangItemTarget::Static(it) => { - write!(buf, "{}", db.static_data(it).name.display(db.upcast()))? + write!(buf, "{}", db.static_data(it).name.display(db.upcast(), edition))? } LangItemTarget::Struct(it) => { - write!(buf, "{}", db.struct_data(it).name.display(db.upcast()))? + write!(buf, "{}", db.struct_data(it).name.display(db.upcast(), edition))? } LangItemTarget::Union(it) => { - write!(buf, "{}", db.union_data(it).name.display(db.upcast()))? + write!(buf, "{}", db.union_data(it).name.display(db.upcast(), edition))? } LangItemTarget::TypeAlias(it) => { - write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast()))? + write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast(), edition))? } LangItemTarget::Trait(it) => { - write!(buf, "{}", db.trait_data(it).name.display(db.upcast()))? + write!(buf, "{}", db.trait_data(it).name.display(db.upcast(), edition))? } LangItemTarget::EnumVariant(it) => { - write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast()))? + write!(buf, "{}", db.enum_variant_data(it).name.display(db.upcast(), edition))? } } if let Some(s) = s { - write!(buf, "::{}", s.display(db.upcast()))?; + write!(buf, "::{}", s.display(db.upcast(), edition))?; } return write!(buf, ")"); } match path.type_anchor() { Some(anchor) => { write!(buf, "<")?; - print_type_ref(db, anchor, buf)?; + print_type_ref(db, anchor, buf, edition)?; write!(buf, ">::")?; } None => match path.kind() { @@ -78,10 +84,10 @@ pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) write!(buf, "::")?; } - write!(buf, "{}", segment.name.display(db.upcast()))?; + write!(buf, "{}", segment.name.display(db.upcast(), edition))?; if let Some(generics) = segment.args_and_bindings { write!(buf, "::<")?; - print_generic_args(db, generics, buf)?; + print_generic_args(db, generics, buf, edition)?; write!(buf, ">")?; } @@ -94,12 +100,13 @@ pub(crate) fn print_generic_args( db: &dyn DefDatabase, generics: &GenericArgs, buf: &mut dyn Write, + edition: Edition, ) -> fmt::Result { let mut first = true; let args = if generics.has_self_type { let (self_ty, args) = generics.args.split_first().unwrap(); write!(buf, "Self=")?; - print_generic_arg(db, self_ty, buf)?; + print_generic_arg(db, self_ty, buf, edition)?; first = false; args } else { @@ -110,21 +117,21 @@ pub(crate) fn print_generic_args( write!(buf, ", ")?; } first = false; - print_generic_arg(db, arg, buf)?; + print_generic_arg(db, arg, buf, edition)?; } for binding in generics.bindings.iter() { if !first { write!(buf, ", ")?; } first = false; - write!(buf, "{}", binding.name.display(db.upcast()))?; + write!(buf, "{}", binding.name.display(db.upcast(), edition))?; if !binding.bounds.is_empty() { write!(buf, ": ")?; - print_type_bounds(db, &binding.bounds, buf)?; + print_type_bounds(db, &binding.bounds, buf, edition)?; } if let Some(ty) = &binding.type_ref { write!(buf, " = ")?; - print_type_ref(db, ty, buf)?; + print_type_ref(db, ty, buf, edition)?; } } Ok(()) @@ -134,11 +141,12 @@ pub(crate) fn print_generic_arg( db: &dyn DefDatabase, arg: &GenericArg, buf: &mut dyn Write, + edition: Edition, ) -> fmt::Result { match arg { - GenericArg::Type(ty) => print_type_ref(db, ty, buf), - GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast())), - GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast())), + GenericArg::Type(ty) => print_type_ref(db, ty, buf, edition), + GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast(), edition)), + GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition)), } } @@ -146,6 +154,7 @@ pub(crate) fn print_type_ref( db: &dyn DefDatabase, type_ref: &TypeRef, buf: &mut dyn Write, + edition: Edition, ) -> fmt::Result { // FIXME: deduplicate with `HirDisplay` impl match type_ref { @@ -157,18 +166,18 @@ pub(crate) fn print_type_ref( if i != 0 { write!(buf, ", ")?; } - print_type_ref(db, field, buf)?; + print_type_ref(db, field, buf, edition)?; } write!(buf, ")")?; } - TypeRef::Path(path) => print_path(db, path, buf)?, + TypeRef::Path(path) => print_path(db, path, buf, edition)?, TypeRef::RawPtr(pointee, mtbl) => { let mtbl = match mtbl { Mutability::Shared => "*const", Mutability::Mut => "*mut", }; write!(buf, "{mtbl} ")?; - print_type_ref(db, pointee, buf)?; + print_type_ref(db, pointee, buf, edition)?; } TypeRef::Reference(pointee, lt, mtbl) => { let mtbl = match mtbl { @@ -177,19 +186,19 @@ pub(crate) fn print_type_ref( }; write!(buf, "&")?; if let Some(lt) = lt { - write!(buf, "{} ", lt.name.display(db.upcast()))?; + write!(buf, "{} ", lt.name.display(db.upcast(), edition))?; } write!(buf, "{mtbl}")?; - print_type_ref(db, pointee, buf)?; + print_type_ref(db, pointee, buf, edition)?; } TypeRef::Array(elem, len) => { write!(buf, "[")?; - print_type_ref(db, elem, buf)?; - write!(buf, "; {}]", len.display(db.upcast()))?; + print_type_ref(db, elem, buf, edition)?; + write!(buf, "; {}]", len.display(db.upcast(), edition))?; } TypeRef::Slice(elem) => { write!(buf, "[")?; - print_type_ref(db, elem, buf)?; + print_type_ref(db, elem, buf, edition)?; write!(buf, "]")?; } TypeRef::Fn(args_and_ret, varargs, is_unsafe, abi) => { @@ -208,7 +217,7 @@ pub(crate) fn print_type_ref( if i != 0 { write!(buf, ", ")?; } - print_type_ref(db, typeref, buf)?; + print_type_ref(db, typeref, buf, edition)?; } if *varargs { if !args.is_empty() { @@ -217,7 +226,7 @@ pub(crate) fn print_type_ref( write!(buf, "...")?; } write!(buf, ") -> ")?; - print_type_ref(db, return_type, buf)?; + print_type_ref(db, return_type, buf, edition)?; } TypeRef::Macro(_ast_id) => { write!(buf, "")?; @@ -225,11 +234,11 @@ pub(crate) fn print_type_ref( TypeRef::Error => write!(buf, "{{unknown}}")?, TypeRef::ImplTrait(bounds) => { write!(buf, "impl ")?; - print_type_bounds(db, bounds, buf)?; + print_type_bounds(db, bounds, buf, edition)?; } TypeRef::DynTrait(bounds) => { write!(buf, "dyn ")?; - print_type_bounds(db, bounds, buf)?; + print_type_bounds(db, bounds, buf, edition)?; } } @@ -240,6 +249,7 @@ pub(crate) fn print_type_bounds( db: &dyn DefDatabase, bounds: &[Interned], buf: &mut dyn Write, + edition: Edition, ) -> fmt::Result { for (i, bound) in bounds.iter().enumerate() { if i != 0 { @@ -252,17 +262,17 @@ pub(crate) fn print_type_bounds( TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(buf, "?")?, } - print_path(db, path, buf)?; + print_path(db, path, buf, edition)?; } TypeBound::ForLifetime(lifetimes, path) => { write!( buf, "for<{}> ", - lifetimes.iter().map(|it| it.display(db.upcast())).format(", ") + lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ") )?; - print_path(db, path, buf)?; + print_path(db, path, buf, edition)?; } - TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast()))?, + TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?, TypeBound::Error => write!(buf, "{{unknown}}")?, } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index 3528b2dde73e..1dadfe2ba99b 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -176,9 +176,10 @@ fn eager_macro_recur( Some(path) => match macro_resolver(&path) { Some(def) => def, None => { + let edition = db.crate_graph()[krate].edition; error = Some(ExpandError::other( span_map.span_at(call.syntax().text_range().start()), - format!("unresolved macro {}", path.display(db)), + format!("unresolved macro {}", path.display(db, edition)), )); offset += call.syntax().text_range().len(); continue; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 2c26fe414d91..dcf2af399797 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -14,7 +14,7 @@ use crate::{ use base_db::CrateId; use intern::sym; use smallvec::SmallVec; -use span::SyntaxContextId; +use span::{Edition, SyntaxContextId}; use syntax::{ast, AstNode}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -140,8 +140,12 @@ impl ModPath { UnescapedModPath(self) } - pub fn display<'a>(&'a self, db: &'a dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { - Display { db, path: self } + pub fn display<'a>( + &'a self, + db: &'a dyn crate::db::ExpandDatabase, + edition: Edition, + ) -> impl fmt::Display + 'a { + Display { db, path: self, edition } } } @@ -154,11 +158,12 @@ impl Extend for ModPath { struct Display<'a> { db: &'a dyn ExpandDatabase, path: &'a ModPath, + edition: Edition, } impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - display_fmt_path(self.db, self.path, f, true) + display_fmt_path(self.db, self.path, f, Escape::IfNeeded(self.edition)) } } @@ -169,7 +174,7 @@ struct UnescapedDisplay<'a> { impl fmt::Display for UnescapedDisplay<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - display_fmt_path(self.db, self.path.0, f, false) + display_fmt_path(self.db, self.path.0, f, Escape::No) } } @@ -178,11 +183,17 @@ impl From for ModPath { ModPath::from_segments(PathKind::Plain, iter::once(name)) } } + +enum Escape { + No, + IfNeeded(Edition), +} + fn display_fmt_path( db: &dyn ExpandDatabase, path: &ModPath, f: &mut fmt::Formatter<'_>, - escaped: bool, + escaped: Escape, ) -> fmt::Result { let mut first_segment = true; let mut add_segment = |s| -> fmt::Result { @@ -210,10 +221,9 @@ fn display_fmt_path( f.write_str("::")?; } first_segment = false; - if escaped { - segment.display(db).fmt(f)?; - } else { - segment.unescaped().display(db).fmt(f)?; + match escaped { + Escape::IfNeeded(edition) => segment.display(db, edition).fmt(f)?, + Escape::No => segment.unescaped().display(db).fmt(f)?, } } Ok(()) @@ -322,9 +332,11 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option PathKind::SELF, tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::super_ => { let mut deg = 1; - while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw })) = leaves.next() { + while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw: _ })) = + leaves.next() + { if *text != sym::super_ { - segments.push(Name::new_symbol_maybe_raw(text.clone(), *is_raw, span.ctx)); + segments.push(Name::new_symbol(text.clone(), span.ctx)); break; } deg += 1; @@ -333,19 +345,13 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option PathKind::Crate, tt::Leaf::Ident(ident) => { - segments.push(Name::new_symbol_maybe_raw( - ident.sym.clone(), - ident.is_raw, - ident.span.ctx, - )); + segments.push(Name::new_symbol(ident.sym.clone(), ident.span.ctx)); PathKind::Plain } _ => return None, }; segments.extend(leaves.filter_map(|leaf| match leaf { - ::tt::Leaf::Ident(ident) => { - Some(Name::new_symbol_maybe_raw(ident.sym.clone(), ident.is_raw, ident.span.ctx)) - } + ::tt::Leaf::Ident(ident) => Some(Name::new_symbol(ident.sym.clone(), ident.span.ctx)), _ => None, })); Some(ModPath { kind, segments }) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 2a52aaba6af9..54313904a7ec 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -3,22 +3,22 @@ use std::fmt; use intern::{sym, Symbol}; -use span::SyntaxContextId; -use syntax::{ast, utils::is_raw_identifier}; +use span::{Edition, SyntaxContextId}; +use syntax::ast; +use syntax::utils::is_raw_identifier; /// `Name` is a wrapper around string, which is used in hir for both references /// and declarations. In theory, names should also carry hygiene info, but we are /// not there yet! /// -/// Note that `Name` holds and prints escaped name i.e. prefixed with "r#" when it -/// is a raw identifier. Use [`unescaped()`][Name::unescaped] when you need the -/// name without "r#". +/// Note that the rawness (`r#`) of names does not depend on whether they are written raw. +/// This is because we want to show (in completions etc.) names as raw depending on the needs +/// of the current crate, for example if it is edition 2021 complete `gen` even if the defining +/// crate is in edition 2024 and wrote `r#gen`, and the opposite holds as well. #[derive(Clone, PartialEq, Eq, Hash)] pub struct Name { symbol: Symbol, ctx: (), - // FIXME: We should probably encode rawness as a property here instead, once we have hygiene - // in here we've got 4 bytes of padding to fill anyways } impl fmt::Debug for Name { @@ -42,6 +42,7 @@ impl PartialOrd for Name { } } +// No need to strip `r#`, all comparisons are done against well-known symbols. impl PartialEq for Name { fn eq(&self, sym: &Symbol) -> bool { self.symbol == *sym @@ -55,16 +56,16 @@ impl PartialEq for Symbol { } /// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct UnescapedName<'a>(&'a Name); -impl UnescapedName<'_> { - pub fn display(&self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + '_ { +impl<'a> UnescapedName<'a> { + pub fn display(self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { _ = db; UnescapedDisplay { name: self } } #[doc(hidden)] - pub fn display_no_db(&self) -> impl fmt::Display + '_ { + pub fn display_no_db(self) -> impl fmt::Display + 'a { UnescapedDisplay { name: self } } } @@ -77,16 +78,9 @@ impl Name { Name { symbol: Symbol::intern(text), ctx: () } } - pub fn new(text: &str, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Name { + pub fn new(text: &str, ctx: SyntaxContextId) -> Name { _ = ctx; - Name { - symbol: if raw.yes() { - Symbol::intern(&format!("{}{text}", raw.as_str())) - } else { - Symbol::intern(text) - }, - ctx: (), - } + Self::new_text(text) } pub fn new_tuple_field(idx: usize) -> Name { @@ -97,26 +91,9 @@ impl Name { Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () } } - /// Shortcut to create a name from a string literal. - fn new_ref(text: &str) -> Name { - Name { symbol: Symbol::intern(text), ctx: () } - } - /// Resolve a name from the text of token. fn resolve(raw_text: &str) -> Name { - // FIXME: Edition - match raw_text.strip_prefix("r#") { - // When `raw_text` starts with "r#" but the name does not coincide with any - // keyword, we never need the prefix so we strip it. - Some(text) if !is_raw_identifier(text, span::Edition::CURRENT) => Name::new_ref(text), - // Keywords (in the current edition) *can* be used as a name in earlier editions of - // Rust, e.g. "try" in Rust 2015. Even in such cases, we keep track of them in their - // escaped form. - None if is_raw_identifier(raw_text, span::Edition::CURRENT) => { - Name::new_text(&format!("r#{}", raw_text)) - } - _ => Name::new_text(raw_text), - } + Name::new_text(raw_text.trim_start_matches("r#")) } /// A fake name for things missing in the source code. @@ -162,19 +139,23 @@ impl Name { UnescapedName(self) } - pub fn is_escaped(&self) -> bool { - self.symbol.as_str().starts_with("r#") + pub fn is_escaped(&self, edition: Edition) -> bool { + is_raw_identifier(self.symbol.as_str(), edition) } - pub fn display<'a>(&'a self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a { + pub fn display<'a>( + &'a self, + db: &dyn crate::db::ExpandDatabase, + edition: Edition, + ) -> impl fmt::Display + 'a { _ = db; - Display { name: self } + self.display_no_db(edition) } // FIXME: Remove this #[doc(hidden)] - pub fn display_no_db(&self) -> impl fmt::Display + '_ { - Display { name: self } + pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ { + Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) } } pub fn symbol(&self) -> &Symbol { @@ -186,39 +167,39 @@ impl Name { Self { symbol, ctx: () } } - pub fn new_symbol_maybe_raw(sym: Symbol, raw: tt::IdentIsRaw, ctx: SyntaxContextId) -> Self { - if raw.no() { - Self { symbol: sym, ctx: () } - } else { - Name::new(sym.as_str(), raw, ctx) - } - } - // FIXME: This needs to go once we have hygiene pub const fn new_symbol_root(sym: Symbol) -> Self { Self { symbol: sym, ctx: () } } + + #[inline] + pub fn eq_ident(&self, ident: &str) -> bool { + self.as_str() == ident.trim_start_matches("r#") + } } struct Display<'a> { name: &'a Name, + needs_escaping: bool, } impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.needs_escaping { + write!(f, "r#")?; + } fmt::Display::fmt(self.name.symbol.as_str(), f) } } struct UnescapedDisplay<'a> { - name: &'a UnescapedName<'a>, + name: UnescapedName<'a>, } impl fmt::Display for UnescapedDisplay<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let symbol = &self.name.0.symbol.as_str(); - let text = symbol.strip_prefix("r#").unwrap_or(symbol); - fmt::Display::fmt(&text, f) + let symbol = self.name.0.symbol.as_str(); + fmt::Display::fmt(symbol, f) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index a151ee01e645..a3e4da5d1afd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -5,6 +5,7 @@ use std::{iter, ops::ControlFlow, sync::Arc}; use hir_expand::name::Name; use intern::sym; +use span::Edition; use tracing::debug; use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds}; @@ -424,18 +425,19 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { fn trait_name(&self, trait_id: chalk_ir::TraitId) -> String { let id = from_chalk_trait_id(trait_id); - self.db.trait_data(id).name.display(self.db.upcast()).to_string() + self.db.trait_data(id).name.display(self.db.upcast(), self.edition()).to_string() } fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String { + let edition = self.edition(); match adt_id { hir_def::AdtId::StructId(id) => { - self.db.struct_data(id).name.display(self.db.upcast()).to_string() + self.db.struct_data(id).name.display(self.db.upcast(), edition).to_string() } hir_def::AdtId::EnumId(id) => { - self.db.enum_data(id).name.display(self.db.upcast()).to_string() + self.db.enum_data(id).name.display(self.db.upcast(), edition).to_string() } hir_def::AdtId::UnionId(id) => { - self.db.union_data(id).name.display(self.db.upcast()).to_string() + self.db.union_data(id).name.display(self.db.upcast(), edition).to_string() } } } @@ -445,7 +447,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { } fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId) -> String { let id = self.db.associated_ty_data(assoc_ty_id).name; - self.db.type_alias_data(id).name.display(self.db.upcast()).to_string() + self.db.type_alias_data(id).name.display(self.db.upcast(), self.edition()).to_string() } fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId) -> String { format!("Opaque_{}", opaque_ty_id.0) @@ -519,6 +521,10 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { } impl<'a> ChalkContext<'a> { + fn edition(&self) -> Edition { + self.db.crate_graph()[self.krate].edition + } + fn for_trait_impls( &self, trait_id: hir_def::TraitId, @@ -843,7 +849,7 @@ fn impl_def_datum( "impl {:?}: {}{} where {:?}", chalk_id, if negative { "!" } else { "" }, - trait_ref.display(db), + trait_ref.display(db, db.crate_graph()[krate].edition), where_clauses ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index dc3817ce3f40..a0399a06f236 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -1,3 +1,4 @@ +use base_db::SourceDatabase; use chalk_ir::Substitution; use hir_def::db::DefDatabase; use rustc_apfloat::{ @@ -94,9 +95,10 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { let mut err = String::new(); let span_formatter = |file, range| format!("{file:?} {range:?}"); + let edition = db.crate_graph()[db.test_crate()].edition; match e { - ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter), - ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter), + ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter, edition), + ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter, edition), } .unwrap(); err @@ -110,7 +112,9 @@ fn eval_goal(db: &TestDB, file_id: EditionedFileId) -> Result { - if db.const_data(x).name.as_ref()?.display(db).to_string() == "GOAL" { + if db.const_data(x).name.as_ref()?.display(db, file_id.edition()).to_string() + == "GOAL" + { Some(x) } else { None diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index b09344006080..024fc32f8637 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -17,17 +17,18 @@ use std::fmt; use hir_def::{ data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, AttrDefId, ConstId, - EnumId, EnumVariantId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId, - StructId, TraitId, TypeAliasId, + EnumId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, ModuleDefId, ModuleId, + StaticId, StructId, TraitId, TypeAliasId, }; use hir_expand::{ name::{AsName, Name}, - HirFileId, MacroFileIdExt, + HirFileId, HirFileIdExt, MacroFileIdExt, }; use intern::sym; use stdx::{always, never}; use syntax::{ ast::{self, HasName}, + utils::is_raw_identifier, AstNode, AstPtr, ToSmolStr, }; @@ -318,17 +319,21 @@ impl<'a> DeclValidator<'a> { /// This includes function parameters except for trait implementation associated functions. fn validate_func_body(&mut self, func: FunctionId) { let body = self.db.body(func.into()); + let edition = self.edition(func); let mut pats_replacements = body .pats .iter() .filter_map(|(pat_id, pat)| match pat { Pat::Bind { id, .. } => { let bind_name = &body.bindings[*id].name; + let mut suggested_text = + to_lower_snake_case(&bind_name.unescaped().display_no_db().to_smolstr())?; + if is_raw_identifier(&suggested_text, edition) { + suggested_text.insert_str(0, "r#"); + } let replacement = Replacement { current_name: bind_name.clone(), - suggested_text: to_lower_snake_case( - &bind_name.display_no_db().to_smolstr(), - )?, + suggested_text, expected_case: CaseType::LowerSnakeCase, }; Some((pat_id, replacement)) @@ -377,6 +382,11 @@ impl<'a> DeclValidator<'a> { } } + fn edition(&self, id: impl HasModule) -> span::Edition { + let krate = id.krate(self.db.upcast()); + self.db.crate_graph()[krate].edition + } + fn validate_struct(&mut self, struct_id: StructId) { // Check the structure name. let non_camel_case_allowed = @@ -405,16 +415,17 @@ impl<'a> DeclValidator<'a> { let VariantData::Record(fields) = data.variant_data.as_ref() else { return; }; + let edition = self.edition(struct_id); let mut struct_fields_replacements = fields .iter() .filter_map(|(_, field)| { - to_lower_snake_case(&field.name.display_no_db().to_smolstr()).map(|new_name| { - Replacement { + to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map( + |new_name| Replacement { current_name: field.name.clone(), suggested_text: new_name, expected_case: CaseType::LowerSnakeCase, - } - }) + }, + ) }) .peekable(); @@ -498,14 +509,17 @@ impl<'a> DeclValidator<'a> { self.validate_enum_variant_fields(*variant_id); } + let edition = self.edition(enum_id); let mut enum_variants_replacements = data .variants .iter() .filter_map(|(_, name)| { - to_camel_case(&name.display_no_db().to_smolstr()).map(|new_name| Replacement { - current_name: name.clone(), - suggested_text: new_name, - expected_case: CaseType::UpperCamelCase, + to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| { + Replacement { + current_name: name.clone(), + suggested_text: new_name, + expected_case: CaseType::UpperCamelCase, + } }) }) .peekable(); @@ -566,16 +580,17 @@ impl<'a> DeclValidator<'a> { let VariantData::Record(fields) = variant_data.variant_data.as_ref() else { return; }; + let edition = self.edition(variant_id); let mut variant_field_replacements = fields .iter() .filter_map(|(_, field)| { - to_lower_snake_case(&field.name.display_no_db().to_smolstr()).map(|new_name| { - Replacement { + to_lower_snake_case(&field.name.display_no_db(edition).to_smolstr()).map( + |new_name| Replacement { current_name: field.name.clone(), suggested_text: new_name, expected_case: CaseType::LowerSnakeCase, - } - }) + }, + ) }) .peekable(); @@ -704,18 +719,22 @@ impl<'a> DeclValidator<'a> { ) where N: AstNode + HasName + fmt::Debug, S: HasSource, - L: Lookup = dyn DefDatabase + 'a>, + L: Lookup = dyn DefDatabase + 'a> + HasModule + Copy, { let to_expected_case_type = match expected_case { CaseType::LowerSnakeCase => to_lower_snake_case, CaseType::UpperSnakeCase => to_upper_snake_case, CaseType::UpperCamelCase => to_camel_case, }; - let Some(replacement) = - to_expected_case_type(&name.display(self.db.upcast()).to_smolstr()).map(|new_name| { - Replacement { current_name: name.clone(), suggested_text: new_name, expected_case } - }) - else { + let edition = self.edition(item_id); + let Some(replacement) = to_expected_case_type( + &name.display(self.db.upcast(), edition).to_smolstr(), + ) + .map(|new_name| Replacement { + current_name: name.clone(), + suggested_text: new_name, + expected_case, + }) else { return; }; @@ -748,12 +767,13 @@ impl<'a> DeclValidator<'a> { return; }; + let edition = file_id.original_file(self.db.upcast()).edition(); let diagnostic = IncorrectCase { file: file_id, ident_type, ident: AstPtr::new(&name_ast), expected_case: replacement.expected_case, - ident_text: replacement.current_name.display(self.db.upcast()).to_string(), + ident_text: replacement.current_name.display(self.db.upcast(), edition).to_string(), suggested_text: replacement.suggested_text, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 6e5a7cce9c97..f8b5c7d0ce2c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -4,6 +4,7 @@ use std::fmt; +use base_db::CrateId; use chalk_solve::rust_ir::AdtKind; use either::Either; use hir_def::{ @@ -15,6 +16,7 @@ use intern::sym; use itertools::Itertools; use rustc_hash::FxHashSet; use rustc_pattern_analysis::constructor::Constructor; +use span::Edition; use syntax::{ ast::{self, UnaryOp}, AstNode, @@ -258,7 +260,13 @@ impl ExprValidator { if !witnesses.is_empty() { self.diagnostics.push(BodyValidationDiagnostic::MissingMatchArms { match_expr, - uncovered_patterns: missing_match_arms(&cx, scrut_ty, witnesses, m_arms.is_empty()), + uncovered_patterns: missing_match_arms( + &cx, + scrut_ty, + witnesses, + m_arms.is_empty(), + self.owner.krate(db.upcast()), + ), }); } } @@ -345,7 +353,13 @@ impl ExprValidator { if !witnesses.is_empty() { self.diagnostics.push(BodyValidationDiagnostic::NonExhaustiveLet { pat, - uncovered_patterns: missing_match_arms(&cx, ty, witnesses, false), + uncovered_patterns: missing_match_arms( + &cx, + ty, + witnesses, + false, + self.owner.krate(db.upcast()), + ), }); } } @@ -616,24 +630,26 @@ fn missing_match_arms<'p>( scrut_ty: &Ty, witnesses: Vec>, arms_is_empty: bool, + krate: CrateId, ) -> String { - struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>); + struct DisplayWitness<'a, 'p>(&'a WitnessPat<'p>, &'a MatchCheckCtx<'p>, Edition); impl fmt::Display for DisplayWitness<'_, '_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let DisplayWitness(witness, cx) = *self; + let DisplayWitness(witness, cx, edition) = *self; let pat = cx.hoist_witness_pat(witness); - write!(f, "{}", pat.display(cx.db)) + write!(f, "{}", pat.display(cx.db, edition)) } } + let edition = cx.db.crate_graph()[krate].edition; let non_empty_enum = match scrut_ty.as_adt() { Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(), _ => false, }; if arms_is_empty && !non_empty_enum { - format!("type `{}` is non-empty", scrut_ty.display(cx.db)) + format!("type `{}` is non-empty", scrut_ty.display(cx.db, edition)) } else { - let pat_display = |witness| DisplayWitness(witness, cx); + let pat_display = |witness| DisplayWitness(witness, cx, edition); const LIMIT: usize = 3; match &*witnesses { [witness] => format!("`{}` not covered", pat_display(witness)), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs index a0ee7c0748b1..4bc07bc9ec8f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs @@ -14,6 +14,7 @@ use hir_def::{ body::Body, data::adt::VariantData, hir::PatId, AdtId, EnumVariantId, LocalFieldId, VariantId, }; use hir_expand::name::Name; +use span::Edition; use stdx::{always, never}; use crate::{ @@ -151,7 +152,11 @@ impl<'a> PatCtxt<'a> { match (bm, ty.kind(Interner)) { (BindingMode::Ref(_), TyKind::Ref(.., rty)) => ty = rty, (BindingMode::Ref(_), _) => { - never!("`ref {}` has wrong type {:?}", name.display(self.db.upcast()), ty); + never!( + "`ref {}` has wrong type {:?}", + name.display(self.db.upcast(), Edition::LATEST), + ty + ); self.errors.push(PatternError::UnexpectedType); return Pat { ty: ty.clone(), kind: PatKind::Wild.into() }; } @@ -297,7 +302,7 @@ impl HirDisplay for Pat { PatKind::Wild => write!(f, "_"), PatKind::Never => write!(f, "!"), PatKind::Binding { name, subpattern } => { - write!(f, "{}", name.display(f.db.upcast()))?; + write!(f, "{}", name.display(f.db.upcast(), f.edition()))?; if let Some(subpattern) = subpattern { write!(f, " @ ")?; subpattern.hir_fmt(f)?; @@ -317,14 +322,22 @@ impl HirDisplay for Pat { if let Some(variant) = variant { match variant { VariantId::EnumVariantId(v) => { - write!(f, "{}", f.db.enum_variant_data(v).name.display(f.db.upcast()))?; - } - VariantId::StructId(s) => { - write!(f, "{}", f.db.struct_data(s).name.display(f.db.upcast()))? - } - VariantId::UnionId(u) => { - write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast()))? + write!( + f, + "{}", + f.db.enum_variant_data(v).name.display(f.db.upcast(), f.edition()) + )?; } + VariantId::StructId(s) => write!( + f, + "{}", + f.db.struct_data(s).name.display(f.db.upcast(), f.edition()) + )?, + VariantId::UnionId(u) => write!( + f, + "{}", + f.db.union_data(u).name.display(f.db.upcast(), f.edition()) + )?, }; let variant_data = variant.variant_data(f.db.upcast()); @@ -341,7 +354,9 @@ impl HirDisplay for Pat { write!( f, "{}: ", - rec_fields[p.field].name.display(f.db.upcast()) + rec_fields[p.field] + .name + .display(f.db.upcast(), f.edition()) )?; p.pattern.hir_fmt(f) }) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 5a96d396ab89..4ef053130a8b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -33,6 +33,7 @@ use rustc_apfloat::{ Float, }; use smallvec::SmallVec; +use span::Edition; use stdx::{never, IsNoneOr}; use triomphe::Arc; @@ -131,7 +132,11 @@ pub trait HirDisplay { /// Returns a `Display`able type that is human-readable. /// Use this for showing types to the user (e.g. diagnostics) - fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self> + fn display<'a>( + &'a self, + db: &'a dyn HirDatabase, + edition: Edition, + ) -> HirDisplayWrapper<'a, Self> where Self: Sized, { @@ -142,7 +147,7 @@ pub trait HirDisplay { limited_size: None, omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, - display_target: DisplayTarget::Diagnostics, + display_target: DisplayTarget::Diagnostics { edition }, show_container_bounds: false, } } @@ -153,6 +158,7 @@ pub trait HirDisplay { &'a self, db: &'a dyn HirDatabase, max_size: Option, + edition: Edition, ) -> HirDisplayWrapper<'a, Self> where Self: Sized, @@ -164,7 +170,7 @@ pub trait HirDisplay { limited_size: None, omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, - display_target: DisplayTarget::Diagnostics, + display_target: DisplayTarget::Diagnostics { edition }, show_container_bounds: false, } } @@ -175,6 +181,7 @@ pub trait HirDisplay { &'a self, db: &'a dyn HirDatabase, limited_size: Option, + edition: Edition, ) -> HirDisplayWrapper<'a, Self> where Self: Sized, @@ -186,7 +193,7 @@ pub trait HirDisplay { limited_size, omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, - display_target: DisplayTarget::Diagnostics, + display_target: DisplayTarget::Diagnostics { edition }, show_container_bounds: false, } } @@ -242,6 +249,7 @@ pub trait HirDisplay { &'a self, db: &'a dyn HirDatabase, show_container_bounds: bool, + edition: Edition, ) -> HirDisplayWrapper<'a, Self> where Self: Sized, @@ -253,13 +261,23 @@ pub trait HirDisplay { limited_size: None, omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, - display_target: DisplayTarget::Diagnostics, + display_target: DisplayTarget::Diagnostics { edition }, show_container_bounds, } } } impl HirFormatter<'_> { + pub fn edition(&self) -> Edition { + match self.display_target { + DisplayTarget::Diagnostics { edition } => edition, + DisplayTarget::SourceCode { module_id, .. } => { + self.db.crate_graph()[module_id.krate()].edition + } + DisplayTarget::Test => Edition::CURRENT, + } + } + pub fn write_joined( &mut self, iter: impl IntoIterator, @@ -324,7 +342,7 @@ pub enum DisplayTarget { /// Display types for inlays, doc popups, autocompletion, etc... /// Showing `{unknown}` or not qualifying paths is fine here. /// There's no reason for this to fail. - Diagnostics, + Diagnostics { edition: Edition }, /// Display types for inserting them in source files. /// The generated code should compile, so paths need to be qualified. SourceCode { module_id: ModuleId, allow_opaque: bool }, @@ -460,7 +478,7 @@ impl HirDisplay for ProjectionTy { ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)) .name - .display(f.db.upcast()) + .display(f.db.upcast(), f.edition()) )?; let proj_params_count = self.substitution.len(Interner) - trait_ref.substitution.len(Interner); @@ -499,7 +517,7 @@ impl HirDisplay for Const { let id = from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); let param_data = &generics[id.local_id]; - write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?; + write!(f, "{}", param_data.name().unwrap().display(f.db.upcast(), f.edition()))?; Ok(()) } ConstValue::Concrete(c) => match &c.interned { @@ -633,7 +651,7 @@ fn render_const_scalar( TyKind::Adt(adt, _) if b.len() == 2 * size_of::() => match adt.0 { hir_def::AdtId::StructId(s) => { let data = f.db.struct_data(s); - write!(f, "&{}", data.name.display(f.db.upcast()))?; + write!(f, "&{}", data.name.display(f.db.upcast(), f.edition()))?; Ok(()) } _ => f.write_str(""), @@ -691,7 +709,7 @@ fn render_const_scalar( match adt.0 { hir_def::AdtId::StructId(s) => { let data = f.db.struct_data(s); - write!(f, "{}", data.name.display(f.db.upcast()))?; + write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?; let field_types = f.db.field_types(s.into()); render_variant_after_name( &data.variant_data, @@ -705,7 +723,7 @@ fn render_const_scalar( ) } hir_def::AdtId::UnionId(u) => { - write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast())) + write!(f, "{}", f.db.union_data(u).name.display(f.db.upcast(), f.edition())) } hir_def::AdtId::EnumId(e) => { let Ok(target_data_layout) = f.db.target_data_layout(trait_env.krate) else { @@ -717,7 +735,7 @@ fn render_const_scalar( return f.write_str(""); }; let data = f.db.enum_variant_data(var_id); - write!(f, "{}", data.name.display(f.db.upcast()))?; + write!(f, "{}", data.name.display(f.db.upcast(), f.edition()))?; let field_types = f.db.field_types(var_id.into()); render_variant_after_name( &data.variant_data, @@ -802,11 +820,11 @@ fn render_variant_after_name( if matches!(data, VariantData::Record(_)) { write!(f, " {{")?; if let Some((id, data)) = it.next() { - write!(f, " {}: ", data.name.display(f.db.upcast()))?; + write!(f, " {}: ", data.name.display(f.db.upcast(), f.edition()))?; render_field(f, id)?; } for (id, data) in it { - write!(f, ", {}: ", data.name.display(f.db.upcast()))?; + write!(f, ", {}: ", data.name.display(f.db.upcast(), f.edition()))?; render_field(f, id)?; } write!(f, " }}")?; @@ -1000,15 +1018,23 @@ impl HirDisplay for Ty { CallableDefId::FunctionId(ff) => { write!(f, "fn ")?; f.start_location_link(def.into()); - write!(f, "{}", db.function_data(ff).name.display(f.db.upcast()))? + write!( + f, + "{}", + db.function_data(ff).name.display(f.db.upcast(), f.edition()) + )? } CallableDefId::StructId(s) => { f.start_location_link(def.into()); - write!(f, "{}", db.struct_data(s).name.display(f.db.upcast()))? + write!(f, "{}", db.struct_data(s).name.display(f.db.upcast(), f.edition()))? } CallableDefId::EnumVariantId(e) => { f.start_location_link(def.into()); - write!(f, "{}", db.enum_variant_data(e).name.display(f.db.upcast()))? + write!( + f, + "{}", + db.enum_variant_data(e).name.display(f.db.upcast(), f.edition()) + )? } }; f.end_location_link(); @@ -1053,13 +1079,13 @@ impl HirDisplay for Ty { TyKind::Adt(AdtId(def_id), parameters) => { f.start_location_link((*def_id).into()); match f.display_target { - DisplayTarget::Diagnostics | DisplayTarget::Test => { + DisplayTarget::Diagnostics { .. } | DisplayTarget::Test => { let name = match *def_id { hir_def::AdtId::StructId(it) => db.struct_data(it).name.clone(), hir_def::AdtId::UnionId(it) => db.union_data(it).name.clone(), hir_def::AdtId::EnumId(it) => db.enum_data(it).name.clone(), }; - write!(f, "{}", name.display(f.db.upcast()))?; + write!(f, "{}", name.display(f.db.upcast(), f.edition()))?; } DisplayTarget::SourceCode { module_id, allow_opaque: _ } => { if let Some(path) = find_path::find_path( @@ -1075,7 +1101,7 @@ impl HirDisplay for Ty { prefer_absolute: false, }, ) { - write!(f, "{}", path.display(f.db.upcast()))?; + write!(f, "{}", path.display(f.db.upcast(), f.edition()))?; } else { return Err(HirDisplayError::DisplaySourceCodeError( DisplaySourceCodeError::PathNotFound, @@ -1101,12 +1127,12 @@ impl HirDisplay for Ty { // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types) if f.display_target.is_test() { f.start_location_link(trait_.into()); - write!(f, "{}", trait_data.name.display(f.db.upcast()))?; + write!(f, "{}", trait_data.name.display(f.db.upcast(), f.edition()))?; f.end_location_link(); write!(f, "::")?; f.start_location_link(type_alias.into()); - write!(f, "{}", type_alias_data.name.display(f.db.upcast()))?; + write!(f, "{}", type_alias_data.name.display(f.db.upcast(), f.edition()))?; f.end_location_link(); // Note that the generic args for the associated type come before those for the // trait (including the self type). @@ -1124,7 +1150,7 @@ impl HirDisplay for Ty { let alias = from_foreign_def_id(*type_alias); let type_alias = db.type_alias_data(alias); f.start_location_link(alias.into()); - write!(f, "{}", type_alias.name.display(f.db.upcast()))?; + write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?; f.end_location_link(); } TyKind::OpaqueType(opaque_ty_id, parameters) => { @@ -1256,7 +1282,10 @@ impl HirDisplay for Ty { write!( f, "{}", - p.name.clone().unwrap_or_else(Name::missing).display(f.db.upcast()) + p.name + .clone() + .unwrap_or_else(Name::missing) + .display(f.db.upcast(), f.edition()) )? } TypeParamProvenance::ArgumentImplTrait => { @@ -1289,7 +1318,7 @@ impl HirDisplay for Ty { } }, TypeOrConstParamData::ConstParamData(p) => { - write!(f, "{}", p.name.display(f.db.upcast()))?; + write!(f, "{}", p.name.display(f.db.upcast(), f.edition()))?; } } } @@ -1632,7 +1661,7 @@ fn write_bounds_like_dyn_trait( // existential) here, which is the only thing that's // possible in actual Rust, and hence don't print it f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; + write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?; f.end_location_link(); if is_fn_trait { if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) { @@ -1706,7 +1735,7 @@ fn write_bounds_like_dyn_trait( let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id); let type_alias = f.db.type_alias_data(assoc_ty_id); f.start_location_link(assoc_ty_id.into()); - write!(f, "{}", type_alias.name.display(f.db.upcast()))?; + write!(f, "{}", type_alias.name.display(f.db.upcast(), f.edition()))?; f.end_location_link(); let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self(); @@ -1770,7 +1799,7 @@ fn fmt_trait_ref( } let trait_ = tr.hir_trait_id(); f.start_location_link(trait_.into()); - write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; + write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?; f.end_location_link(); let substs = tr.substitution.as_slice(Interner); hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner)) @@ -1796,7 +1825,11 @@ impl HirDisplay for WhereClause { write!(f, ">::",)?; let type_alias = from_assoc_type_id(projection_ty.associated_ty_id); f.start_location_link(type_alias.into()); - write!(f, "{}", f.db.type_alias_data(type_alias).name.display(f.db.upcast()),)?; + write!( + f, + "{}", + f.db.type_alias_data(type_alias).name.display(f.db.upcast(), f.edition()), + )?; f.end_location_link(); write!(f, " = ")?; ty.hir_fmt(f)?; @@ -1832,7 +1865,7 @@ impl HirDisplay for LifetimeData { let id = lt_from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); let param_data = &generics[id.local_id]; - write!(f, "{}", param_data.name.display(f.db.upcast()))?; + write!(f, "{}", param_data.name.display(f.db.upcast(), f.edition()))?; Ok(()) } _ if f.display_target.is_source_code() => write!(f, "'_"), @@ -1913,7 +1946,7 @@ impl HirDisplay for TypeRef { }; write!(f, "&")?; if let Some(lifetime) = lifetime { - write!(f, "{} ", lifetime.name.display(f.db.upcast()))?; + write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?; } write!(f, "{mutability}")?; inner.hir_fmt(f)?; @@ -1921,7 +1954,7 @@ impl HirDisplay for TypeRef { TypeRef::Array(inner, len) => { write!(f, "[")?; inner.hir_fmt(f)?; - write!(f, "; {}]", len.display(f.db.upcast()))?; + write!(f, "; {}]", len.display(f.db.upcast(), f.edition()))?; } TypeRef::Slice(inner) => { write!(f, "[")?; @@ -1942,7 +1975,7 @@ impl HirDisplay for TypeRef { for index in 0..function_parameters.len() { let (param_name, param_type) = &function_parameters[index]; if let Some(name) = param_name { - write!(f, "{}: ", name.display(f.db.upcast()))?; + write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?; } param_type.hir_fmt(f)?; @@ -2000,12 +2033,15 @@ impl HirDisplay for TypeBound { } path.hir_fmt(f) } - TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name.display(f.db.upcast())), + TypeBound::Lifetime(lifetime) => { + write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition())) + } TypeBound::ForLifetime(lifetimes, path) => { + let edition = f.edition(); write!( f, "for<{}> ", - lifetimes.iter().map(|it| it.display(f.db.upcast())).format(", ") + lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ") )?; path.hir_fmt(f) } @@ -2071,7 +2107,7 @@ impl HirDisplay for Path { if !matches!(self.kind(), PathKind::Plain) || seg_idx > 0 { write!(f, "::")?; } - write!(f, "{}", segment.name.display(f.db.upcast()))?; + write!(f, "{}", segment.name.display(f.db.upcast(), f.edition()))?; if let Some(generic_args) = segment.args_and_bindings { // We should be in type context, so format as `Foo` instead of `Foo::`. // Do we actually format expressions? @@ -2116,7 +2152,7 @@ impl HirDisplay for Path { } else { write!(f, ", ")?; } - write!(f, "{}", binding.name.display(f.db.upcast()))?; + write!(f, "{}", binding.name.display(f.db.upcast(), f.edition()))?; match &binding.type_ref { Some(ty) => { write!(f, " = ")?; @@ -2150,9 +2186,11 @@ impl HirDisplay for hir_def::path::GenericArg { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { match self { hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f), - hir_def::path::GenericArg::Const(c) => write!(f, "{}", c.display(f.db.upcast())), + hir_def::path::GenericArg::Const(c) => { + write!(f, "{}", c.display(f.db.upcast(), f.edition())) + } hir_def::path::GenericArg::Lifetime(lifetime) => { - write!(f, "{}", lifetime.name.display(f.db.upcast())) + write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition())) } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index 034ed2d691b4..03072790d026 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -255,7 +255,9 @@ impl CapturedItem { pub fn display_place(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String { let body = db.body(owner); - let mut result = body[self.place.local].name.display(db.upcast()).to_string(); + let krate = owner.krate(db.upcast()); + let edition = db.crate_graph()[krate].edition; + let mut result = body[self.place.local].name.display(db.upcast(), edition).to_string(); let mut field_need_paren = false; for proj in &self.place.projections { match proj { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 8cb428a610a8..f40d508f755a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -42,19 +42,20 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result, LayoutErro hir_def::ModuleDefId::AdtId(x) => { let name = match x { hir_def::AdtId::StructId(x) => { - db.struct_data(x).name.display_no_db().to_smolstr() + db.struct_data(x).name.display_no_db(file_id.edition()).to_smolstr() } hir_def::AdtId::UnionId(x) => { - db.union_data(x).name.display_no_db().to_smolstr() + db.union_data(x).name.display_no_db(file_id.edition()).to_smolstr() } hir_def::AdtId::EnumId(x) => { - db.enum_data(x).name.display_no_db().to_smolstr() + db.enum_data(x).name.display_no_db(file_id.edition()).to_smolstr() } }; (name == "Goal").then_some(Either::Left(x)) } hir_def::ModuleDefId::TypeAliasId(x) => { - let name = db.type_alias_data(x).name.display_no_db().to_smolstr(); + let name = + db.type_alias_data(x).name.display_no_db(file_id.edition()).to_smolstr(); (name == "Goal").then_some(Either::Right(x)) } _ => None, @@ -94,7 +95,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result, LayoutErro .declarations() .find_map(|x| match x { hir_def::ModuleDefId::FunctionId(x) => { - let name = db.function_data(x).name.display_no_db().to_smolstr(); + let name = db.function_data(x).name.display_no_db(file_id.edition()).to_smolstr(); (name == "main").then_some(x) } _ => None, @@ -104,7 +105,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result, LayoutErro let b = hir_body .bindings .iter() - .find(|x| x.1.name.display_no_db().to_smolstr() == "goal") + .find(|x| x.1.name.display_no_db(file_id.edition()).to_smolstr() == "goal") .unwrap() .0; let infer = db.infer(function_id.into()); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 4c9e0a1e1183..46611ae0de92 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -66,6 +66,7 @@ use intern::{sym, Symbol}; use la_arena::{Arena, Idx}; use mir::{MirEvalError, VTableMap}; use rustc_hash::{FxHashMap, FxHashSet}; +use span::Edition; use syntax::ast::{make, ConstArg}; use traits::FnTrait; use triomphe::Arc; @@ -1025,7 +1026,11 @@ where collector.placeholders.into_iter().collect() } -pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option { +pub fn known_const_to_ast( + konst: &Const, + db: &dyn HirDatabase, + edition: Edition, +) -> Option { if let ConstValue::Concrete(c) = &konst.interned().value { match c.interned { ConstScalar::UnevaluatedConst(GeneralConstId::InTypeConstId(cid), _) => { @@ -1035,5 +1040,5 @@ pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option (), } } - Some(make::expr_const_value(konst.display(db).to_string().as_str())) + Some(make::expr_const_value(konst.display(db, edition).to_string().as_str())) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 06a4236e0acd..9c727cb4ed19 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -158,7 +158,10 @@ impl ProjectionElem { subst.at(Interner, 0).assert_ty_ref(Interner).clone() } _ => { - never!("Overloaded deref on type {} is not a projection", base.display(db)); + never!( + "Overloaded deref on type {} is not a projection", + base.display(db, db.crate_graph()[krate].edition) + ); TyKind::Error.intern(Interner) } }, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index f8083e898588..590cb3952ef3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -23,7 +23,7 @@ use rustc_apfloat::{ Float, }; use rustc_hash::{FxHashMap, FxHashSet}; -use span::FileId; +use span::{Edition, FileId}; use stdx::never; use syntax::{SyntaxNodePtr, TextRange}; use triomphe::Arc; @@ -358,6 +358,7 @@ impl MirEvalError { f: &mut String, db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, + edition: Edition, ) -> std::result::Result<(), std::fmt::Error> { writeln!(f, "Mir eval error:")?; let mut err = self; @@ -370,7 +371,7 @@ impl MirEvalError { writeln!( f, "In function {} ({:?})", - function_name.name.display(db.upcast()), + function_name.name.display(db.upcast(), edition), func )?; } @@ -415,7 +416,7 @@ impl MirEvalError { write!( f, "Layout for type `{}` is not available due {err:?}", - ty.display(db).with_closure_style(ClosureStyle::ClosureWithId) + ty.display(db, edition).with_closure_style(ClosureStyle::ClosureWithId) )?; } MirEvalError::MirLowerError(func, err) => { @@ -423,16 +424,17 @@ impl MirEvalError { writeln!( f, "MIR lowering for function `{}` ({:?}) failed due:", - function_name.name.display(db.upcast()), + function_name.name.display(db.upcast(), edition), func )?; - err.pretty_print(f, db, span_formatter)?; + err.pretty_print(f, db, span_formatter, edition)?; } MirEvalError::ConstEvalError(name, err) => { MirLowerError::ConstEvalError((**name).into(), err.clone()).pretty_print( f, db, span_formatter, + edition, )?; } MirEvalError::UndefinedBehavior(_) @@ -2675,10 +2677,11 @@ impl Evaluator<'_> { let db = self.db.upcast(); let loc = variant.lookup(db); let enum_loc = loc.parent.lookup(db); + let edition = self.db.crate_graph()[self.crate_id].edition; let name = format!( "{}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), - loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition), + loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition), ); Err(MirEvalError::ConstEvalError(name, Box::new(e))) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index d76f53818716..0cdad74a4f6c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -856,7 +856,11 @@ impl Evaluator<'_> { Ok(ty_name) => ty_name, // Fallback to human readable display in case of `Err`. Ideally we want to use `display_source_code` to // render full paths. - Err(_) => ty.display(self.db).to_string(), + Err(_) => { + let krate = locals.body.owner.krate(self.db.upcast()); + let edition = self.db.crate_graph()[krate].edition; + ty.display(self.db, edition).to_string() + } }; let len = ty_name.len(); let addr = self.heap_allocate(len, 1)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index b21a401fa764..371a5278dc9a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -1,5 +1,5 @@ use hir_def::db::DefDatabase; -use span::EditionedFileId; +use span::{Edition, EditionedFileId}; use syntax::{TextRange, TextSize}; use test_fixture::WithFixture; @@ -15,7 +15,7 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), .declarations() .find_map(|x| match x { hir_def::ModuleDefId::FunctionId(x) => { - if db.function_data(x).name.display(db).to_string() == "main" { + if db.function_data(x).name.display(db, Edition::CURRENT).to_string() == "main" { Some(x) } else { None @@ -63,7 +63,7 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr let span_formatter = |file, range: TextRange| { format!("{:?} {:?}..{:?}", file, line_index(range.start()), line_index(range.end())) }; - e.pretty_print(&mut err, &db, span_formatter).unwrap(); + e.pretty_print(&mut err, &db, span_formatter, Edition::CURRENT).unwrap(); panic!("Error in interpreting: {err}"); } Ok((stdout, stderr)) => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 9aa2eeebc175..a15549f9f9ba 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -21,7 +21,7 @@ use hir_expand::name::Name; use la_arena::ArenaMap; use rustc_apfloat::Float; use rustc_hash::FxHashMap; -use span::FileId; +use span::{Edition, FileId}; use syntax::TextRange; use triomphe::Arc; @@ -157,13 +157,18 @@ impl MirLowerError { f: &mut String, db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, + edition: Edition, ) -> std::result::Result<(), std::fmt::Error> { match self { MirLowerError::ConstEvalError(name, e) => { writeln!(f, "In evaluating constant {name}")?; match &**e { - ConstEvalError::MirLowerError(e) => e.pretty_print(f, db, span_formatter)?, - ConstEvalError::MirEvalError(e) => e.pretty_print(f, db, span_formatter)?, + ConstEvalError::MirLowerError(e) => { + e.pretty_print(f, db, span_formatter, edition)? + } + ConstEvalError::MirEvalError(e) => { + e.pretty_print(f, db, span_formatter, edition)? + } } } MirLowerError::MissingFunctionDefinition(owner, it) => { @@ -171,15 +176,15 @@ impl MirLowerError { writeln!( f, "Missing function definition for {}", - body.pretty_print_expr(db.upcast(), *owner, *it) + body.pretty_print_expr(db.upcast(), *owner, *it, edition) )?; } MirLowerError::TypeMismatch(e) => match e { Some(e) => writeln!( f, "Type mismatch: Expected {}, found {}", - e.expected.display(db), - e.actual.display(db), + e.expected.display(db, edition), + e.actual.display(db, edition), )?, None => writeln!(f, "Type mismatch: types mismatch with {{unknown}}",)?, }, @@ -189,11 +194,11 @@ impl MirLowerError { writeln!( f, "Generic arg not provided for {}", - param.name().unwrap_or(&Name::missing()).display(db.upcast()) + param.name().unwrap_or(&Name::missing()).display(db.upcast(), edition) )?; writeln!(f, "Provided args: [")?; for g in subst.iter(Interner) { - write!(f, " {},", g.display(db))?; + write!(f, " {},", g.display(db, edition))?; } writeln!(f, "]")?; } @@ -242,8 +247,8 @@ impl From for MirLowerError { } impl MirLowerError { - fn unresolved_path(db: &dyn HirDatabase, p: &Path) -> Self { - Self::UnresolvedName(p.display(db).to_string()) + fn unresolved_path(db: &dyn HirDatabase, p: &Path, edition: Edition) -> Self { + Self::UnresolvedName(p.display(db, edition).to_string()) } } @@ -436,7 +441,8 @@ impl<'ctx> MirLowerCtx<'ctx> { VariantId::UnionId(_) => implementation_error!("Union variant as path"), } } else { - let unresolved_name = || MirLowerError::unresolved_path(self.db, p); + let unresolved_name = + || MirLowerError::unresolved_path(self.db, p, self.edition()); let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); resolver .resolve_path_in_value_ns_fully(self.db.upcast(), p) @@ -662,7 +668,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let (func_id, generic_args) = self.infer.method_resolution(expr_id).ok_or_else(|| { MirLowerError::UnresolvedMethod( - method_name.display(self.db.upcast()).to_string(), + method_name.display(self.db.upcast(), self.edition()).to_string(), ) })?; let func = Operand::from_fn(self.db, func_id, generic_args); @@ -803,7 +809,9 @@ impl<'ctx> MirLowerCtx<'ctx> { }; let variant_id = self.infer.variant_resolution_for_expr(expr_id).ok_or_else(|| match path { - Some(p) => MirLowerError::UnresolvedName(p.display(self.db).to_string()), + Some(p) => MirLowerError::UnresolvedName( + p.display(self.db, self.edition()).to_string(), + ), None => MirLowerError::RecordLiteralWithoutPath, })?; let subst = match self.expr_ty_without_adjust(expr_id).kind(Interner) { @@ -1378,7 +1386,9 @@ impl<'ctx> MirLowerCtx<'ctx> { "only `char` and numeric types are allowed in range patterns" ), }; - let unresolved_name = || MirLowerError::unresolved_path(self.db, c.as_ref()); + let edition = self.edition(); + let unresolved_name = + || MirLowerError::unresolved_path(self.db, c.as_ref(), edition); let resolver = self.owner.resolver(self.db.upcast()); let pr = resolver .resolve_path_in_value_ns(self.db.upcast(), c.as_ref()) @@ -1904,19 +1914,25 @@ impl<'ctx> MirLowerCtx<'ctx> { match r { Ok(r) => Ok(r), Err(e) => { + let edition = self.edition(); let db = self.db.upcast(); let loc = variant.lookup(db); let enum_loc = loc.parent.lookup(db); let name = format!( "{}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast()), - loc.id.item_tree(db)[loc.id.value].name.display(db.upcast()), + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition), + loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition), ); Err(MirLowerError::ConstEvalError(name.into(), Box::new(e))) } } } + fn edition(&self) -> Edition { + let krate = self.owner.krate(self.db.upcast()); + self.db.crate_graph()[krate].edition + } + fn drop_until_scope( &mut self, scope_index: usize, @@ -2121,18 +2137,24 @@ pub fn mir_body_for_closure_query( } pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result> { + let krate = def.krate(db.upcast()); + let edition = db.crate_graph()[krate].edition; let detail = match def { - DefWithBodyId::FunctionId(it) => db.function_data(it).name.display(db.upcast()).to_string(), - DefWithBodyId::StaticId(it) => db.static_data(it).name.display(db.upcast()).to_string(), + DefWithBodyId::FunctionId(it) => { + db.function_data(it).name.display(db.upcast(), edition).to_string() + } + DefWithBodyId::StaticId(it) => { + db.static_data(it).name.display(db.upcast(), edition).to_string() + } DefWithBodyId::ConstId(it) => db .const_data(it) .name .clone() .unwrap_or_else(Name::missing) - .display(db.upcast()) + .display(db.upcast(), edition) .to_string(), DefWithBodyId::VariantId(it) => { - db.enum_variant_data(it).name.display(db.upcast()).to_string() + db.enum_variant_data(it).name.display(db.upcast(), edition).to_string() } DefWithBodyId::InTypeConstId(it) => format!("in type const {it:?}"), }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index 34e0f30afb7f..b1c0d1f2b390 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -347,7 +347,8 @@ impl MirLowerCtx<'_> { // A const don't bind anything. Only needs check. return Ok((current, current_else)); } - let unresolved_name = || MirLowerError::unresolved_path(self.db, p); + let unresolved_name = + || MirLowerError::unresolved_path(self.db, p, self.edition()); let resolver = self.owner.resolver(self.db.upcast()); let pr = resolver .resolve_path_in_value_ns(self.db.upcast(), p) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index 0c641d7c6c2b..df56071aa9af 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -9,6 +9,7 @@ use either::Either; use hir_def::{body::Body, hir::BindingId}; use hir_expand::{name::Name, Lookup}; use la_arena::ArenaMap; +use span::Edition; use crate::{ db::HirDatabase, @@ -44,18 +45,21 @@ impl MirBody { ctx.for_body(|this| match ctx.body.owner { hir_def::DefWithBodyId::FunctionId(id) => { let data = db.function_data(id); - w!(this, "fn {}() ", data.name.display(db.upcast())); + w!(this, "fn {}() ", data.name.display(db.upcast(), Edition::LATEST)); } hir_def::DefWithBodyId::StaticId(id) => { let data = db.static_data(id); - w!(this, "static {}: _ = ", data.name.display(db.upcast())); + w!(this, "static {}: _ = ", data.name.display(db.upcast(), Edition::LATEST)); } hir_def::DefWithBodyId::ConstId(id) => { let data = db.const_data(id); w!( this, "const {}: _ = ", - data.name.as_ref().unwrap_or(&Name::missing()).display(db.upcast()) + data.name + .as_ref() + .unwrap_or(&Name::missing()) + .display(db.upcast(), Edition::LATEST) ); } hir_def::DefWithBodyId::VariantId(id) => { @@ -64,8 +68,12 @@ impl MirBody { w!( this, "enum {}::{} = ", - enum_loc.id.item_tree(db.upcast())[enum_loc.id.value].name.display(db.upcast()), - loc.id.item_tree(db.upcast())[loc.id.value].name.display(db.upcast()), + enum_loc.id.item_tree(db.upcast())[enum_loc.id.value] + .name + .display(db.upcast(), Edition::LATEST), + loc.id.item_tree(db.upcast())[loc.id.value] + .name + .display(db.upcast(), Edition::LATEST), ) } hir_def::DefWithBodyId::InTypeConstId(id) => { @@ -122,7 +130,7 @@ impl HirDisplay for LocalName { match self { LocalName::Unknown(l) => write!(f, "_{}", u32::from(l.into_raw())), LocalName::Binding(n, l) => { - write!(f, "{}_{}", n.display(f.db.upcast()), u32::from(l.into_raw())) + write!(f, "{}_{}", n.display(f.db.upcast(), f.edition()), u32::from(l.into_raw())) } } } @@ -200,7 +208,7 @@ impl<'a> MirPrettyCtx<'a> { wln!( self, "let {}: {};", - self.local_name(id).display(self.db), + self.local_name(id).display_test(self.db), self.hir_display(&local.ty) ); } @@ -231,10 +239,18 @@ impl<'a> MirPrettyCtx<'a> { wln!(this, ";"); } StatementKind::StorageDead(p) => { - wln!(this, "StorageDead({})", this.local_name(*p).display(self.db)); + wln!( + this, + "StorageDead({})", + this.local_name(*p).display_test(self.db) + ); } StatementKind::StorageLive(p) => { - wln!(this, "StorageLive({})", this.local_name(*p).display(self.db)); + wln!( + this, + "StorageLive({})", + this.local_name(*p).display_test(self.db) + ); } StatementKind::Deinit(p) => { w!(this, "Deinit("); @@ -297,7 +313,7 @@ impl<'a> MirPrettyCtx<'a> { fn f(this: &mut MirPrettyCtx<'_>, local: LocalId, projections: &[PlaceElem]) { let Some((last, head)) = projections.split_last() else { // no projection - w!(this, "{}", this.local_name(local).display(this.db)); + w!(this, "{}", this.local_name(local).display_test(this.db)); return; }; match last { @@ -317,13 +333,13 @@ impl<'a> MirPrettyCtx<'a> { w!( this, " as {}).{}", - variant_name.display(this.db.upcast()), - name.display(this.db.upcast()) + variant_name.display(this.db.upcast(), Edition::LATEST), + name.display(this.db.upcast(), Edition::LATEST) ); } hir_def::VariantId::StructId(_) | hir_def::VariantId::UnionId(_) => { f(this, local, head); - w!(this, ".{}", name.display(this.db.upcast())); + w!(this, ".{}", name.display(this.db.upcast(), Edition::LATEST)); } } } @@ -337,7 +353,7 @@ impl<'a> MirPrettyCtx<'a> { } ProjectionElem::Index(l) => { f(this, local, head); - w!(this, "[{}]", this.local_name(*l).display(this.db)); + w!(this, "[{}]", this.local_name(*l).display_test(this.db)); } it => { f(this, local, head); @@ -387,7 +403,7 @@ impl<'a> MirPrettyCtx<'a> { Rvalue::Repeat(op, len) => { w!(self, "["); self.operand(op); - w!(self, "; {}]", len.display(self.db)); + w!(self, "; {}]", len.display_test(self.db)); } Rvalue::Aggregate(AggregateKind::Adt(_, _), it) => { w!(self, "Adt("); @@ -458,6 +474,6 @@ impl<'a> MirPrettyCtx<'a> { } fn hir_display(&self, ty: &'a T) -> impl Display + 'a { - ty.display(self.db).with_closure_style(ClosureStyle::ClosureWithSubst) + ty.display_test(self.db).with_closure_style(ClosureStyle::ClosureWithSubst) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs index db5fa3205778..6cb59491fac8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs @@ -2,6 +2,7 @@ use std::fmt::{self, Display}; use itertools::Itertools; +use span::Edition; use crate::{ chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk, @@ -24,7 +25,7 @@ impl DebugContext<'_> { AdtId::UnionId(it) => self.0.union_data(it).name.clone(), AdtId::EnumId(it) => self.0.enum_data(it).name.clone(), }; - name.display(self.0.upcast()).fmt(f)?; + name.display(self.0.upcast(), Edition::LATEST).fmt(f)?; Ok(()) } @@ -35,7 +36,7 @@ impl DebugContext<'_> { ) -> Result<(), fmt::Error> { let trait_: hir_def::TraitId = from_chalk_trait_id(id); let trait_data = self.0.trait_data(trait_); - trait_data.name.display(self.0.upcast()).fmt(f)?; + trait_data.name.display(self.0.upcast(), Edition::LATEST).fmt(f)?; Ok(()) } @@ -54,8 +55,8 @@ impl DebugContext<'_> { write!( fmt, "{}::{}", - trait_data.name.display(self.0.upcast()), - type_alias_data.name.display(self.0.upcast()) + trait_data.name.display(self.0.upcast(), Edition::LATEST), + type_alias_data.name.display(self.0.upcast(), Edition::LATEST) )?; Ok(()) } @@ -75,7 +76,7 @@ impl DebugContext<'_> { let trait_ref = projection_ty.trait_ref(self.0); let trait_params = trait_ref.substitution.as_slice(Interner); let self_ty = trait_ref.self_type_parameter(Interner); - write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0.upcast()))?; + write!(fmt, "<{self_ty:?} as {}", trait_name.display(self.0.upcast(), Edition::LATEST))?; if trait_params.len() > 1 { write!( fmt, @@ -83,7 +84,7 @@ impl DebugContext<'_> { trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{x:?}"))), )?; } - write!(fmt, ">::{}", type_alias_data.name.display(self.0.upcast()))?; + write!(fmt, ">::{}", type_alias_data.name.display(self.0.upcast(), Edition::LATEST))?; let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len(); let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count]; @@ -110,9 +111,11 @@ impl DebugContext<'_> { CallableDefId::EnumVariantId(e) => self.0.enum_variant_data(e).name.clone(), }; match def { - CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name.display(self.0.upcast())), + CallableDefId::FunctionId(_) => { + write!(fmt, "{{fn {}}}", name.display(self.0.upcast(), Edition::LATEST)) + } CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => { - write!(fmt, "{{ctor {}}}", name.display(self.0.upcast())) + write!(fmt, "{{ctor {}}}", name.display(self.0.upcast(), Edition::LATEST)) } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 00791c51491d..51ccd4ef293f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -14,6 +14,7 @@ use hir_def::{ }; use hir_expand::name::Name; use intern::sym; +use span::Edition; use stdx::{never, panic_context}; use triomphe::Arc; @@ -114,7 +115,7 @@ pub(crate) fn trait_solve_query( ) -> Option { let detail = match &goal.value.goal.data(Interner) { GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => { - db.trait_data(it.hir_trait_id()).name.display(db.upcast()).to_string() + db.trait_data(it.hir_trait_id()).name.display(db.upcast(), Edition::LATEST).to_string() } GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(), _ => "??".to_owned(), diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index 02d92620e05b..af60c233e551 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -328,11 +328,9 @@ fn doc_modpath_from_str(link: &str) -> Option { }; let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() { Ok(idx) => Name::new_tuple_field(idx), - Err(_) => Name::new( - segment.split_once('<').map_or(segment, |it| it.0), - tt::IdentIsRaw::No, - SyntaxContextId::ROOT, - ), + Err(_) => { + Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT) + } }); Some(ModPath::from_segments(kind, parts)) }; diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 12dd8b5bf4f5..923dca646673 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -84,7 +84,7 @@ impl HirDisplay for Function { if let Some(abi) = &data.abi { write!(f, "extern \"{}\" ", abi.as_str())?; } - write!(f, "fn {}", data.name.display(f.db.upcast()))?; + write!(f, "fn {}", data.name.display(f.db.upcast(), f.edition()))?; write_generic_params(GenericDefId::FunctionId(self.id), f)?; @@ -107,7 +107,7 @@ impl HirDisplay for Function { first = false; } match local { - Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?, + Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?, None => f.write_str("_: ")?, } type_ref.hir_fmt(f)?; @@ -177,7 +177,7 @@ fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDi if let Some(trait_) = impl_.trait_(db) { let trait_data = db.trait_data(trait_.id); - write!(f, " {} for", trait_data.name.display(db.upcast()))?; + write!(f, " {} for", trait_data.name.display(db.upcast(), f.edition()))?; } f.write_char(' ')?; @@ -196,7 +196,7 @@ impl HirDisplay for SelfParam { { f.write_char('&')?; if let Some(lifetime) = lifetime { - write!(f, "{} ", lifetime.name.display(f.db.upcast()))?; + write!(f, "{} ", lifetime.name.display(f.db.upcast(), f.edition()))?; } if let hir_def::type_ref::Mutability::Mut = mut_ { f.write_str("mut ")?; @@ -227,7 +227,7 @@ impl HirDisplay for Struct { // FIXME: Render repr if its set explicitly? write_visibility(module_id, self.visibility(f.db), f)?; f.write_str("struct ")?; - write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?; let def_id = GenericDefId::AdtId(AdtId::StructId(self.id)); write_generic_params(def_id, f)?; @@ -266,7 +266,7 @@ impl HirDisplay for Enum { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("enum ")?; - write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?; let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id)); write_generic_params(def_id, f)?; @@ -283,7 +283,7 @@ impl HirDisplay for Union { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("union ")?; - write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?; let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id)); write_generic_params(def_id, f)?; @@ -343,7 +343,7 @@ fn write_variants( } else { f.write_str("{\n")?; for variant in &variants[..count] { - write!(f, " {}", variant.name(f.db).display(f.db.upcast()))?; + write!(f, " {}", variant.name(f.db).display(f.db.upcast(), f.edition()))?; match variant.kind(f.db) { StructKind::Tuple => { let fields_str = @@ -372,21 +372,21 @@ fn write_variants( impl HirDisplay for Field { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?; - write!(f, "{}: ", self.name(f.db).display(f.db.upcast()))?; + write!(f, "{}: ", self.name(f.db).display(f.db.upcast(), f.edition()))?; self.ty(f.db).hir_fmt(f) } } impl HirDisplay for TupleField { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "pub {}: ", self.name().display(f.db.upcast()))?; + write!(f, "pub {}: ", self.name().display(f.db.upcast(), f.edition()))?; self.ty(f.db).hir_fmt(f) } } impl HirDisplay for Variant { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?; let data = self.variant_data(f.db); match &*data { VariantData::Unit => {} @@ -424,9 +424,9 @@ impl HirDisplay for ExternCrateDecl { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; f.write_str("extern crate ")?; - write!(f, "{}", self.name(f.db).display(f.db.upcast()))?; + write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition()))?; if let Some(alias) = self.alias(f.db) { - write!(f, " as {alias}",)?; + write!(f, " as {}", alias.display(f.edition()))?; } Ok(()) } @@ -478,7 +478,7 @@ impl HirDisplay for TypeParam { match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { - write!(f, "{}", p.name.clone().unwrap().display(f.db.upcast()))? + write!(f, "{}", p.name.clone().unwrap().display(f.db.upcast(), f.edition()))? } TypeParamProvenance::ArgumentImplTrait => { return write_bounds_like_dyn_trait_with_prefix( @@ -491,7 +491,7 @@ impl HirDisplay for TypeParam { } }, TypeOrConstParamData::ConstParamData(p) => { - write!(f, "{}", p.name.display(f.db.upcast()))?; + write!(f, "{}", p.name.display(f.db.upcast(), f.edition()))?; } } @@ -525,13 +525,13 @@ impl HirDisplay for TypeParam { impl HirDisplay for LifetimeParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "{}", self.name(f.db).display(f.db.upcast())) + write!(f, "{}", self.name(f.db).display(f.db.upcast(), f.edition())) } } impl HirDisplay for ConstParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write!(f, "const {}: ", self.name(f.db).display(f.db.upcast()))?; + write!(f, "const {}: ", self.name(f.db).display(f.db.upcast(), f.edition()))?; self.ty(f.db).hir_fmt(f) } } @@ -563,7 +563,7 @@ fn write_generic_params( }; for (_, lifetime) in params.iter_lt() { delim(f)?; - write!(f, "{}", lifetime.name.display(f.db.upcast()))?; + write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition()))?; } for (_, ty) in params.iter_type_or_consts() { if let Some(name) = &ty.name() { @@ -573,7 +573,7 @@ fn write_generic_params( continue; } delim(f)?; - write!(f, "{}", name.display(f.db.upcast()))?; + write!(f, "{}", name.display(f.db.upcast(), f.edition()))?; if let Some(default) = &ty.default { f.write_str(" = ")?; default.hir_fmt(f)?; @@ -581,12 +581,12 @@ fn write_generic_params( } TypeOrConstParamData::ConstParamData(c) => { delim(f)?; - write!(f, "const {}: ", name.display(f.db.upcast()))?; + write!(f, "const {}: ", name.display(f.db.upcast(), f.edition()))?; c.ty.hir_fmt(f)?; if let Some(default) = &c.default { f.write_str(" = ")?; - write!(f, "{}", default.display(f.db.upcast()))?; + write!(f, "{}", default.display(f.db.upcast(), f.edition()))?; } } } @@ -639,7 +639,7 @@ fn write_where_predicates( let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), WherePredicateTypeTarget::TypeOrConstParam(id) => match params[*id].name() { - Some(name) => write!(f, "{}", name.display(f.db.upcast())), + Some(name) => write!(f, "{}", name.display(f.db.upcast(), f.edition())), None => f.write_str("{unnamed}"), }, }; @@ -668,12 +668,13 @@ fn write_where_predicates( bound.hir_fmt(f)?; } Lifetime { target, bound } => { - let target = target.name.display(f.db.upcast()); - let bound = bound.name.display(f.db.upcast()); + let target = target.name.display(f.db.upcast(), f.edition()); + let bound = bound.name.display(f.db.upcast(), f.edition()); write!(f, "{target}: {bound}")?; } ForLifetime { lifetimes, target, bound } => { - let lifetimes = lifetimes.iter().map(|it| it.display(f.db.upcast())).join(", "); + let lifetimes = + lifetimes.iter().map(|it| it.display(f.db.upcast(), f.edition())).join(", "); write!(f, "for<{lifetimes}> ")?; write_target(target, f)?; f.write_str(": ")?; @@ -685,7 +686,9 @@ fn write_where_predicates( f.write_str(" + ")?; match nxt { TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?, - Lifetime { bound, .. } => write!(f, "{}", bound.name.display(f.db.upcast()))?, + Lifetime { bound, .. } => { + write!(f, "{}", bound.name.display(f.db.upcast(), f.edition()))? + } } } f.write_str(",")?; @@ -707,7 +710,7 @@ impl HirDisplay for Const { let data = db.const_data(self.id); f.write_str("const ")?; match &data.name { - Some(name) => write!(f, "{}: ", name.display(f.db.upcast()))?, + Some(name) => write!(f, "{}: ", name.display(f.db.upcast(), f.edition()))?, None => f.write_str("_: ")?, } data.type_ref.hir_fmt(f)?; @@ -723,7 +726,7 @@ impl HirDisplay for Static { if data.mutable { f.write_str("mut ")?; } - write!(f, "{}: ", data.name.display(f.db.upcast()))?; + write!(f, "{}: ", data.name.display(f.db.upcast(), f.edition()))?; data.type_ref.hir_fmt(f)?; Ok(()) } @@ -777,7 +780,7 @@ fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), Hi if data.is_auto { f.write_str("auto ")?; } - write!(f, "trait {}", data.name.display(f.db.upcast()))?; + write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?; write_generic_params(GenericDefId::TraitId(trait_.id), f)?; Ok(()) } @@ -786,7 +789,7 @@ impl HirDisplay for TraitAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; let data = f.db.trait_alias_data(self.id); - write!(f, "trait {}", data.name.display(f.db.upcast()))?; + write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?; let def_id = GenericDefId::TraitAliasId(self.id); write_generic_params(def_id, f)?; f.write_str(" = ")?; @@ -802,7 +805,7 @@ impl HirDisplay for TypeAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; let data = f.db.type_alias_data(self.id); - write!(f, "type {}", data.name.display(f.db.upcast()))?; + write!(f, "type {}", data.name.display(f.db.upcast(), f.edition()))?; let def_id = GenericDefId::TypeAliasId(self.id); write_generic_params(def_id, f)?; if !data.bounds.is_empty() { @@ -822,7 +825,7 @@ impl HirDisplay for Module { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { // FIXME: Module doesn't have visibility saved in data. match self.name(f.db) { - Some(name) => write!(f, "mod {}", name.display(f.db.upcast())), + Some(name) => write!(f, "mod {}", name.display(f.db.upcast(), f.edition())), None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) { Some(name) => write!(f, "extern crate {name}"), None => f.write_str("extern crate {unknown}"), @@ -839,6 +842,6 @@ impl HirDisplay for Macro { hir_def::MacroId::MacroRulesId(_) => f.write_str("macro_rules!"), hir_def::MacroId::ProcMacroId(_) => f.write_str("proc_macro"), }?; - write!(f, " {}", self.name(f.db).display(f.db.upcast())) + write!(f, " {}", self.name(f.db).display(f.db.upcast(), f.edition())) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 1a3becdf50e9..57f810c7c79c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -340,13 +340,13 @@ impl ModuleDef { } } - pub fn canonical_path(&self, db: &dyn HirDatabase) -> Option { + pub fn canonical_path(&self, db: &dyn HirDatabase, edition: Edition) -> Option { let mut segments = vec![self.name(db)?]; for m in self.module(db)?.path_to_root(db) { segments.extend(m.name(db)) } segments.reverse(); - Some(segments.iter().map(|it| it.display(db.upcast())).join("::")) + Some(segments.iter().map(|it| it.display(db.upcast(), edition)).join("::")) } pub fn canonical_module_path( @@ -556,13 +556,14 @@ impl Module { style_lints: bool, ) { let _p = tracing::info_span!("Module::diagnostics", name = ?self.name(db)).entered(); + let edition = db.crate_graph()[self.id.krate()].edition; let def_map = self.id.def_map(db.upcast()); for diag in def_map.diagnostics() { if diag.in_module != self.id.local_id { // FIXME: This is accidentally quadratic. continue; } - emit_def_diagnostic(db, acc, diag); + emit_def_diagnostic(db, acc, diag, edition); } if !self.id.is_block_module() { @@ -582,7 +583,7 @@ impl Module { } ModuleDef::Trait(t) => { for diag in db.trait_data_with_diagnostics(t.id).1.iter() { - emit_def_diagnostic(db, acc, diag); + emit_def_diagnostic(db, acc, diag, edition); } for item in t.items(db) { @@ -599,19 +600,19 @@ impl Module { match adt { Adt::Struct(s) => { for diag in db.struct_data_with_diagnostics(s.id).1.iter() { - emit_def_diagnostic(db, acc, diag); + emit_def_diagnostic(db, acc, diag, edition); } } Adt::Union(u) => { for diag in db.union_data_with_diagnostics(u.id).1.iter() { - emit_def_diagnostic(db, acc, diag); + emit_def_diagnostic(db, acc, diag, edition); } } Adt::Enum(e) => { for v in e.variants(db) { acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints)); for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { - emit_def_diagnostic(db, acc, diag); + emit_def_diagnostic(db, acc, diag, edition); } } } @@ -645,7 +646,7 @@ impl Module { let ast_id_map = db.ast_id_map(file_id); for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() { - emit_def_diagnostic(db, acc, diag); + emit_def_diagnostic(db, acc, diag, edition); } if inherent_impls.invalid_impls().contains(&impl_def.id) { @@ -869,23 +870,32 @@ fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec never!("declarative expander for non decl-macro: {:?}", e); return; }; + let krate = HasModule::krate(&m.id, db.upcast()); + let edition = db.crate_graph()[krate].edition; emit_def_diagnostic_( db, acc, &DefDiagnosticKind::MacroDefError { ast, message: e.to_string() }, + edition, ); } } } -fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec, diag: &DefDiagnostic) { - emit_def_diagnostic_(db, acc, &diag.kind) +fn emit_def_diagnostic( + db: &dyn HirDatabase, + acc: &mut Vec, + diag: &DefDiagnostic, + edition: Edition, +) { + emit_def_diagnostic_(db, acc, &diag.kind, edition) } fn emit_def_diagnostic_( db: &dyn HirDatabase, acc: &mut Vec, diag: &DefDiagnosticKind, + edition: Edition, ) { match diag { DefDiagnosticKind::UnresolvedModule { ast: declaration, candidates } => { @@ -910,7 +920,7 @@ fn emit_def_diagnostic_( MacroError { node: InFile::new(ast.file_id, item.syntax_node_ptr()), precise_location: None, - message: format!("{}: {message}", path.display(db.upcast())), + message: format!("{}: {message}", path.display(db.upcast(), edition)), error, } .into(), @@ -1764,7 +1774,7 @@ impl DefWithBody { /// A textual representation of the HIR of this def's body for debugging purposes. pub fn debug_hir(self, db: &dyn HirDatabase) -> String { let body = db.body(self.id()); - body.pretty_print(db.upcast(), self.id()) + body.pretty_print(db.upcast(), self.id(), Edition::CURRENT) } /// A textual representation of the MIR of this def's body for debugging purposes. @@ -2259,6 +2269,8 @@ impl Function { db: &dyn HirDatabase, span_formatter: impl Fn(FileId, TextRange) -> String, ) -> String { + let krate = HasModule::krate(&self.id, db.upcast()); + let edition = db.crate_graph()[krate].edition; let body = match db.monomorphized_mir_body( self.id.into(), Substitution::empty(Interner), @@ -2267,7 +2279,7 @@ impl Function { Ok(body) => body, Err(e) => { let mut r = String::new(); - _ = e.pretty_print(&mut r, db, &span_formatter); + _ = e.pretty_print(&mut r, db, &span_formatter, edition); return r; } }; @@ -2276,7 +2288,7 @@ impl Function { Ok(_) => "pass".to_owned(), Err(e) => { let mut r = String::new(); - _ = e.pretty_print(&mut r, db, &span_formatter); + _ = e.pretty_print(&mut r, db, &span_formatter, edition); r } }; @@ -2510,7 +2522,11 @@ impl Const { Type::from_value_def(db, self.id) } - pub fn render_eval(self, db: &dyn HirDatabase) -> Result { + pub fn render_eval( + self, + db: &dyn HirDatabase, + edition: Edition, + ) -> Result { let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?; let data = &c.data(Interner); if let TyKind::Scalar(s) = data.ty.kind(Interner) { @@ -2532,7 +2548,7 @@ impl Const { if let Ok(s) = mir::render_const_using_debug_impl(db, self.id, &c) { Ok(s) } else { - Ok(format!("{}", c.display(db))) + Ok(format!("{}", c.display(db, edition))) } } } @@ -3728,9 +3744,9 @@ impl ConstParam { Type::new(db, self.id.parent(), db.const_param_ty(self.id)) } - pub fn default(self, db: &dyn HirDatabase) -> Option { + pub fn default(self, db: &dyn HirDatabase, edition: Edition) -> Option { let arg = generic_arg_from_param(db, self.id.into())?; - known_const_to_ast(arg.constant(Interner)?, db) + known_const_to_ast(arg.constant(Interner)?, db, edition) } } @@ -4038,12 +4054,20 @@ impl Closure { TyKind::Closure(self.id, self.subst).intern(Interner) } - pub fn display_with_id(&self, db: &dyn HirDatabase) -> String { - self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ClosureWithId).to_string() + pub fn display_with_id(&self, db: &dyn HirDatabase, edition: Edition) -> String { + self.clone() + .as_ty() + .display(db, edition) + .with_closure_style(ClosureStyle::ClosureWithId) + .to_string() } - pub fn display_with_impl(&self, db: &dyn HirDatabase) -> String { - self.clone().as_ty().display(db).with_closure_style(ClosureStyle::ImplFn).to_string() + pub fn display_with_impl(&self, db: &dyn HirDatabase, edition: Edition) -> String { + self.clone() + .as_ty() + .display(db, edition) + .with_closure_style(ClosureStyle::ImplFn) + .to_string() } pub fn captured_items(&self, db: &dyn HirDatabase) -> Vec { @@ -4704,18 +4728,20 @@ impl Type { pub fn type_and_const_arguments<'a>( &'a self, db: &'a dyn HirDatabase, + edition: Edition, ) -> impl Iterator + 'a { self.ty .strip_references() .as_adt() .into_iter() .flat_map(|(_, substs)| substs.iter(Interner)) - .filter_map(|arg| { + .filter_map(move |arg| { // arg can be either a `Ty` or `constant` if let Some(ty) = arg.ty(Interner) { - Some(format_smolstr!("{}", ty.display(db))) + Some(format_smolstr!("{}", ty.display(db, edition))) } else { - arg.constant(Interner).map(|const_| format_smolstr!("{}", const_.display(db))) + arg.constant(Interner) + .map(|const_| format_smolstr!("{}", const_.display(db, edition))) } }) } @@ -4724,13 +4750,17 @@ impl Type { pub fn generic_parameters<'a>( &'a self, db: &'a dyn HirDatabase, + edition: Edition, ) -> impl Iterator + 'a { // iterate the lifetime self.as_adt() - .and_then(|a| a.lifetime(db).map(|lt| lt.name.display_no_db().to_smolstr())) + .and_then(|a| { + // Lifetimes do not need edition-specific handling as they cannot be escaped. + a.lifetime(db).map(|lt| lt.name.display_no_db(Edition::Edition2015).to_smolstr()) + }) .into_iter() // add the type and const parameters - .chain(self.type_and_const_arguments(db)) + .chain(self.type_and_const_arguments(db, edition)) } pub fn iterate_method_candidates_with_traits( diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index b1f5df681f2c..cabb7e3db3d9 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -9,6 +9,7 @@ use hir_def::{ }; use hir_expand::HirFileId; use hir_ty::{db::HirDatabase, display::HirDisplay}; +use span::Edition; use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr}; use crate::{Module, ModuleDef, Semantics}; @@ -54,6 +55,7 @@ pub struct SymbolCollector<'a> { symbols: Vec, work: Vec, current_container_name: Option, + edition: Edition, } /// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect @@ -65,10 +67,13 @@ impl<'a> SymbolCollector<'a> { symbols: Default::default(), work: Default::default(), current_container_name: None, + edition: Edition::Edition2015, } } pub fn collect(&mut self, module: Module) { + self.edition = module.krate().edition(self.db); + // The initial work is the root module we're collecting, additional work will // be populated as we traverse the module's definitions. self.work.push(SymbolCollectorWork { module_id: module.into(), parent: None }); @@ -209,7 +214,8 @@ impl<'a> SymbolCollector<'a> { fn collect_from_impl(&mut self, impl_id: ImplId) { let impl_data = self.db.impl_data(impl_id); - let impl_name = Some(SmolStr::new(impl_data.self_ty.display(self.db).to_string())); + let impl_name = + Some(SmolStr::new(impl_data.self_ty.display(self.db, self.edition).to_string())); self.with_container_name(impl_name, |s| { for &assoc_item_id in impl_data.items.iter() { s.push_assoc_item(assoc_item_id) @@ -239,16 +245,16 @@ impl<'a> SymbolCollector<'a> { fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option { match body_id { DefWithBodyId::FunctionId(id) => { - Some(self.db.function_data(id).name.display_no_db().to_smolstr()) + Some(self.db.function_data(id).name.display_no_db(self.edition).to_smolstr()) } DefWithBodyId::StaticId(id) => { - Some(self.db.static_data(id).name.display_no_db().to_smolstr()) + Some(self.db.static_data(id).name.display_no_db(self.edition).to_smolstr()) } DefWithBodyId::ConstId(id) => { - Some(self.db.const_data(id).name.as_ref()?.display_no_db().to_smolstr()) + Some(self.db.const_data(id).name.as_ref()?.display_no_db(self.edition).to_smolstr()) } DefWithBodyId::VariantId(id) => { - Some(self.db.enum_variant_data(id).name.display_no_db().to_smolstr()) + Some(self.db.enum_variant_data(id).name.display_no_db(self.edition).to_smolstr()) } DefWithBodyId::InTypeConstId(_) => Some("in type const".into()), } diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs index 0c8f6932c717..6ad074e8e5c8 100644 --- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs +++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs @@ -7,6 +7,7 @@ use hir_ty::{ display::{DisplaySourceCodeError, HirDisplay}, }; use itertools::Itertools; +use span::Edition; use crate::{ Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, Local, ModuleDef, @@ -29,9 +30,10 @@ fn mod_item_path_str( sema_scope: &SemanticsScope<'_>, def: &ModuleDef, cfg: ImportPathConfig, + edition: Edition, ) -> Result { let path = mod_item_path(sema_scope, def, cfg); - path.map(|it| it.display(sema_scope.db.upcast()).to_string()) + path.map(|it| it.display(sema_scope.db.upcast(), edition).to_string()) .ok_or(DisplaySourceCodeError::PathNotFound) } @@ -97,37 +99,38 @@ impl Expr { sema_scope: &SemanticsScope<'_>, many_formatter: &mut dyn FnMut(&Type) -> String, cfg: ImportPathConfig, + edition: Edition, ) -> Result { let db = sema_scope.db; - let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg); + let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg, edition); match self { Expr::Const(it) => match it.as_assoc_item(db).map(|it| it.container(db)) { Some(container) => { - let container_name = container_name(container, sema_scope, cfg)?; + let container_name = container_name(container, sema_scope, cfg, edition)?; let const_name = it .name(db) - .map(|c| c.display(db.upcast()).to_string()) + .map(|c| c.display(db.upcast(), edition).to_string()) .unwrap_or(String::new()); Ok(format!("{container_name}::{const_name}")) } None => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)), }, Expr::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)), - Expr::Local(it) => Ok(it.name(db).display(db.upcast()).to_string()), - Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast()).to_string()), + Expr::Local(it) => Ok(it.name(db).display(db.upcast(), edition).to_string()), + Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast(), edition).to_string()), Expr::FamousType { value, .. } => Ok(value.to_string()), Expr::Function { func, params, .. } => { let args = params .iter() - .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg)) + .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition)) .collect::, DisplaySourceCodeError>>()? .into_iter() .join(", "); match func.as_assoc_item(db).map(|it| it.container(db)) { Some(container) => { - let container_name = container_name(container, sema_scope, cfg)?; - let fn_name = func.name(db).display(db.upcast()).to_string(); + let container_name = container_name(container, sema_scope, cfg, edition)?; + let fn_name = func.name(db).display(db.upcast(), edition).to_string(); Ok(format!("{container_name}::{fn_name}({args})")) } None => { @@ -141,12 +144,13 @@ impl Expr { return Ok(many_formatter(&target.ty(db))); } - let func_name = func.name(db).display(db.upcast()).to_string(); + let func_name = func.name(db).display(db.upcast(), edition).to_string(); let self_param = func.self_param(db).unwrap(); - let target_str = target.gen_source_code(sema_scope, many_formatter, cfg)?; + let target_str = + target.gen_source_code(sema_scope, many_formatter, cfg, edition)?; let args = params .iter() - .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg)) + .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition)) .collect::, DisplaySourceCodeError>>()? .into_iter() .join(", "); @@ -176,7 +180,7 @@ impl Expr { StructKind::Tuple => { let args = params .iter() - .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg)) + .map(|f| f.gen_source_code(sema_scope, many_formatter, cfg, edition)) .collect::, DisplaySourceCodeError>>()? .into_iter() .join(", "); @@ -190,8 +194,8 @@ impl Expr { .map(|(a, f)| { let tmp = format!( "{}: {}", - f.name(db).display(db.upcast()), - a.gen_source_code(sema_scope, many_formatter, cfg)? + f.name(db).display(db.upcast(), edition), + a.gen_source_code(sema_scope, many_formatter, cfg, edition)? ); Ok(tmp) }) @@ -211,7 +215,7 @@ impl Expr { StructKind::Tuple => { let args = params .iter() - .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg)) + .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, edition)) .collect::, DisplaySourceCodeError>>()? .into_iter() .join(", "); @@ -225,8 +229,8 @@ impl Expr { .map(|(a, f)| { let tmp = format!( "{}: {}", - f.name(db).display(db.upcast()), - a.gen_source_code(sema_scope, many_formatter, cfg)? + f.name(db).display(db.upcast(), edition), + a.gen_source_code(sema_scope, many_formatter, cfg, edition)? ); Ok(tmp) }) @@ -244,7 +248,7 @@ impl Expr { Expr::Tuple { params, .. } => { let args = params .iter() - .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg)) + .map(|a| a.gen_source_code(sema_scope, many_formatter, cfg, edition)) .collect::, DisplaySourceCodeError>>()? .into_iter() .join(", "); @@ -256,8 +260,8 @@ impl Expr { return Ok(many_formatter(&expr.ty(db))); } - let strukt = expr.gen_source_code(sema_scope, many_formatter, cfg)?; - let field = field.name(db).display(db.upcast()).to_string(); + let strukt = expr.gen_source_code(sema_scope, many_formatter, cfg, edition)?; + let field = field.name(db).display(db.upcast(), edition).to_string(); Ok(format!("{strukt}.{field}")) } Expr::Reference(expr) => { @@ -265,7 +269,7 @@ impl Expr { return Ok(many_formatter(&expr.ty(db))); } - let inner = expr.gen_source_code(sema_scope, many_formatter, cfg)?; + let inner = expr.gen_source_code(sema_scope, many_formatter, cfg, edition)?; Ok(format!("&{inner}")) } Expr::Many(ty) => Ok(many_formatter(ty)), @@ -353,17 +357,18 @@ fn container_name( container: AssocItemContainer, sema_scope: &SemanticsScope<'_>, cfg: ImportPathConfig, + edition: Edition, ) -> Result { let container_name = match container { crate::AssocItemContainer::Trait(trait_) => { - mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_), cfg)? + mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_), cfg, edition)? } crate::AssocItemContainer::Impl(imp) => { let self_ty = imp.self_ty(sema_scope.db); // Should it be guaranteed that `mod_item_path` always exists? match self_ty.as_adt().and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg)) { - Some(path) => path.display(sema_scope.db.upcast()).to_string(), - None => self_ty.display(sema_scope.db).to_string(), + Some(path) => path.display(sema_scope.db.upcast(), edition).to_string(), + None => self_ty.display(sema_scope.db, edition).to_string(), } } }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 4cd15f1c755e..7f8ea44fb12c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -1,5 +1,8 @@ use hir::HasSource; -use syntax::ast::{self, make, AstNode}; +use syntax::{ + ast::{self, make, AstNode}, + Edition, +}; use crate::{ assist_context::{AssistContext, Assists}, @@ -150,14 +153,22 @@ fn add_missing_impl_members_inner( &missing_items, trait_, &new_impl_def, - target_scope, + &target_scope, ); if let Some(cap) = ctx.config.snippet_cap { let mut placeholder = None; if let DefaultMethods::No = mode { if let ast::AssocItem::Fn(func) = &first_new_item { - if try_gen_trait_body(ctx, func, trait_ref, &impl_def).is_none() { + if try_gen_trait_body( + ctx, + func, + trait_ref, + &impl_def, + target_scope.krate().edition(ctx.sema.db), + ) + .is_none() + { if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { if m.syntax().text() == "todo!()" { @@ -182,9 +193,11 @@ fn try_gen_trait_body( func: &ast::Fn, trait_ref: hir::TraitRef, impl_def: &ast::Impl, + edition: Edition, ) -> Option<()> { - let trait_path = - make::ext::ident_path(&trait_ref.trait_().name(ctx.db()).display(ctx.db()).to_string()); + let trait_path = make::ext::ident_path( + &trait_ref.trait_().name(ctx.db()).display(ctx.db(), edition).to_string(), + ); let hir_ty = ctx.sema.resolve_type(&impl_def.self_ty()?)?; let adt = hir_ty.as_adt()?.source(ctx.db())?; gen_trait_fn_body(func, &trait_path, &adt.value, Some(trait_ref)) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index f4569ca848ff..b6abb06a2afc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -445,7 +445,8 @@ fn build_pat( ) -> Option { match var { ExtendedVariant::Variant(var) => { - let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?); + let edition = module.krate().edition(db); + let path = mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition); // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though Some(match var.source(db)?.value.kind() { ast::StructKind::Tuple(field_list) => { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs index db53e49d8463..d86948818b16 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs @@ -8,7 +8,7 @@ use ide_db::{ insert_use::{insert_use, insert_use_as_alias, ImportScope}, }, }; -use syntax::{ast, AstNode, NodeOrToken, SyntaxElement}; +use syntax::{ast, AstNode, Edition, NodeOrToken, SyntaxElement}; use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel}; @@ -120,13 +120,14 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< // prioritize more relevant imports proposed_imports .sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref()))); + let edition = current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT); let group_label = group_label(import_assets.import_candidate()); for import in proposed_imports { let import_path = import.import_path; let (assist_id, import_name) = - (AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db())); + (AssistId("auto_import", AssistKind::QuickFix), import_path.display(ctx.db(), edition)); acc.add_group( &group_label, assist_id, @@ -138,7 +139,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), }; - insert_use(&scope, mod_path_to_ast(&import_path), &ctx.config.insert_use); + insert_use(&scope, mod_path_to_ast(&import_path, edition), &ctx.config.insert_use); }, ); @@ -165,7 +166,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< }; insert_use_as_alias( &scope, - mod_path_to_ast(&import_path), + mod_path_to_ast(&import_path, edition), &ctx.config.insert_use, ); }, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index 3a0754d60f85..cd5fe0f86269 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -339,6 +339,7 @@ fn augment_references_with_imports( let cfg = ctx.config.import_path_config(); + let edition = target_module.krate().edition(ctx.db()); references .into_iter() .filter_map(|FileReference { range, name, .. }| { @@ -361,7 +362,10 @@ fn augment_references_with_imports( cfg, ) .map(|mod_path| { - make::path_concat(mod_path_to_ast(&mod_path), make::path_from_text("Bool")) + make::path_concat( + mod_path_to_ast(&mod_path, edition), + make::path_from_text("Bool"), + ) }); import_scope.zip(path) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index 77f9c66b354e..a5c5b08d5b0c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -159,7 +159,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> }; // Verify this is `bool::then` that is being called. let func = ctx.sema.resolve_method_call(&mcall)?; - if func.name(ctx.sema.db).display(ctx.db()).to_string() != "then" { + if !func.name(ctx.sema.db).eq_ident("then") { return None; } let assoc = func.as_assoc_item(ctx.sema.db)?; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs index 5aa94590e679..8c59ef4314f0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_into_to_from.rs @@ -51,7 +51,10 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - Some(hir::PathResolution::Def(module_def)) => module_def, _ => return None, }; - mod_path_to_ast(&module.find_path(ctx.db(), src_type_def, cfg)?) + mod_path_to_ast( + &module.find_path(ctx.db(), src_type_def, cfg)?, + module.krate().edition(ctx.db()), + ) }; let dest_type = match &ast_trait { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs index e86ff0dbebc6..3c9a91741047 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs @@ -114,12 +114,16 @@ pub(crate) fn convert_for_loop_with_for_each( |builder| { let mut buf = String::new(); - if let Some((expr_behind_ref, method)) = + if let Some((expr_behind_ref, method, krate)) = is_ref_and_impls_iter_method(&ctx.sema, &iterable) { // We have either "for x in &col" and col implements a method called iter // or "for x in &mut col" and col implements a method called iter_mut - format_to!(buf, "{expr_behind_ref}.{}()", method.display(ctx.db())); + format_to!( + buf, + "{expr_behind_ref}.{}()", + method.display(ctx.db(), krate.edition(ctx.db())) + ); } else if let ast::Expr::RangeExpr(..) = iterable { // range expressions need to be parenthesized for the syntax to be correct format_to!(buf, "({iterable})"); @@ -144,7 +148,7 @@ pub(crate) fn convert_for_loop_with_for_each( fn is_ref_and_impls_iter_method( sema: &hir::Semantics<'_, ide_db::RootDatabase>, iterable: &ast::Expr, -) -> Option<(ast::Expr, hir::Name)> { +) -> Option<(ast::Expr, hir::Name, hir::Crate)> { let ref_expr = match iterable { ast::Expr::RefExpr(r) => r, _ => return None, @@ -172,7 +176,7 @@ fn is_ref_and_impls_iter_method( return None; } - Some((expr_behind_ref, wanted_method)) + Some((expr_behind_ref, wanted_method, krate)) } /// Whether iterable implements core::Iterator diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index 0f0b4442d8ac..91af9b05bbb8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -211,7 +211,7 @@ fn augment_references_with_imports( ) .map(|mod_path| { make::path_concat( - mod_path_to_ast(&mod_path), + mod_path_to_ast(&mod_path, target_module.krate().edition(ctx.db())), make::path_from_text(struct_name), ) }); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 095b8f958d09..b229b750e88b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -7,7 +7,7 @@ use ide_db::{ FxHashMap, FxHashSet, }; use itertools::Itertools; -use syntax::{ast, ted, AstNode, SmolStr, SyntaxNode, ToSmolStr}; +use syntax::{ast, ted, AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr}; use text_edit::TextRange; use crate::{ @@ -81,6 +81,7 @@ struct StructEditData { has_private_members: bool, is_nested: bool, is_ref: bool, + edition: Edition, } fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option { @@ -145,6 +146,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option AssignmentEdit { let ident_pat = builder.make_mut(data.ident_pat.clone()); - let struct_path = mod_path_to_ast(&data.struct_def_path); + let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition); let is_ref = ident_pat.ref_token().is_some(); let is_mut = ident_pat.mut_token().is_some(); @@ -247,7 +249,7 @@ fn generate_field_names(ctx: &AssistContext<'_>, data: &StructEditData) -> Vec<( .visible_fields .iter() .map(|field| { - let field_name = field.name(ctx.db()).display_no_db().to_smolstr(); + let field_name = field.name(ctx.db()).display_no_db(data.edition).to_smolstr(); let new_name = new_field_name(field_name.clone(), &data.names_in_scope); (field_name, new_name) }) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs index 9beb616d99bc..3d6d37ad93d2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs @@ -66,7 +66,9 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> let names_to_import = find_names_to_import(ctx, refs_in_target, imported_defs); let expanded = make::use_tree_list(names_to_import.iter().map(|n| { - let path = make::ext::ident_path(&n.display(ctx.db()).to_string()); + let path = make::ext::ident_path( + &n.display(ctx.db(), current_module.krate().edition(ctx.db())).to_string(), + ); make::use_tree(path, None, None, false) })) .clone_for_update(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 0a2cb6d5ef8a..cfcb09b9f7d9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -23,7 +23,7 @@ use syntax::{ self, edit::IndentLevel, edit_in_place::Indent, AstNode, AstToken, HasGenericParams, HasName, }, - match_ast, ted, SyntaxElement, + match_ast, ted, Edition, SyntaxElement, SyntaxKind::{self, COMMENT}, SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, }; @@ -84,7 +84,6 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op }; let body = extraction_target(&node, range)?; - let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema)?; let (locals_used, self_param) = body.analyze(&ctx.sema); @@ -92,6 +91,9 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let insert_after = node_to_insert_after(&body, anchor)?; let semantics_scope = ctx.sema.scope(&insert_after)?; let module = semantics_scope.module(); + let edition = semantics_scope.krate().edition(ctx.db()); + + let (container_info, contains_tail_expr) = body.analyze_container(&ctx.sema, edition)?; let ret_ty = body.return_ty(ctx)?; let control_flow = body.external_control_flow(ctx, &container_info)?; @@ -217,7 +219,11 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op ); if let Some(mod_path) = mod_path { - insert_use(&scope, mod_path_to_ast(&mod_path), &ctx.config.insert_use); + insert_use( + &scope, + mod_path_to_ast(&mod_path, edition), + &ctx.config.insert_use, + ); } } } @@ -238,7 +244,13 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef { let mut names_in_scope = vec![]; semantics_scope.process_all_names(&mut |name, _| { - names_in_scope.push(name.display(semantics_scope.db.upcast()).to_string()) + names_in_scope.push( + name.display( + semantics_scope.db.upcast(), + semantics_scope.krate().edition(semantics_scope.db), + ) + .to_string(), + ) }); let default_name = "fun_name"; @@ -366,6 +378,7 @@ struct ContainerInfo { ret_type: Option, generic_param_lists: Vec, where_clauses: Vec, + edition: Edition, } /// Control flow that is exported from extracted function @@ -489,8 +502,8 @@ impl Param { } } - fn to_arg(&self, ctx: &AssistContext<'_>) -> ast::Expr { - let var = path_expr_from_local(ctx, self.var); + fn to_arg(&self, ctx: &AssistContext<'_>, edition: Edition) -> ast::Expr { + let var = path_expr_from_local(ctx, self.var, edition); match self.kind() { ParamKind::Value | ParamKind::MutValue => var, ParamKind::SharedRef => make::expr_ref(var, false), @@ -498,8 +511,13 @@ impl Param { } } - fn to_param(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Param { - let var = self.var.name(ctx.db()).display(ctx.db()).to_string(); + fn to_param( + &self, + ctx: &AssistContext<'_>, + module: hir::Module, + edition: Edition, + ) -> ast::Param { + let var = self.var.name(ctx.db()).display(ctx.db(), edition).to_string(); let var_name = make::name(&var); let pat = match self.kind() { ParamKind::MutValue => make::ident_pat(false, true, var_name), @@ -520,7 +538,7 @@ impl Param { } impl TryKind { - fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>) -> Option { + fn of_ty(ty: hir::Type, ctx: &AssistContext<'_>, edition: Edition) -> Option { if ty.is_unknown() { // We favour Result for `expr?` return Some(TryKind::Result { ty }); @@ -529,7 +547,7 @@ impl TryKind { let name = adt.name(ctx.db()); // FIXME: use lang items to determine if it is std type or user defined // E.g. if user happens to define type named `Option`, we would have false positive - let name = &name.display(ctx.db()).to_string(); + let name = &name.display(ctx.db(), edition).to_string(); match name.as_str() { "Option" => Some(TryKind::Option), "Result" => Some(TryKind::Result { ty }), @@ -828,6 +846,7 @@ impl FunctionBody { fn analyze_container( &self, sema: &Semantics<'_, RootDatabase>, + edition: Edition, ) -> Option<(ContainerInfo, bool)> { let mut ancestors = self.parent()?.ancestors(); let infer_expr_opt = |expr| sema.type_of_expr(&expr?).map(TypeInfo::adjusted); @@ -927,6 +946,7 @@ impl FunctionBody { ret_type: ty, generic_param_lists, where_clauses, + edition, }, contains_tail_expr, )) @@ -1015,7 +1035,7 @@ impl FunctionBody { let kind = match (try_expr, ret_expr, break_expr, continue_expr) { (Some(_), _, None, None) => { let ret_ty = container_info.ret_type.clone()?; - let kind = TryKind::of_ty(ret_ty, ctx)?; + let kind = TryKind::of_ty(ret_ty, ctx, container_info.edition)?; Some(FlowKind::Try { kind }) } @@ -1397,7 +1417,7 @@ fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) { fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> SyntaxNode { let ret_ty = fun.return_type(ctx); - let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx))); + let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx, fun.mods.edition))); let name = fun.name.clone(); let mut call_expr = if fun.self_param.is_some() { let self_arg = make::expr_path(make::ext::ident_path("self")); @@ -1420,13 +1440,13 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> Sy [] => None, [var] => { let name = var.local.name(ctx.db()); - let name = make::name(&name.display(ctx.db()).to_string()); + let name = make::name(&name.display(ctx.db(), fun.mods.edition).to_string()); Some(ast::Pat::IdentPat(make::ident_pat(false, var.mut_usage_outside_body, name))) } vars => { let binding_pats = vars.iter().map(|var| { let name = var.local.name(ctx.db()); - let name = make::name(&name.display(ctx.db()).to_string()); + let name = make::name(&name.display(ctx.db(), fun.mods.edition).to_string()); make::ident_pat(false, var.mut_usage_outside_body, name).into() }); Some(ast::Pat::TuplePat(make::tuple_pat(binding_pats))) @@ -1569,8 +1589,8 @@ impl FlowHandler { } } -fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local) -> ast::Expr { - let name = var.name(ctx.db()).display(ctx.db()).to_string(); +fn path_expr_from_local(ctx: &AssistContext<'_>, var: Local, edition: Edition) -> ast::Expr { + let name = var.name(ctx.db()).display(ctx.db(), edition).to_string(); make::expr_path(make::ext::ident_path(&name)) } @@ -1581,7 +1601,7 @@ fn format_function( old_indent: IndentLevel, ) -> ast::Fn { let fun_name = make::name(&fun.name.text()); - let params = fun.make_param_list(ctx, module); + let params = fun.make_param_list(ctx, module, fun.mods.edition); let ret_ty = fun.make_ret_ty(ctx, module); let body = make_body(ctx, old_indent, fun); let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun); @@ -1707,9 +1727,14 @@ impl Function { type_params_in_descendant_paths.chain(type_params_in_params).collect() } - fn make_param_list(&self, ctx: &AssistContext<'_>, module: hir::Module) -> ast::ParamList { + fn make_param_list( + &self, + ctx: &AssistContext<'_>, + module: hir::Module, + edition: Edition, + ) -> ast::ParamList { let self_param = self.self_param.clone(); - let params = self.params.iter().map(|param| param.to_param(ctx, module)); + let params = self.params.iter().map(|param| param.to_param(ctx, module, edition)); make::param_list(self_param, params) } @@ -1842,10 +1867,12 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) - None => match fun.outliving_locals.as_slice() { [] => {} [var] => { - tail_expr = Some(path_expr_from_local(ctx, var.local)); + tail_expr = Some(path_expr_from_local(ctx, var.local, fun.mods.edition)); } vars => { - let exprs = vars.iter().map(|var| path_expr_from_local(ctx, var.local)); + let exprs = vars + .iter() + .map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition)); let expr = make::expr_tuple(exprs); tail_expr = Some(expr); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index a62fdeb61739..615b5d3f98b5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -1,7 +1,7 @@ use std::iter; use either::Either; -use hir::{Module, ModuleDef, Name, Variant}; +use hir::{HasCrate, Module, ModuleDef, Name, Variant}; use ide_db::{ defs::Definition, helpers::mod_path_to_ast, @@ -16,7 +16,7 @@ use syntax::{ self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams, HasName, HasVisibility, }, - match_ast, ted, SyntaxElement, + match_ast, ted, Edition, SyntaxElement, SyntaxKind::*, SyntaxNode, T, }; @@ -58,6 +58,7 @@ pub(crate) fn extract_struct_from_enum_variant( "Extract struct from enum variant", target, |builder| { + let edition = enum_hir.krate(ctx.db()).edition(ctx.db()); let variant_hir_name = variant_hir.name(ctx.db()); let enum_module_def = ModuleDef::from(enum_hir); let usages = Definition::Variant(variant_hir).usages(&ctx.sema).all(); @@ -82,7 +83,7 @@ pub(crate) fn extract_struct_from_enum_variant( references, ); processed.into_iter().for_each(|(path, node, import)| { - apply_references(ctx.config.insert_use, path, node, import) + apply_references(ctx.config.insert_use, path, node, import, edition) }); } builder.edit_file(ctx.file_id()); @@ -98,7 +99,7 @@ pub(crate) fn extract_struct_from_enum_variant( references, ); processed.into_iter().for_each(|(path, node, import)| { - apply_references(ctx.config.insert_use, path, node, import) + apply_references(ctx.config.insert_use, path, node, import, edition) }); } @@ -169,7 +170,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va ), _ => false, }) - .any(|(name, _)| name.display(db).to_string() == variant_name.to_string()) + .any(|(name, _)| name.eq_ident(variant_name.text().as_str())) } fn extract_generic_params( @@ -359,9 +360,10 @@ fn apply_references( segment: ast::PathSegment, node: SyntaxNode, import: Option<(ImportScope, hir::ModPath)>, + edition: Edition, ) { if let Some((scope, path)) = import { - insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg); + insert_use(&scope, mod_path_to_ast(&path, edition), &insert_use_cfg); } // deep clone to prevent cycle let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs index 758f50d3f47b..ee321864805e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs @@ -45,8 +45,9 @@ pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext< let new_field_list = make::record_pat_field_list(old_field_list.fields(), None).clone_for_update(); for (f, _) in missing_fields.iter() { + let edition = ctx.sema.scope(record_pat.syntax())?.krate().edition(ctx.db()); let field = make::record_pat_field_shorthand(make::name_ref( - &f.name(ctx.sema.db).display_no_db().to_smolstr(), + &f.name(ctx.sema.db).display_no_db(edition).to_smolstr(), )); new_field_list.add_field(field.clone_for_update()); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs index 9950f9c14749..7a92d8911bf8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs @@ -4,7 +4,7 @@ use hir::{ use ide_db::FileId; use syntax::{ ast::{self, edit_in_place::HasVisibilityEdit, make, HasVisibility as _}, - AstNode, TextRange, ToSmolStr, + AstNode, TextRange, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -48,7 +48,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) let (_, def) = module .scope(ctx.db(), None) .into_iter() - .find(|(name, _)| name.display_no_db().to_smolstr() == name_ref.text().as_str())?; + .find(|(name, _)| name.eq_ident(name_ref.text().as_str()))?; let ScopeDef::ModuleDef(def) = def else { return None; }; @@ -71,7 +71,10 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) let assist_label = match target_name { None => format!("Change visibility to {missing_visibility}"), Some(name) => { - format!("Change visibility of {} to {missing_visibility}", name.display(ctx.db())) + format!( + "Change visibility of {} to {missing_visibility}", + name.display(ctx.db(), current_module.krate().edition(ctx.db())) + ) } }; @@ -92,6 +95,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_> let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?; let current_module = ctx.sema.scope(record_field.syntax())?.module(); + let current_edition = current_module.krate().edition(ctx.db()); let visibility = record_field_def.visibility(ctx.db()); if visibility.is_visible_from(ctx.db(), current_module.into()) { return None; @@ -123,8 +127,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_> let target_name = record_field_def.name(ctx.db()); let assist_label = format!( "Change visibility of {}.{} to {missing_visibility}", - parent_name.display(ctx.db()), - target_name.display(ctx.db()) + parent_name.display(ctx.db(), current_edition), + target_name.display(ctx.db(), current_edition) ); acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |edit| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs index 2150003bc143..bbb902f8a2a4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs @@ -51,6 +51,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' let strukt = ctx.find_node_at_offset::()?; let strukt_name = strukt.name()?; let current_module = ctx.sema.scope(strukt.syntax())?.module(); + let current_edition = current_module.krate().edition(ctx.db()); let (field_name, field_ty, target) = match ctx.find_node_at_offset::() { Some(field) => { @@ -89,7 +90,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<' methods.sort_by(|(a, _), (b, _)| a.cmp(b)); for (name, method) in methods { let adt = ast::Adt::Struct(strukt.clone()); - let name = name.display(ctx.db()).to_string(); + let name = name.display(ctx.db(), current_edition).to_string(); // if `find_struct_impl` returns None, that means that a function named `name` already exists. let Some(impl_def) = find_struct_impl(ctx, &adt, std::slice::from_ref(&name)) else { continue; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs index 5a3457e5b7a4..933ab2058ec9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs @@ -22,7 +22,7 @@ use syntax::{ WherePred, }, ted::{self, Position}, - AstNode, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr, + AstNode, Edition, NodeOrToken, SmolStr, SyntaxKind, ToSmolStr, }; // Assist: generate_delegate_trait @@ -109,6 +109,7 @@ struct Field { ty: ast::Type, range: syntax::TextRange, impls: Vec, + edition: Edition, } impl Field { @@ -119,6 +120,7 @@ impl Field { let db = ctx.sema.db; let module = ctx.sema.file_to_module_def(ctx.file_id())?; + let edition = module.krate().edition(ctx.db()); let (name, range, ty) = match f { Either::Left(f) => { @@ -147,7 +149,7 @@ impl Field { } } - Some(Field { name, ty, range, impls }) + Some(Field { name, ty, range, impls, edition }) } } @@ -163,18 +165,18 @@ enum Delegee { } impl Delegee { - fn signature(&self, db: &dyn HirDatabase) -> String { + fn signature(&self, db: &dyn HirDatabase, edition: Edition) -> String { let mut s = String::new(); let (Delegee::Bound(it) | Delegee::Impls(it, _)) = self; for m in it.module(db).path_to_root(db).iter().rev() { if let Some(name) = m.name(db) { - s.push_str(&format!("{}::", name.display_no_db().to_smolstr())); + s.push_str(&format!("{}::", name.display_no_db(edition).to_smolstr())); } } - s.push_str(&it.name(db).display_no_db().to_smolstr()); + s.push_str(&it.name(db).display_no_db(edition).to_smolstr()); s } } @@ -212,9 +214,11 @@ impl Struct { // if self.hir_ty.impls_trait(db, trait_, &[]) { // continue; // } - let signature = delegee.signature(db); + let signature = delegee.signature(db, field.edition); - let Some(delegate) = generate_impl(ctx, self, &field.ty, &field.name, delegee) else { + let Some(delegate) = + generate_impl(ctx, self, &field.ty, &field.name, delegee, field.edition) + else { continue; }; @@ -240,6 +244,7 @@ fn generate_impl( field_ty: &ast::Type, field_name: &str, delegee: &Delegee, + edition: Edition, ) -> Option { let delegate: ast::Impl; let db = ctx.db(); @@ -259,7 +264,7 @@ fn generate_impl( strukt_params.clone(), strukt_params.map(|params| params.to_generic_args()), delegee.is_auto(db), - make::ty(&delegee.name(db).display_no_db().to_smolstr()), + make::ty(&delegee.name(db).display_no_db(edition).to_smolstr()), strukt_ty, bound_def.where_clause(), ast_strukt.where_clause(), @@ -350,7 +355,7 @@ fn generate_impl( let type_gen_args = strukt_params.clone().map(|params| params.to_generic_args()); let path_type = - make::ty(&trait_.name(db).display_no_db().to_smolstr()).clone_for_update(); + make::ty(&trait_.name(db).display_no_db(edition).to_smolstr()).clone_for_update(); transform_impl(ctx, ast_strukt, &old_impl, &transform_args, path_type.syntax())?; // 3) Generate delegate trait impl diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs index 2ac7057fe794..e558bb6da89b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_deref.rs @@ -4,7 +4,7 @@ use hir::{ModPath, ModuleDef}; use ide_db::{famous_defs::FamousDefs, RootDatabase}; use syntax::{ ast::{self, HasName}, - AstNode, SyntaxNode, + AstNode, Edition, SyntaxNode, }; use crate::{ @@ -77,6 +77,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( field_name.syntax(), deref_type_to_generate, trait_path, + module.krate().edition(ctx.db()), ) }, ) @@ -117,6 +118,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() field_list_index, deref_type_to_generate, trait_path, + module.krate().edition(ctx.db()), ) }, ) @@ -130,6 +132,7 @@ fn generate_edit( field_name: impl Display, deref_type: DerefType, trait_path: ModPath, + edition: Edition, ) { let start_offset = strukt.syntax().text_range().end(); let impl_code = match deref_type { @@ -147,8 +150,11 @@ fn generate_edit( ), }; let strukt_adt = ast::Adt::Struct(strukt); - let deref_impl = - generate_trait_impl_text(&strukt_adt, &trait_path.display(db).to_string(), &impl_code); + let deref_impl = generate_trait_impl_text( + &strukt_adt, + &trait_path.display(db, edition).to_string(), + &impl_code, + ); edit.insert(start_offset, deref_impl); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs index 51dd4884547b..c5c70c9f8eb6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs @@ -5,7 +5,7 @@ use stdx::{format_to, to_lower_snake_case}; use syntax::{ algo::skip_whitespace_token, ast::{self, edit::IndentLevel, HasDocComments, HasGenericArgs, HasName}, - match_ast, AstNode, AstToken, + match_ast, AstNode, AstToken, Edition, }; use crate::assist_context::{AssistContext, Assists}; @@ -139,7 +139,8 @@ fn make_example_for_fn(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option Vec { } /// Helper function to build the path of the module in the which is the node -fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> Option { +fn build_path(ast_func: &ast::Fn, ctx: &AssistContext<'_>, edition: Edition) -> Option { let crate_name = crate_name(ast_func, ctx)?; let leaf = self_partial_type(ast_func) .or_else(|| ast_func.name().map(|n| n.to_string())) .unwrap_or_else(|| "*".into()); let module_def: ModuleDef = ctx.sema.to_def(ast_func)?.module(ctx.db()).into(); - match module_def.canonical_path(ctx.db()) { + match module_def.canonical_path(ctx.db(), edition) { Some(path) => Some(format!("{crate_name}::{path}::{leaf}")), None => Some(format!("{crate_name}::{leaf}")), } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index b2980d5c6301..cd29f77f0c95 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -17,7 +17,7 @@ use syntax::{ self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, BlockExpr, CallExpr, HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds, }, - ted, SyntaxKind, SyntaxNode, TextRange, T, + ted, Edition, SyntaxKind, SyntaxNode, TextRange, T, }; use crate::{ @@ -175,6 +175,7 @@ fn add_func_to_accumulator( edit.edit_file(file); let target = function_builder.target.clone(); + let edition = function_builder.target_edition; let func = function_builder.render(ctx.config.snippet_cap, edit); if let Some(adt) = @@ -183,7 +184,7 @@ fn add_func_to_accumulator( { let name = make::ty_path(make::ext::ident_path(&format!( "{}", - adt.name(ctx.db()).display(ctx.db()) + adt.name(ctx.db()).display(ctx.db(), edition) ))); // FIXME: adt may have generic params. @@ -222,6 +223,7 @@ struct FunctionBuilder { should_focus_return_type: bool, visibility: Visibility, is_async: bool, + target_edition: Edition, } impl FunctionBuilder { @@ -237,6 +239,7 @@ impl FunctionBuilder { ) -> Option { let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?; + let target_edition = target_module.krate().edition(ctx.db()); let current_module = ctx.sema.scope(call.syntax())?.module(); let visibility = calculate_necessary_visibility(current_module, target_module, ctx); @@ -258,7 +261,9 @@ impl FunctionBuilder { // If generated function has the name "new" and is an associated function, we generate fn body // as a constructor and assume a "Self" return type. - if let Some(body) = make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info) { + if let Some(body) = + make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info, target_edition) + { ret_type = Some(make::ret_type(make::ty_path(make::ext::ident_path("Self")))); should_focus_return_type = false; fn_body = body; @@ -288,6 +293,7 @@ impl FunctionBuilder { should_focus_return_type, visibility, is_async, + target_edition, }) } @@ -299,6 +305,8 @@ impl FunctionBuilder { target_module: Module, target: GeneratedFunctionTarget, ) -> Option { + let target_edition = target_module.krate().edition(ctx.db()); + let current_module = ctx.sema.scope(call.syntax())?.module(); let visibility = calculate_necessary_visibility(current_module, target_module, ctx); @@ -336,6 +344,7 @@ impl FunctionBuilder { should_focus_return_type, visibility, is_async, + target_edition, }) } @@ -425,6 +434,7 @@ fn make_fn_body_as_new_function( ctx: &AssistContext<'_>, fn_name: &str, adt_info: &Option, + edition: Edition, ) -> Option { if fn_name != "new" { return None; @@ -441,7 +451,10 @@ fn make_fn_body_as_new_function( .iter() .map(|field| { make::record_expr_field( - make::name_ref(&format!("{}", field.name(ctx.db()).display(ctx.db()))), + make::name_ref(&format!( + "{}", + field.name(ctx.db()).display(ctx.db(), edition) + )), Some(placeholder_expr.clone()), ) }) @@ -1102,8 +1115,9 @@ fn fn_arg_type( if ty.is_reference() || ty.is_mutable_reference() { let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate()); + let target_edition = target_module.krate().edition(ctx.db()); convert_reference_type(ty.strip_references(), ctx.db(), famous_defs) - .map(|conversion| conversion.convert_type(ctx.db()).to_string()) + .map(|conversion| conversion.convert_type(ctx.db(), target_edition).to_string()) .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok()) } else { ty.display_source_code(ctx.db(), target_module.into(), true).ok() diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs index 60214aaaf69e..8e349e84a96c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -233,7 +233,7 @@ fn generate_getter_from_info( .map(|conversion| { cov_mark::hit!(convert_reference_type); ( - conversion.convert_type(ctx.db()), + conversion.convert_type(ctx.db(), krate.edition(ctx.db())), conversion.getter(record_field_info.field_name.to_string()), ) }) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs index b985b5e66c4d..b9dede7cbdc3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs @@ -64,10 +64,13 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option ctx.config.import_path_config(), )?; + let edition = current_module.krate().edition(ctx.db()); + let expr = use_trivial_constructor( ctx.sema.db, - ide_db::helpers::mod_path_to_ast(&type_path), + ide_db::helpers::mod_path_to_ast(&type_path, edition), &ty, + edition, )?; Some(make::record_expr_field(make::name_ref(&name.text()), Some(expr))) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs index 111ea50fdc94..f1c2acdd3ed9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs @@ -51,10 +51,13 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_> | ast::Expr::MatchExpr(_) | ast::Expr::MacroExpr(_) | ast::Expr::BinExpr(_) - | ast::Expr::CallExpr(_) => match konst.render_eval(ctx.sema.db) { - Ok(result) => result, - Err(_) => return None, - }, + | ast::Expr::CallExpr(_) => { + let edition = ctx.sema.scope(variable.syntax())?.krate().edition(ctx.db()); + match konst.render_eval(ctx.sema.db, edition) { + Ok(result) => result, + Err(_) => return None, + } + } _ => return None, }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs index 3057745a97b7..743ea9476150 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_const_to_impl.rs @@ -104,9 +104,13 @@ pub(crate) fn move_const_to_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> }; builder.delete(range_to_delete); - let const_ref = format!("Self::{}", name.display(ctx.db())); - for range in usages.file_ranges().map(|it| it.range) { - builder.replace(range, const_ref.clone()); + let usages = usages.iter().flat_map(|(file_id, usages)| { + let edition = file_id.edition(); + usages.iter().map(move |usage| (edition, usage.range)) + }); + for (edition, range) in usages { + let const_ref = format!("Self::{}", name.display(ctx.db(), edition)); + builder.replace(range, const_ref); } // Heuristically inserting the extracted const after the consecutive existing consts diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs index 14381085a782..8a7a06b380f5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs @@ -39,7 +39,7 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op } let target = source_file.syntax().text_range(); - let module_name = module.name(ctx.db())?.display(ctx.db()).to_string(); + let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string(); let path = format!("../{module_name}.rs"); let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path }; acc.add( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs index e679a68f4466..9692b7059291 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs @@ -61,7 +61,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) -> .string_value_unescape() .is_none() => { - format_to!(buf, "{}/", name.display(db)) + format_to!(buf, "{}/", name.unescaped().display(db)) } _ => (), } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs index c89d54ff039d..2925e2334b44 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs @@ -39,7 +39,7 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti } let target = source_file.syntax().text_range(); - let module_name = module.name(ctx.db())?.display(ctx.db()).to_string(); + let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string(); let path = format!("./{module_name}/mod.rs"); let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path }; acc.add( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs index b1e98045fcfa..14518c4d2cc4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -42,6 +42,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> let resolved_call = ctx.sema.resolve_method_call(&call)?; let current_module = ctx.sema.scope(call.syntax())?.module(); + let current_edition = current_module.krate().edition(ctx.db()); let target_module_def = ModuleDef::from(resolved_call); let item_in_ns = ItemInNs::from(target_module_def); let receiver_path = current_module.find_path( @@ -61,6 +62,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> |replace_with: String| builder.replace(range, replace_with), &receiver_path, item_in_ns, + current_edition, ) }, ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs index d8e7da15d5bf..ac88861fe4fd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs @@ -8,6 +8,7 @@ use ide_db::{ imports::import_assets::{ImportCandidate, LocatedImport}, }; use syntax::ast::HasGenericArgs; +use syntax::Edition; use syntax::{ ast, ast::{make, HasArgList}, @@ -93,6 +94,8 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option NodeOrToken::Token(t) => t.parent()?, }) .map(|scope| scope.module()); + let current_edition = + current_module.map(|it| it.krate().edition(ctx.db())).unwrap_or(Edition::CURRENT); // prioritize more relevant imports proposed_imports.sort_by_key(|import| { Reverse(super::auto_import::relevance_score(ctx, import, current_module.as_ref())) @@ -103,13 +106,14 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option acc.add_group( &group_label, AssistId("qualify_path", AssistKind::QuickFix), - label(ctx.db(), candidate, &import), + label(ctx.db(), candidate, &import, current_edition), range, |builder| { qualify_candidate.qualify( |replace_with: String| builder.replace(range, replace_with), &import.import_path, import.item_to_import, + current_edition, ) }, ); @@ -130,8 +134,9 @@ impl QualifyCandidate<'_> { mut replacer: impl FnMut(String), import: &hir::ModPath, item: hir::ItemInNs, + edition: Edition, ) { - let import = mod_path_to_ast(import); + let import = mod_path_to_ast(import, edition); match self { QualifyCandidate::QualifierStart(segment, generics) => { let generics = generics.as_ref().map_or_else(String::new, ToString::to_string); @@ -203,7 +208,7 @@ fn find_trait_method( if let Some(hir::AssocItem::Function(method)) = trait_.items(db).into_iter().find(|item: &hir::AssocItem| { item.name(db) - .map(|name| name.display(db).to_string() == trait_method_name.to_string()) + .map(|name| name.eq_ident(trait_method_name.text().as_str())) .unwrap_or(false) }) { @@ -233,14 +238,19 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { GroupLabel(format!("Qualify {name}")) } -fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String { +fn label( + db: &RootDatabase, + candidate: &ImportCandidate, + import: &LocatedImport, + edition: Edition, +) -> String { let import_path = &import.import_path; match candidate { ImportCandidate::Path(candidate) if candidate.qualifier.is_none() => { - format!("Qualify as `{}`", import_path.display(db)) + format!("Qualify as `{}`", import_path.display(db, edition)) } - _ => format!("Qualify with `{}`", import_path.display(db)), + _ => format!("Qualify with `{}`", import_path.display(db, edition)), } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs index 025625669774..df7a5112f126 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs @@ -1,7 +1,7 @@ use either::Either; use ide_db::FxHashMap; use itertools::Itertools; -use syntax::{ast, ted, AstNode}; +use syntax::{ast, ted, AstNode, SmolStr, ToSmolStr}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,8 +25,9 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti path.syntax().parent().and_then(>::cast)?; let ranks = compute_fields_ranks(&path, ctx)?; - let get_rank_of_field = - |of: Option<_>| *ranks.get(&of.unwrap_or_default()).unwrap_or(&usize::MAX); + let get_rank_of_field = |of: Option| { + *ranks.get(of.unwrap_or_default().trim_start_matches("r#")).unwrap_or(&usize::MAX) + }; let field_list = match &record { Either::Left(it) => Either::Left(it.record_expr_field_list()?), @@ -36,7 +37,7 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti Either::Left(it) => Either::Left(( it.fields() .sorted_unstable_by_key(|field| { - get_rank_of_field(field.field_name().map(|it| it.to_string())) + get_rank_of_field(field.field_name().map(|it| it.to_smolstr())) }) .collect::>(), it, @@ -44,7 +45,7 @@ pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti Either::Right(it) => Either::Right(( it.fields() .sorted_unstable_by_key(|field| { - get_rank_of_field(field.field_name().map(|it| it.to_string())) + get_rank_of_field(field.field_name().map(|it| it.to_smolstr())) }) .collect::>(), it, @@ -97,7 +98,7 @@ fn compute_fields_ranks( .fields(ctx.db()) .into_iter() .enumerate() - .map(|(idx, field)| (field.name(ctx.db()).display(ctx.db()).to_string(), idx)) + .map(|(idx, field)| (field.name(ctx.db()).unescaped().display(ctx.db()).to_string(), idx)) .collect(); Some(res) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs index cf135f83e7b6..ada89ce7c40a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs @@ -77,7 +77,8 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) -> ast::AssocItem::MacroCall(_) => None, }; - name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::MAX) + name.and_then(|n| ranks.get(n.text().as_str().trim_start_matches("r#")).copied()) + .unwrap_or(usize::MAX) }) .collect(); @@ -114,7 +115,7 @@ fn compute_item_ranks( .iter() .flat_map(|i| i.name(ctx.db())) .enumerate() - .map(|(idx, name)| (name.display(ctx.db()).to_string(), idx)) + .map(|(idx, name)| (name.unescaped().display(ctx.db()).to_string(), idx)) .collect(), ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 5ff4af19fbf1..248f18789ce3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -70,6 +70,7 @@ pub(crate) fn replace_derive_with_manual_impl( let current_module = ctx.sema.scope(adt.syntax())?.module(); let current_crate = current_module.krate(); + let current_edition = current_crate.edition(ctx.db()); let found_traits = items_locator::items_with_name( &ctx.sema, @@ -85,7 +86,7 @@ pub(crate) fn replace_derive_with_manual_impl( current_module .find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.import_path_config()) .as_ref() - .map(mod_path_to_ast) + .map(|path| mod_path_to_ast(path, current_edition)) .zip(Some(trait_)) }); @@ -214,7 +215,7 @@ fn impl_def_from_trait( let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone())); let first_assoc_item = - add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, target_scope); + add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, &target_scope); // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index d0aa835e79af..65330b34c4ad 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -5,7 +5,7 @@ use ide_db::{ }; use syntax::{ ast::{self, make, HasGenericArgs}, - match_ast, ted, AstNode, SyntaxNode, + match_ast, ted, AstNode, Edition, SyntaxNode, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -29,32 +29,32 @@ pub(crate) fn replace_qualified_name_with_use( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - let path: ast::Path = ctx.find_node_at_offset()?; + let original_path: ast::Path = ctx.find_node_at_offset()?; // We don't want to mess with use statements - if path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() { + if original_path.syntax().ancestors().find_map(ast::UseTree::cast).is_some() { cov_mark::hit!(not_applicable_in_use); return None; } - if path.qualifier().is_none() { + if original_path.qualifier().is_none() { cov_mark::hit!(dont_import_trivial_paths); return None; } // only offer replacement for non assoc items - match ctx.sema.resolve_path(&path)? { + match ctx.sema.resolve_path(&original_path)? { hir::PathResolution::Def(def) if def.as_assoc_item(ctx.sema.db).is_none() => (), _ => return None, } // then search for an import for the first path segment of what we want to replace // that way it is less likely that we import the item from a different location due re-exports - let module = match ctx.sema.resolve_path(&path.first_qualifier_or_self())? { + let module = match ctx.sema.resolve_path(&original_path.first_qualifier_or_self())? { hir::PathResolution::Def(module @ hir::ModuleDef::Module(_)) => module, _ => return None, }; let starts_with_name_ref = !matches!( - path.first_segment().and_then(|it| it.kind()), + original_path.first_segment().and_then(|it| it.kind()), Some( ast::PathSegmentKind::CrateKw | ast::PathSegmentKind::SuperKw @@ -63,7 +63,7 @@ pub(crate) fn replace_qualified_name_with_use( ); let path_to_qualifier = starts_with_name_ref .then(|| { - ctx.sema.scope(path.syntax())?.module().find_use_path( + ctx.sema.scope(original_path.syntax())?.module().find_use_path( ctx.sema.db, module, ctx.config.insert_use.prefix_kind, @@ -72,8 +72,8 @@ pub(crate) fn replace_qualified_name_with_use( }) .flatten(); - let scope = ImportScope::find_insert_use_container(path.syntax(), &ctx.sema)?; - let target = path.syntax().text_range(); + let scope = ImportScope::find_insert_use_container(original_path.syntax(), &ctx.sema)?; + let target = original_path.syntax().text_range(); acc.add( AssistId("replace_qualified_name_with_use", AssistKind::RefactorRewrite), "Replace qualified path with use", @@ -86,13 +86,19 @@ pub(crate) fn replace_qualified_name_with_use( ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)), }; - shorten_paths(scope.as_syntax_node(), &path); - let path = drop_generic_args(&path); + shorten_paths(scope.as_syntax_node(), &original_path); + let path = drop_generic_args(&original_path); + let edition = ctx + .sema + .scope(original_path.syntax()) + .map(|semantics_scope| semantics_scope.krate().edition(ctx.db())) + .unwrap_or(Edition::CURRENT); // stick the found import in front of the to be replaced path - let path = match path_to_qualifier.and_then(|it| mod_path_to_ast(&it).qualifier()) { - Some(qualifier) => make::path_concat(qualifier, path), - None => path, - }; + let path = + match path_to_qualifier.and_then(|it| mod_path_to_ast(&it, edition).qualifier()) { + Some(qualifier) => make::path_concat(qualifier, path), + None => path, + }; insert_use(&scope, path, &ctx.config.insert_use); }, ) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs index 4913cfdea944..66671c934c4b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs @@ -48,15 +48,17 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< let mut formatter = |_: &hir::Type| String::from("todo!()"); + let edition = scope.krate().edition(ctx.db()); let paths = paths .into_iter() .filter_map(|path| { - path.gen_source_code(&scope, &mut formatter, ctx.config.import_path_config()).ok() + path.gen_source_code(&scope, &mut formatter, ctx.config.import_path_config(), edition) + .ok() }) .unique(); let macro_name = macro_call.name(ctx.sema.db); - let macro_name = macro_name.display(ctx.sema.db); + let macro_name = macro_name.display(ctx.sema.db, edition); for code in paths { acc.add_group( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs index 98975a324dc3..9ab36bf7757d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_async_sugar.rs @@ -141,7 +141,8 @@ pub(crate) fn desugar_async_into_impl_future( ModuleDef::Trait(future_trait), ctx.config.import_path_config(), )?; - let trait_path = trait_path.display(ctx.db()); + let edition = scope.krate().edition(ctx.db()); + let trait_path = trait_path.display(ctx.db(), edition); acc.add( AssistId("desugar_async_into_impl_future", AssistKind::RefactorRewrite), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index c67693ea2bb8..b8a6f3b6dbeb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -14,7 +14,7 @@ use syntax::{ edit_in_place::{AttrsOwnerEdit, Indent, Removable}, make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace, }, - ted, AstNode, AstToken, Direction, NodeOrToken, SourceFile, + ted, AstNode, AstToken, Direction, Edition, NodeOrToken, SourceFile, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TextSize, T, }; @@ -174,7 +174,7 @@ pub fn add_trait_assoc_items_to_impl( original_items: &[InFile], trait_: hir::Trait, impl_: &ast::Impl, - target_scope: hir::SemanticsScope<'_>, + target_scope: &hir::SemanticsScope<'_>, ) -> ast::AssocItem { let new_indent_level = IndentLevel::from_node(impl_.syntax()) + 1; let items = original_items.iter().map(|InFile { file_id, value: original_item }| { @@ -195,7 +195,7 @@ pub fn add_trait_assoc_items_to_impl( // FIXME: Paths in nested macros are not handled well. See // `add_missing_impl_members::paths_in_nested_macro_should_get_transformed` test. let transform = - PathTransform::trait_impl(&target_scope, &source_scope, trait_, impl_.clone()); + PathTransform::trait_impl(target_scope, &source_scope, trait_, impl_.clone()); transform.apply(cloned_item.syntax()); } cloned_item.remove_attrs_and_docs(); @@ -684,31 +684,31 @@ enum ReferenceConversionType { } impl ReferenceConversion { - pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> ast::Type { + pub(crate) fn convert_type(&self, db: &dyn HirDatabase, edition: Edition) -> ast::Type { let ty = match self.conversion { - ReferenceConversionType::Copy => self.ty.display(db).to_string(), + ReferenceConversionType::Copy => self.ty.display(db, edition).to_string(), ReferenceConversionType::AsRefStr => "&str".to_owned(), ReferenceConversionType::AsRefSlice => { let type_argument_name = - self.ty.type_arguments().next().unwrap().display(db).to_string(); + self.ty.type_arguments().next().unwrap().display(db, edition).to_string(); format!("&[{type_argument_name}]") } ReferenceConversionType::Dereferenced => { let type_argument_name = - self.ty.type_arguments().next().unwrap().display(db).to_string(); + self.ty.type_arguments().next().unwrap().display(db, edition).to_string(); format!("&{type_argument_name}") } ReferenceConversionType::Option => { let type_argument_name = - self.ty.type_arguments().next().unwrap().display(db).to_string(); + self.ty.type_arguments().next().unwrap().display(db, edition).to_string(); format!("Option<&{type_argument_name}>") } ReferenceConversionType::Result => { let mut type_arguments = self.ty.type_arguments(); let first_type_argument_name = - type_arguments.next().unwrap().display(db).to_string(); + type_arguments.next().unwrap().display(db, edition).to_string(); let second_type_argument_name = - type_arguments.next().unwrap().display(db).to_string(); + type_arguments.next().unwrap().display(db, edition).to_string(); format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>") } }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs index fc43d243b36e..3130ef069557 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use stdx::to_lower_snake_case; use syntax::{ ast::{self, HasName}, - match_ast, AstNode, SmolStr, + match_ast, AstNode, Edition, SmolStr, }; /// Trait names, that will be ignored when in `impl Trait` and `dyn Trait` @@ -271,24 +271,25 @@ fn var_name_from_pat(pat: &ast::Pat) -> Option { fn from_type(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option { let ty = sema.type_of_expr(expr)?.adjusted(); let ty = ty.remove_ref().unwrap_or(ty); + let edition = sema.scope(expr.syntax())?.krate().edition(sema.db); - name_of_type(&ty, sema.db) + name_of_type(&ty, sema.db, edition) } -fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option { +fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option { let name = if let Some(adt) = ty.as_adt() { - let name = adt.name(db).display(db).to_string(); + let name = adt.name(db).display(db, edition).to_string(); if WRAPPER_TYPES.contains(&name.as_str()) { let inner_ty = ty.type_arguments().next()?; - return name_of_type(&inner_ty, db); + return name_of_type(&inner_ty, db, edition); } name } else if let Some(trait_) = ty.as_dyn_trait() { - trait_name(&trait_, db)? + trait_name(&trait_, db, edition)? } else if let Some(traits) = ty.as_impl_traits(db) { - let mut iter = traits.filter_map(|t| trait_name(&t, db)); + let mut iter = traits.filter_map(|t| trait_name(&t, db, edition)); let name = iter.next()?; if iter.next().is_some() { return None; @@ -300,8 +301,8 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase) -> Option { normalize(&name) } -fn trait_name(trait_: &hir::Trait, db: &RootDatabase) -> Option { - let name = trait_.name(db).display(db).to_string(); +fn trait_name(trait_: &hir::Trait, db: &RootDatabase, edition: Edition) -> Option { + let name = trait_.name(db).display(db, edition).to_string(); if USELESS_TRAITS.contains(&name.as_str()) { return None; } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 58e9b724df2a..b537150608bb 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -85,6 +85,7 @@ impl Completions { CompletionItemKind::Keyword, ctx.source_range(), SmolStr::new_static(keyword), + ctx.edition, ); item.add_to(self, ctx.db); } @@ -124,7 +125,8 @@ impl Completions { kw: &str, snippet: &str, ) { - let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw); + let mut item = + CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw, ctx.edition); match ctx.config.snippet_cap { Some(cap) => { @@ -149,7 +151,8 @@ impl Completions { kw: &str, snippet: &str, ) { - let mut item = CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw); + let mut item = + CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), kw, ctx.edition); match ctx.config.snippet_cap { Some(cap) => item.insert_snippet(cap, snippet), @@ -544,7 +547,8 @@ impl Completions { CompletionItem::new( SymbolKind::LifetimeParam, ctx.source_range(), - name.display_no_db().to_smolstr(), + name.display_no_db(ctx.edition).to_smolstr(), + ctx.edition, ) .add_to(self, ctx.db) } @@ -553,7 +557,8 @@ impl Completions { CompletionItem::new( SymbolKind::Label, ctx.source_range(), - name.display_no_db().to_smolstr(), + name.display_no_db(ctx.edition).to_smolstr(), + ctx.edition, ) .add_to(self, ctx.db) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index a7a6cdebd361..88f4461f4ddc 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -48,11 +48,15 @@ pub(crate) fn complete_known_attribute_input( match path.text().as_str() { "repr" => repr::complete_repr(acc, ctx, tt), - "feature" => { - lint::complete_lint(acc, ctx, colon_prefix, &parse_tt_as_comma_sep_paths(tt)?, FEATURES) - } + "feature" => lint::complete_lint( + acc, + ctx, + colon_prefix, + &parse_tt_as_comma_sep_paths(tt, ctx.edition)?, + FEATURES, + ), "allow" | "warn" | "deny" | "forbid" => { - let existing_lints = parse_tt_as_comma_sep_paths(tt)?; + let existing_lints = parse_tt_as_comma_sep_paths(tt, ctx.edition)?; let lints: Vec = CLIPPY_LINT_GROUPS .iter() @@ -66,9 +70,12 @@ pub(crate) fn complete_known_attribute_input( lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints); } "cfg" => cfg::complete_cfg(acc, ctx), - "macro_use" => { - macro_use::complete_macro_use(acc, ctx, extern_crate, &parse_tt_as_comma_sep_paths(tt)?) - } + "macro_use" => macro_use::complete_macro_use( + acc, + ctx, + extern_crate, + &parse_tt_as_comma_sep_paths(tt, ctx.edition)?, + ), _ => (), } Some(()) @@ -130,8 +137,12 @@ pub(crate) fn complete_attribute_path( }); let add_completion = |attr_completion: &AttrCompletion| { - let mut item = - CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), attr_completion.label); + let mut item = CompletionItem::new( + SymbolKind::Attribute, + ctx.source_range(), + attr_completion.label, + ctx.edition, + ); if let Some(lookup) = attr_completion.lookup { item.lookup_by(lookup); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs index 6e7d50ede066..cda0da13b26e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs @@ -8,7 +8,8 @@ use crate::{completions::Completions, context::CompletionContext, CompletionItem pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { let add_completion = |item: &str| { - let mut completion = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item); + let mut completion = + CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), item, ctx.edition); completion.insert_text(format!(r#""{item}""#)); acc.add(completion.build(ctx.db)); }; @@ -41,7 +42,12 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { name => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| { let s = s.as_str(); let insert_text = format!(r#""{s}""#); - let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); + let mut item = CompletionItem::new( + SymbolKind::BuiltinAttr, + ctx.source_range(), + s, + ctx.edition, + ); item.insert_text(insert_text); acc.add(item.build(ctx.db)); @@ -49,7 +55,8 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext<'_>) { }, None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().unique().for_each(|s| { let s = s.as_str(); - let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s); + let item = + CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s, ctx.edition); acc.add(item.build(ctx.db)); }), } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs index 0127a4282488..1f8927401b2f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs @@ -62,7 +62,7 @@ pub(crate) fn complete_derive_path( _ => return acc.add_macro(ctx, path_ctx, mac, name), }; - let name_ = name.display_no_db().to_smolstr(); + let name_ = name.display_no_db(ctx.edition).to_smolstr(); let find = DEFAULT_DERIVE_DEPENDENCIES .iter() .find(|derive_completion| derive_completion.label == name_); @@ -72,10 +72,9 @@ pub(crate) fn complete_derive_path( let mut components = vec![derive_completion.label]; components.extend(derive_completion.dependencies.iter().filter( |&&dependency| { - !existing_derives - .iter() - .map(|it| it.name(ctx.db)) - .any(|it| it.display_no_db().to_smolstr() == dependency) + !existing_derives.iter().map(|it| it.name(ctx.db)).any(|it| { + it.display_no_db(ctx.edition).to_smolstr() == dependency + }) }, )); let lookup = components.join(", "); @@ -85,6 +84,7 @@ pub(crate) fn complete_derive_path( SymbolKind::Derive, ctx.source_range(), SmolStr::from_iter(label), + ctx.edition, ); if let Some(docs) = mac.docs(ctx.db) { item.documentation(docs); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs index f9dec5380646..d5f9cd5fc76c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/lint.rs @@ -54,7 +54,8 @@ pub(super) fn complete_lint( Some(qual) if !is_qualified => format!("{qual}::{name}"), _ => name.to_owned(), }; - let mut item = CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label); + let mut item = + CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition); item.documentation(Documentation::new(description.to_owned())); item.add_to(acc, ctx.db) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs index 7e3a62405a78..deb12282c025 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/macro_use.rs @@ -28,7 +28,8 @@ pub(super) fn complete_macro_use( continue; } - let item = CompletionItem::new(SymbolKind::Macro, ctx.source_range(), mac_name); + let item = + CompletionItem::new(SymbolKind::Macro, ctx.source_range(), mac_name, ctx.edition); item.add_to(acc, ctx.db); } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs index 14f464b7753d..12652b448925 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/repr.rs @@ -30,7 +30,12 @@ pub(super) fn complete_repr( continue; } - let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), label); + let mut item = CompletionItem::new( + SymbolKind::BuiltinAttr, + ctx.source_range(), + label, + ctx.edition, + ); if let Some(lookup) = lookup { item.lookup_by(lookup); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index a07daf4c4e49..d55bc3ea5d03 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -29,6 +29,7 @@ pub(crate) fn complete_dot( CompletionItemKind::Keyword, ctx.source_range(), SmolStr::new_static("await"), + ctx.edition, ); item.detail("expr.await"); item.add_to(acc, ctx.db); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs index 23d93d3b7467..c9013d1d17d4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs @@ -56,7 +56,7 @@ pub(crate) fn complete_cargo_env_vars( let range = original.text_range_between_quotes()?; CARGO_DEFINED_VARS.iter().for_each(|&(var, detail)| { - let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var); + let mut item = CompletionItem::new(CompletionItemKind::Keyword, range, var, ctx.edition); item.detail(detail); item.add_to(acc, ctx.db); }); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index b5d5604c7519..1a06e0a3a0e7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -52,8 +52,13 @@ pub(crate) fn complete_extern_abi( let abi_str = expanded; let source_range = abi_str.text_range_between_quotes()?; for &abi in SUPPORTED_CALLING_CONVENTIONS { - CompletionItem::new(CompletionItemKind::Keyword, source_range, SmolStr::new_static(abi)) - .add_to(acc, ctx.db); + CompletionItem::new( + CompletionItemKind::Keyword, + source_range, + SmolStr::new_static(abi), + ctx.edition, + ) + .add_to(acc, ctx.db); } Some(()) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs index 2427f4e49f29..7cb710c2d963 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs @@ -19,7 +19,8 @@ pub(crate) fn complete_extern_crate(acc: &mut Completions, ctx: &CompletionConte let mut item = CompletionItem::new( CompletionItemKind::SymbolKind(SymbolKind::Module), ctx.source_range(), - name.display_no_db().to_smolstr(), + name.display_no_db(ctx.edition).to_smolstr(), + ctx.edition, ); item.set_documentation(module.docs(ctx.db)); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs index fdce7c547a49..2a6b310d3a21 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs @@ -411,7 +411,7 @@ fn compute_fuzzy_completion_order_key( cov_mark::hit!(certain_fuzzy_order_test); let import_name = match proposed_mod_path.segments().last() { // FIXME: nasty alloc, this is a hot path! - Some(name) => name.display_no_db().to_smolstr().to_ascii_lowercase(), + Some(name) => name.unescaped().display_no_db().to_smolstr().to_ascii_lowercase(), None => return usize::MAX, }; match import_name.match_indices(user_input_lowercased).next() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs index a59246229bb2..ee3b817ee8cf 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/fn_param.rs @@ -32,7 +32,7 @@ pub(crate) fn complete_fn_param( let comma_wrapper = comma_wrapper(ctx); let mut add_new_item_to_acc = |label: &str| { let mk_item = |label: &str, range: TextRange| { - CompletionItem::new(CompletionItemKind::Binding, range, label) + CompletionItem::new(CompletionItemKind::Binding, range, label, ctx.edition) }; let item = match &comma_wrapper { Some((fmt, range)) => mk_item(&fmt(label), *range), @@ -50,7 +50,7 @@ pub(crate) fn complete_fn_param( ParamKind::Closure(closure) => { let stmt_list = closure.syntax().ancestors().find_map(ast::StmtList::cast)?; params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { - add_new_item_to_acc(&format!("{}: {ty}", name.display(ctx.db))); + add_new_item_to_acc(&format!("{}: {ty}", name.display(ctx.db, ctx.edition))); }); } } @@ -101,8 +101,8 @@ fn fill_fn_params( if let Some(stmt_list) = function.syntax().parent().and_then(ast::StmtList::cast) { params_from_stmt_list_scope(ctx, stmt_list, |name, ty| { file_params - .entry(format!("{}: {ty}", name.display(ctx.db))) - .or_insert(name.display(ctx.db).to_string()); + .entry(format!("{}: {ty}", name.display(ctx.db, ctx.edition))) + .or_insert(name.display(ctx.db, ctx.edition).to_string()); }); } remove_duplicated(&mut file_params, param_list.params()); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs index 23affc365920..a87c60c694ac 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs @@ -35,7 +35,8 @@ pub(crate) fn format_string( CompletionItem::new( CompletionItemKind::Binding, source_range, - name.display_no_db().to_smolstr(), + name.display_no_db(ctx.edition).to_smolstr(), + ctx.edition, ) .add_to(acc, ctx.db); }); @@ -50,7 +51,8 @@ pub(crate) fn format_string( CompletionItem::new( CompletionItemKind::SymbolKind(symbol_kind), source_range, - name.display_no_db().to_smolstr(), + name.display_no_db(ctx.edition).to_smolstr(), + ctx.edition, ) .add_to(acc, ctx.db); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index 2fd7805e60d5..fc6e1ebf05fc 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -184,7 +184,7 @@ fn add_function_impl( let label = format_smolstr!( "{}fn {}({})", if is_async { "async " } else { "" }, - fn_name.display(ctx.db), + fn_name.display(ctx.db, ctx.edition), if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." } ); @@ -194,11 +194,11 @@ fn add_function_impl( SymbolKind::Function }); - let mut item = CompletionItem::new(completion_kind, replacement_range, label); + let mut item = CompletionItem::new(completion_kind, replacement_range, label, ctx.edition); item.lookup_by(format!( "{}fn {}", if is_async { "async " } else { "" }, - fn_name.display(ctx.db) + fn_name.display(ctx.db, ctx.edition) )) .set_documentation(func.docs(ctx.db)) .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); @@ -262,7 +262,8 @@ fn add_type_alias_impl( let label = format_smolstr!("type {alias_name} ="); - let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label); + let mut item = + CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label, ctx.edition); item.lookup_by(format!("type {alias_name}")) .set_documentation(type_alias.docs(ctx.db)) .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() }); @@ -320,7 +321,7 @@ fn add_const_impl( const_: hir::Const, impl_def: hir::Impl, ) { - let const_name = const_.name(ctx.db).map(|n| n.display_no_db().to_smolstr()); + let const_name = const_.name(ctx.db).map(|n| n.display_no_db(ctx.edition).to_smolstr()); if let Some(const_name) = const_name { if let Some(source) = ctx.sema.source(const_) { @@ -334,7 +335,8 @@ fn add_const_impl( let label = make_const_compl_syntax(&transformed_const, source.file_id.is_macro()); let replacement = format!("{label} "); - let mut item = CompletionItem::new(SymbolKind::Const, replacement_range, label); + let mut item = + CompletionItem::new(SymbolKind::Const, replacement_range, label, ctx.edition); item.lookup_by(format_smolstr!("const {const_name}")) .set_documentation(const_.docs(ctx.db)) .set_relevance(CompletionRelevance { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index 03fe93c563ff..9efc52428eff 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -41,7 +41,7 @@ pub(crate) fn complete_lifetime( if matches!( res, ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) - if param_lifetime != Some(&*name.display_no_db().to_smolstr()) + if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr()) ) { acc.add_lifetime(ctx, name); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index d9a10893bf52..05e2892fdc85 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -53,7 +53,7 @@ pub(crate) fn complete_mod( let existing_mod_declarations = current_module .children(ctx.db) - .filter_map(|module| Some(module.name(ctx.db)?.display(ctx.db).to_string())) + .filter_map(|module| Some(module.name(ctx.db)?.display(ctx.db, ctx.edition).to_string())) .filter(|module| module != ctx.original_token.text()) .collect::>(); @@ -99,7 +99,8 @@ pub(crate) fn complete_mod( if mod_under_caret.semicolon_token().is_none() { label.push(';'); } - let item = CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label); + let item = + CompletionItem::new(SymbolKind::Module, ctx.source_range(), &label, ctx.edition); item.add_to(acc, ctx.db) }); @@ -140,7 +141,9 @@ fn directory_to_look_for_submodules( module_chain_to_containing_module_file(module, db) .into_iter() .filter_map(|module| module.name(db)) - .try_fold(base_directory, |path, name| path.join(&name.display_no_db().to_smolstr())) + .try_fold(base_directory, |path, name| { + path.join(&name.unescaped().display_no_db().to_smolstr()) + }) } fn module_chain_to_containing_module_file( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 977e0d80a4d4..a632f148936d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -72,7 +72,10 @@ pub(crate) fn complete_postfix( let mut item = postfix_snippet( "drop", "fn drop(&mut self)", - &format!("{path}($0{receiver_text})", path = path.display(ctx.db)), + &format!( + "{path}($0{receiver_text})", + path = path.display(ctx.db, ctx.edition) + ), ); item.set_documentation(drop_fn.docs(ctx.db)); item.add_to(acc, ctx.db); @@ -335,8 +338,12 @@ fn build_postfix_snippet_builder<'ctx>( ) -> impl Fn(&str, &str, &str) -> Builder + 'ctx { move |label, detail, snippet| { let edit = TextEdit::replace(delete_range, snippet.to_owned()); - let mut item = - CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label); + let mut item = CompletionItem::new( + CompletionItemKind::Snippet, + ctx.source_range(), + label, + ctx.edition, + ); item.detail(detail).snippet_edit(cap, edit); let postfix_match = if ctx.original_token.text() == label { cov_mark::hit!(postfix_exact_match_is_high_priority); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs index 1dcf41f8dd23..117a5e3d9359 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs @@ -73,6 +73,7 @@ pub(crate) fn complete_record_expr_fields( CompletionItemKind::Snippet, ctx.source_range(), SmolStr::new_static(".."), + ctx.edition, ); item.insert_text("."); item.add_to(acc, ctx.db); @@ -101,6 +102,7 @@ pub(crate) fn add_default_update( SymbolKind::Field, ctx.source_range(), SmolStr::new_static(completion_text), + ctx.edition, ); let completion_text = completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs index e831113350ac..357709e0c1fd 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs @@ -118,7 +118,8 @@ macro_rules! $1 { } fn snippet(ctx: &CompletionContext<'_>, cap: SnippetCap, label: &str, snippet: &str) -> Builder { - let mut item = CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label); + let mut item = + CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label, ctx.edition); item.insert_snippet(cap, snippet); item } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs index 8e5b55360dc1..45704549e609 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs @@ -107,7 +107,11 @@ pub(crate) fn complete_use_path( let item = CompletionItem::new( CompletionItemKind::SymbolKind(SymbolKind::Enum), ctx.source_range(), - format_smolstr!("{}::", e.name(ctx.db).display(ctx.db)), + format_smolstr!( + "{}::", + e.name(ctx.db).display(ctx.db, ctx.edition) + ), + ctx.edition, ); acc.add(item.build(ctx.db)); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 5b64a98a8bba..bcd9df941947 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -437,6 +437,7 @@ pub(crate) struct CompletionContext<'a> { pub(crate) module: hir::Module, /// Whether nightly toolchain is used. Cached since this is looked up a lot. is_nightly: bool, + pub(crate) edition: Edition, /// The expected name of what we are completing. /// This is usually the parameter name of the function argument we are completing. @@ -467,9 +468,9 @@ impl CompletionContext<'_> { cov_mark::hit!(completes_if_lifetime_without_idents); TextRange::at(self.original_token.text_range().start(), TextSize::from(1)) } - IDENT | LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(), - // FIXME: Edition - _ if kind.is_keyword(Edition::CURRENT) => self.original_token.text_range(), + LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(), + // We want to consider all keywords in all editions. + _ if kind.is_any_identifier() => self.original_token.text_range(), _ => TextRange::empty(self.position.offset), } } @@ -717,6 +718,7 @@ impl<'a> CompletionContext<'a> { let krate = scope.krate(); let module = scope.module(); + let edition = krate.edition(db); let toolchain = db.toolchain_channel(krate.into()); // `toolchain == None` means we're in some detached files. Since we have no information on @@ -743,6 +745,7 @@ impl<'a> CompletionContext<'a> { krate, module, is_nightly, + edition, expected_name, expected_type, qualifier_ctx, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 1e972b9b4ce0..ed359394f1c4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -1385,7 +1385,7 @@ fn pattern_context_for( }).map(|enum_| enum_.variants(sema.db)) }) }).map(|variants| variants.iter().filter_map(|variant| { - let variant_name = variant.name(sema.db).display(sema.db).to_string(); + let variant_name = variant.name(sema.db).unescaped().display(sema.db).to_string(); let variant_already_present = match_arm_list.arms().any(|arm| { arm.pat().and_then(|pat| { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index 3657a7d969b9..a30a115da1f1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -10,7 +10,7 @@ use ide_db::{ use itertools::Itertools; use smallvec::SmallVec; use stdx::{impl_from, never}; -use syntax::{format_smolstr, SmolStr, TextRange, TextSize}; +use syntax::{format_smolstr, Edition, SmolStr, TextRange, TextSize}; use text_edit::TextEdit; use crate::{ @@ -400,6 +400,7 @@ impl CompletionItem { kind: impl Into, source_range: TextRange, label: impl Into, + edition: Edition, ) -> Builder { let label = label.into(); Builder { @@ -419,6 +420,7 @@ impl CompletionItem { ref_match: None, imports_to_add: Default::default(), doc_aliases: vec![], + edition, } } @@ -464,6 +466,7 @@ pub(crate) struct Builder { trigger_call_info: bool, relevance: CompletionRelevance, ref_match: Option<(Mutability, TextSize)>, + edition: Edition, } impl Builder { @@ -517,7 +520,7 @@ impl Builder { label_detail.replace(format_smolstr!( "{} (use {})", label_detail.as_deref().unwrap_or_default(), - import_edit.import_path.display(db) + import_edit.import_path.display(db, self.edition) )); } else if let Some(trait_name) = self.trait_name { label_detail.replace(format_smolstr!( @@ -536,8 +539,8 @@ impl Builder { .into_iter() .filter_map(|import| { Some(( - import.import_path.display(db).to_string(), - import.import_path.segments().last()?.display(db).to_string(), + import.import_path.display(db, self.edition).to_string(), + import.import_path.segments().last()?.display(db, self.edition).to_string(), )) }) .collect(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index 90c1728074d4..58d1fad09504 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -245,6 +245,7 @@ pub fn resolve_completion_edits( let current_module = sema.scope(position_for_import)?.module(); let current_crate = current_module.krate(); + let current_edition = current_crate.edition(db); let new_ast = scope.clone_for_update(); let mut import_insert = TextEdit::builder(); @@ -261,9 +262,13 @@ pub fn resolve_completion_edits( .filter_map(|candidate| { current_module.find_use_path(db, candidate, config.insert_use.prefix_kind, cfg) }) - .find(|mod_path| mod_path.display(db).to_string() == full_import_path); + .find(|mod_path| mod_path.display(db, current_edition).to_string() == full_import_path); if let Some(import_path) = import { - insert_use::insert_use(&new_ast, mod_path_to_ast(&import_path), &config.insert_use); + insert_use::insert_use( + &new_ast, + mod_path_to_ast(&import_path, current_edition), + &config.insert_use, + ); } }); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index 02d667c52056..ff5ec3a29f3e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -17,7 +17,7 @@ use ide_db::{ imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind, }; -use syntax::{ast, format_smolstr, AstNode, SmolStr, SyntaxKind, TextRange, ToSmolStr}; +use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr}; use text_edit::TextEdit; use crate::{ @@ -133,19 +133,22 @@ pub(crate) fn render_field( let db = ctx.db(); let is_deprecated = ctx.is_deprecated(field); let name = field.name(db); - let (name, escaped_name) = - (name.unescaped().display(db).to_smolstr(), name.display_no_db().to_smolstr()); + let (name, escaped_name) = ( + name.unescaped().display(db).to_smolstr(), + name.display_no_db(ctx.completion.edition).to_smolstr(), + ); let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), - field_with_receiver(db, receiver.as_ref(), &name), + field_with_receiver(db, receiver.as_ref(), &name, ctx.completion.edition), + ctx.completion.edition, ); item.set_relevance(CompletionRelevance { type_match: compute_type_match(ctx.completion, ty), exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()), ..CompletionRelevance::default() }); - item.detail(ty.display(db).to_string()) + item.detail(ty.display(db, ctx.completion.edition).to_string()) .set_documentation(field.docs(db)) .set_deprecated(is_deprecated) .lookup_by(name); @@ -159,7 +162,8 @@ pub(crate) fn render_field( builder.replace( ctx.source_range(), - field_with_receiver(db, receiver.as_ref(), &escaped_name).into(), + field_with_receiver(db, receiver.as_ref(), &escaped_name, ctx.completion.edition) + .into(), ); let expected_fn_type = @@ -183,7 +187,12 @@ pub(crate) fn render_field( item.text_edit(builder.finish()); } else { - item.insert_text(field_with_receiver(db, receiver.as_ref(), &escaped_name)); + item.insert_text(field_with_receiver( + db, + receiver.as_ref(), + &escaped_name, + ctx.completion.edition, + )); } if let Some(receiver) = &dot_access.receiver { if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) { @@ -200,10 +209,11 @@ fn field_with_receiver( db: &RootDatabase, receiver: Option<&hir::Name>, field_name: &str, + edition: Edition, ) -> SmolStr { receiver.map_or_else( || field_name.into(), - |receiver| format_smolstr!("{}.{field_name}", receiver.display(db)), + |receiver| format_smolstr!("{}.{field_name}", receiver.display(db, edition)), ) } @@ -216,9 +226,16 @@ pub(crate) fn render_tuple_field( let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), - field_with_receiver(ctx.db(), receiver.as_ref(), &field.to_string()), + field_with_receiver( + ctx.db(), + receiver.as_ref(), + &field.to_string(), + ctx.completion.edition, + ), + ctx.completion.edition, ); - item.detail(ty.display(ctx.db()).to_string()).lookup_by(field.to_string()); + item.detail(ty.display(ctx.db(), ctx.completion.edition).to_string()) + .lookup_by(field.to_string()); item.build(ctx.db()) } @@ -226,8 +243,12 @@ pub(crate) fn render_type_inference( ty_string: String, ctx: &CompletionContext<'_>, ) -> CompletionItem { - let mut builder = - CompletionItem::new(CompletionItemKind::InferredType, ctx.source_range(), ty_string); + let mut builder = CompletionItem::new( + CompletionItemKind::InferredType, + ctx.source_range(), + ty_string, + ctx.edition, + ); builder.set_relevance(CompletionRelevance { is_definite: true, ..Default::default() }); builder.build(ctx.db) } @@ -296,7 +317,7 @@ pub(crate) fn render_expr( let cfg = ctx.config.import_path_config(); - let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg).ok()?; + let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.edition).ok()?; let source_range = match ctx.original_token.parent() { Some(node) => match node.ancestors().find_map(ast::Path::cast) { @@ -306,10 +327,13 @@ pub(crate) fn render_expr( None => ctx.source_range(), }; - let mut item = CompletionItem::new(CompletionItemKind::Expression, source_range, label); + let mut item = + CompletionItem::new(CompletionItemKind::Expression, source_range, label, ctx.edition); - let snippet = - format!("{}$0", expr.gen_source_code(&ctx.scope, &mut snippet_formatter, cfg).ok()?); + let snippet = format!( + "{}$0", + expr.gen_source_code(&ctx.scope, &mut snippet_formatter, cfg, ctx.edition).ok()? + ); let edit = TextEdit::replace(source_range, snippet); item.snippet_edit(ctx.config.snippet_cap?, edit); item.documentation(Documentation::new(String::from("Autogenerated expression by term search"))); @@ -396,10 +420,10 @@ fn render_resolution_path( let config = completion.config; let requires_import = import_to_add.is_some(); - let name = local_name.display_no_db().to_smolstr(); + let name = local_name.display_no_db(ctx.completion.edition).to_smolstr(); let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution); - if local_name.is_escaped() { - item.insert_text(local_name.display_no_db().to_smolstr()); + if local_name.is_escaped(completion.edition) { + item.insert_text(local_name.display_no_db(completion.edition).to_smolstr()); } // Add `<>` for generic types let type_path_no_ty_args = matches!( @@ -421,14 +445,17 @@ fn render_resolution_path( item.lookup_by(name.clone()) .label(SmolStr::from_iter([&name, "<…>"])) .trigger_call_info() - .insert_snippet(cap, format!("{}<$0>", local_name.display(db))); + .insert_snippet( + cap, + format!("{}<$0>", local_name.display(db, completion.edition)), + ); } } } let mut set_item_relevance = |ty: Type| { if !ty.is_unknown() { - item.detail(ty.display(db).to_string()); + item.detail(ty.display(db, completion.edition).to_string()); } item.set_relevance(CompletionRelevance { @@ -485,6 +512,7 @@ fn render_resolution_simple_( kind, ctx.source_range(), local_name.unescaped().display(db).to_smolstr(), + ctx.completion.edition, ); item.set_relevance(ctx.completion_relevance()) .set_documentation(scope_def_docs(db, resolution)) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs index 3bfec0de6bca..415d87c6239b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs @@ -14,11 +14,14 @@ pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option { let db = ctx.db(); let name = const_.name(db)?; - let (name, escaped_name) = - (name.unescaped().display(db).to_smolstr(), name.display(db).to_smolstr()); - let detail = const_.display(db).to_string(); + let (name, escaped_name) = ( + name.unescaped().display(db).to_smolstr(), + name.display(db, ctx.completion.edition).to_smolstr(), + ); + let detail = const_.display(db, ctx.completion.edition).to_string(); - let mut item = CompletionItem::new(SymbolKind::Const, ctx.source_range(), name); + let mut item = + CompletionItem::new(SymbolKind::Const, ctx.source_range(), name, ctx.completion.edition); item.set_documentation(ctx.docs(const_)) .set_deprecated(ctx.is_deprecated(const_) || ctx.is_deprecated_assoc_item(const_)) .detail(detail) @@ -26,7 +29,7 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option if let Some(actm) = const_.as_assoc_item(db) { if let Some(trt) = actm.container_or_implemented_trait(db) { - item.trait_name(trt.name(db).display_no_db().to_smolstr()); + item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr()); } } item.insert_text(escaped_name); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index 05b2d0ae386b..74092b53f523 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -4,7 +4,7 @@ use hir::{db::HirDatabase, AsAssocItem, HirDisplay}; use ide_db::{SnippetCap, SymbolKind}; use itertools::Itertools; use stdx::{format_to, to_lower_snake_case}; -use syntax::{format_smolstr, AstNode, SmolStr, ToSmolStr}; +use syntax::{format_smolstr, AstNode, Edition, SmolStr, ToSmolStr}; use crate::{ context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind}, @@ -62,9 +62,16 @@ fn render( receiver.unescaped().display(ctx.db()), name.unescaped().display(ctx.db()) ), - format_smolstr!("{}.{}", receiver.display(ctx.db()), name.display(ctx.db())), + format_smolstr!( + "{}.{}", + receiver.display(ctx.db(), completion.edition), + name.display(ctx.db(), completion.edition) + ), + ), + _ => ( + name.unescaped().display(db).to_smolstr(), + name.display(db, completion.edition).to_smolstr(), ), - _ => (name.unescaped().display(db).to_smolstr(), name.display(db).to_smolstr()), }; let has_self_param = func.self_param(db).is_some(); let mut item = CompletionItem::new( @@ -75,6 +82,7 @@ fn render( }), ctx.source_range(), call.clone(), + completion.edition, ); let ret_type = func.ret_type(db); @@ -141,9 +149,9 @@ fn render( } let detail = if ctx.completion.config.full_function_signatures { - detail_full(db, func) + detail_full(db, func, ctx.completion.edition) } else { - detail(db, func) + detail(db, func, ctx.completion.edition) }; item.set_documentation(ctx.docs(func)) .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func)) @@ -161,7 +169,9 @@ fn render( None => { if let Some(actm) = assoc_item { if let Some(trt) = actm.container_or_implemented_trait(db) { - item.trait_name(trt.name(db).display_no_db().to_smolstr()); + item.trait_name( + trt.name(db).display_no_db(ctx.completion.edition).to_smolstr(), + ); } } } @@ -219,7 +229,7 @@ pub(super) fn add_call_parens<'b>( params.iter().enumerate().format_with(", ", |(index, param), f| { match param.name(ctx.db) { Some(n) => { - let smol_str = n.display_no_db().to_smolstr(); + let smol_str = n.display_no_db(ctx.edition).to_smolstr(); let text = smol_str.as_str().trim_start_matches('_'); let ref_ = ref_of_param(ctx, text, param.ty()); f(&format_args!("${{{}:{ref_}{text}}}", index + offset)) @@ -238,7 +248,7 @@ pub(super) fn add_call_parens<'b>( format!( "{}(${{1:{}}}{}{})$0", escaped_name, - self_param.display(ctx.db), + self_param.display(ctx.db, ctx.edition), if params.is_empty() { "" } else { ", " }, function_params_snippet ) @@ -276,7 +286,7 @@ fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'sta "" } -fn detail(db: &dyn HirDatabase, func: hir::Function) -> String { +fn detail(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String { let mut ret_ty = func.ret_type(db); let mut detail = String::new(); @@ -293,15 +303,15 @@ fn detail(db: &dyn HirDatabase, func: hir::Function) -> String { format_to!(detail, "unsafe "); } - format_to!(detail, "fn({})", params_display(db, func)); + format_to!(detail, "fn({})", params_display(db, func, edition)); if !ret_ty.is_unit() { - format_to!(detail, " -> {}", ret_ty.display(db)); + format_to!(detail, " -> {}", ret_ty.display(db, edition)); } detail } -fn detail_full(db: &dyn HirDatabase, func: hir::Function) -> String { - let signature = format!("{}", func.display(db)); +fn detail_full(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String { + let signature = format!("{}", func.display(db, edition)); let mut detail = String::with_capacity(signature.len()); for segment in signature.split_whitespace() { @@ -315,16 +325,16 @@ fn detail_full(db: &dyn HirDatabase, func: hir::Function) -> String { detail } -fn params_display(db: &dyn HirDatabase, func: hir::Function) -> String { +fn params_display(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String { if let Some(self_param) = func.self_param(db) { let assoc_fn_params = func.assoc_fn_params(db); let params = assoc_fn_params .iter() .skip(1) // skip the self param because we are manually handling that - .map(|p| p.ty().display(db)); + .map(|p| p.ty().display(db, edition)); format!( "{}{}", - self_param.display(db), + self_param.display(db, edition), params.format_with("", |display, f| { f(&", ")?; f(&display) @@ -332,7 +342,7 @@ fn params_display(db: &dyn HirDatabase, func: hir::Function) -> String { ) } else { let assoc_fn_params = func.assoc_fn_params(db); - assoc_fn_params.iter().map(|p| p.ty().display(db)).join(", ") + assoc_fn_params.iter().map(|p| p.ty().display(db, edition)).join(", ") } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs index 27435307d508..c71356e5300f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs @@ -76,16 +76,16 @@ fn render( }; let (qualified_name, escaped_qualified_name) = ( qualified_name.unescaped().display(ctx.db()).to_string(), - qualified_name.display(ctx.db()).to_string(), + qualified_name.display(ctx.db(), completion.edition).to_string(), ); let snippet_cap = ctx.snippet_cap(); let mut rendered = match kind { StructKind::Tuple if should_add_parens => { - render_tuple_lit(db, snippet_cap, &fields, &escaped_qualified_name) + render_tuple_lit(db, snippet_cap, &fields, &escaped_qualified_name, completion.edition) } StructKind::Record if should_add_parens => { - render_record_lit(db, snippet_cap, &fields, &escaped_qualified_name) + render_record_lit(db, snippet_cap, &fields, &escaped_qualified_name, completion.edition) } _ => RenderedLiteral { literal: escaped_qualified_name.clone(), @@ -103,7 +103,10 @@ fn render( } let label = format_literal_label(&qualified_name, kind, snippet_cap); let lookup = if qualified { - format_literal_lookup(&short_qualified_name.display(ctx.db()).to_string(), kind) + format_literal_lookup( + &short_qualified_name.display(ctx.db(), completion.edition).to_string(), + kind, + ) } else { format_literal_lookup(&qualified_name, kind) }; @@ -112,6 +115,7 @@ fn render( CompletionItemKind::SymbolKind(thing.symbol_kind()), ctx.source_range(), label, + completion.edition, ); item.lookup_by(lookup); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs index de715bcbfaf9..6490171fbb48 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs @@ -46,8 +46,10 @@ fn render( ctx.source_range() }; - let (name, escaped_name) = - (name.unescaped().display(ctx.db()).to_smolstr(), name.display(ctx.db()).to_smolstr()); + let (name, escaped_name) = ( + name.unescaped().display(ctx.db()).to_smolstr(), + name.display(ctx.db(), completion.edition).to_smolstr(), + ); let docs = ctx.docs(macro_); let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default(); let is_fn_like = macro_.is_fn_like(completion.db); @@ -59,9 +61,10 @@ fn render( SymbolKind::from(macro_.kind(completion.db)), source_range, label(&ctx, needs_bang, bra, ket, &name), + completion.edition, ); item.set_deprecated(ctx.is_deprecated(macro_)) - .detail(macro_.display(completion.db).to_string()) + .detail(macro_.display(completion.db, completion.edition).to_string()) .set_documentation(docs) .set_relevance(ctx.completion_relevance()); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs index 598b8762b688..5675dfb5c6ff 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs @@ -3,7 +3,7 @@ use hir::{db::HirDatabase, Name, StructKind}; use ide_db::{documentation::HasDocs, SnippetCap}; use itertools::Itertools; -use syntax::{SmolStr, ToSmolStr}; +use syntax::{Edition, SmolStr, ToSmolStr}; use crate::{ context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext}, @@ -31,8 +31,10 @@ pub(crate) fn render_struct_pat( } let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())); - let (name, escaped_name) = - (name.unescaped().display(ctx.db()).to_smolstr(), name.display(ctx.db()).to_smolstr()); + let (name, escaped_name) = ( + name.unescaped().display(ctx.db()).to_smolstr(), + name.display(ctx.db(), ctx.completion.edition).to_smolstr(), + ); let kind = strukt.kind(ctx.db()); let label = format_literal_label(name.as_str(), kind, ctx.snippet_cap()); let lookup = format_literal_lookup(name.as_str(), kind); @@ -60,13 +62,13 @@ pub(crate) fn render_variant_pat( let (name, escaped_name) = match path { Some(path) => ( path.unescaped().display(ctx.db()).to_string().into(), - path.display(ctx.db()).to_string().into(), + path.display(ctx.db(), ctx.completion.edition).to_string().into(), ), None => { let name = local_name.unwrap_or_else(|| variant.name(ctx.db())); let it = ( name.unescaped().display(ctx.db()).to_smolstr(), - name.display(ctx.db()).to_smolstr(), + name.display(ctx.db(), ctx.completion.edition).to_smolstr(), ); it } @@ -119,7 +121,12 @@ fn build_completion( relevance.type_match = super::compute_type_match(ctx.completion, &adt_ty); } - let mut item = CompletionItem::new(CompletionItemKind::Binding, ctx.source_range(), label); + let mut item = CompletionItem::new( + CompletionItemKind::Binding, + ctx.source_range(), + label, + ctx.completion.edition, + ); item.set_documentation(ctx.docs(def)) .set_deprecated(ctx.is_deprecated(def)) .detail(&pat) @@ -142,9 +149,14 @@ fn render_pat( ) -> Option { let mut pat = match kind { StructKind::Tuple => render_tuple_as_pat(ctx.snippet_cap(), fields, name, fields_omitted), - StructKind::Record => { - render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted) - } + StructKind::Record => render_record_as_pat( + ctx.db(), + ctx.snippet_cap(), + fields, + name, + fields_omitted, + ctx.completion.edition, + ), StructKind::Unit => name.to_owned(), }; @@ -173,6 +185,7 @@ fn render_record_as_pat( fields: &[hir::Field], name: &str, fields_omitted: bool, + edition: Edition, ) -> String { let fields = fields.iter(); match snippet_cap { @@ -180,7 +193,7 @@ fn render_record_as_pat( format!( "{name} {{ {}{} }}", fields.enumerate().format_with(", ", |(idx, field), f| { - f(&format_args!("{}${}", field.name(db).display(db.upcast()), idx + 1)) + f(&format_args!("{}${}", field.name(db).display(db.upcast(), edition), idx + 1)) }), if fields_omitted { ", .." } else { "" }, name = name @@ -189,7 +202,7 @@ fn render_record_as_pat( None => { format!( "{name} {{ {}{} }}", - fields.map(|field| field.name(db).display_no_db().to_smolstr()).format(", "), + fields.map(|field| field.name(db).display_no_db(edition).to_smolstr()).format(", "), if fields_omitted { ", .." } else { "" }, name = name ) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs index b81caf24220b..09eb19201c5b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs @@ -33,14 +33,22 @@ fn render( let (name, escaped_name) = if with_eq { ( SmolStr::from_iter([&name.unescaped().display(db).to_smolstr(), " = "]), - SmolStr::from_iter([&name.display_no_db().to_smolstr(), " = "]), + SmolStr::from_iter([&name.display_no_db(ctx.completion.edition).to_smolstr(), " = "]), ) } else { - (name.unescaped().display(db).to_smolstr(), name.display_no_db().to_smolstr()) + ( + name.unescaped().display(db).to_smolstr(), + name.display_no_db(ctx.completion.edition).to_smolstr(), + ) }; - let detail = type_alias.display(db).to_string(); + let detail = type_alias.display(db, ctx.completion.edition).to_string(); - let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), name); + let mut item = CompletionItem::new( + SymbolKind::TypeAlias, + ctx.source_range(), + name, + ctx.completion.edition, + ); item.set_documentation(ctx.docs(type_alias)) .set_deprecated(ctx.is_deprecated(type_alias) || ctx.is_deprecated_assoc_item(type_alias)) .detail(detail) @@ -48,7 +56,7 @@ fn render( if let Some(actm) = type_alias.as_assoc_item(db) { if let Some(trt) = actm.container_or_implemented_trait(db) { - item.trait_name(trt.name(db).display_no_db().to_smolstr()); + item.trait_name(trt.name(db).display_no_db(ctx.completion.edition).to_smolstr()); } } item.insert_text(escaped_name); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs index ca7593c122ee..e053e299d903 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs @@ -22,21 +22,29 @@ pub(crate) fn render_union_literal( let name = local_name.unwrap_or_else(|| un.name(ctx.db())); let (qualified_name, escaped_qualified_name) = match path { - Some(p) => (p.unescaped().display(ctx.db()).to_string(), p.display(ctx.db()).to_string()), - None => { - (name.unescaped().display(ctx.db()).to_string(), name.display(ctx.db()).to_string()) - } + Some(p) => ( + p.unescaped().display(ctx.db()).to_string(), + p.display(ctx.db(), ctx.completion.edition).to_string(), + ), + None => ( + name.unescaped().display(ctx.db()).to_string(), + name.display(ctx.db(), ctx.completion.edition).to_string(), + ), }; let label = format_literal_label( - &name.display_no_db().to_smolstr(), + &name.display_no_db(ctx.completion.edition).to_smolstr(), StructKind::Record, ctx.snippet_cap(), ); - let lookup = format_literal_lookup(&name.display_no_db().to_smolstr(), StructKind::Record); + let lookup = format_literal_lookup( + &name.display_no_db(ctx.completion.edition).to_smolstr(), + StructKind::Record, + ); let mut item = CompletionItem::new( CompletionItemKind::SymbolKind(SymbolKind::Union), ctx.source_range(), label, + ctx.completion.edition, ); item.lookup_by(lookup); @@ -54,7 +62,10 @@ pub(crate) fn render_union_literal( escaped_qualified_name, fields .iter() - .map(|field| field.name(ctx.db()).display_no_db().to_smolstr()) + .map(|field| field + .name(ctx.db()) + .display_no_db(ctx.completion.edition) + .to_smolstr()) .format(",") ) } else { @@ -62,7 +73,10 @@ pub(crate) fn render_union_literal( "{} {{ {} }}", escaped_qualified_name, fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: ()", field.name(ctx.db()).display(ctx.db()))) + f(&format_args!( + "{}: ()", + field.name(ctx.db()).display(ctx.db(), ctx.completion.edition) + )) }) ) }; @@ -73,8 +87,8 @@ pub(crate) fn render_union_literal( fields.iter().format_with(", ", |field, f| { f(&format_args!( "{}: {}", - field.name(ctx.db()).display(ctx.db()), - field.ty(ctx.db()).display(ctx.db()) + field.name(ctx.db()).display(ctx.db(), ctx.completion.edition), + field.ty(ctx.db()).display(ctx.db(), ctx.completion.edition) )) }), if fields_omitted { ", .." } else { "" } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs index bc2df9e39f3d..d8516ea10786 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs @@ -4,7 +4,7 @@ use crate::context::CompletionContext; use hir::{db::HirDatabase, sym, HasAttrs, HasCrate, HasVisibility, HirDisplay, StructKind}; use ide_db::SnippetCap; use itertools::Itertools; -use syntax::SmolStr; +use syntax::{Edition, SmolStr}; /// A rendered struct, union, or enum variant, split into fields for actual /// auto-completion (`literal`, using `field: ()`) and display in the @@ -21,20 +21,29 @@ pub(crate) fn render_record_lit( snippet_cap: Option, fields: &[hir::Field], path: &str, + edition: Edition, ) -> RenderedLiteral { if snippet_cap.is_none() { return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() }; } let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| { if snippet_cap.is_some() { - f(&format_args!("{}: ${{{}:()}}", field.name(db).display(db.upcast()), idx + 1)) + f(&format_args!( + "{}: ${{{}:()}}", + field.name(db).display(db.upcast(), edition), + idx + 1 + )) } else { - f(&format_args!("{}: ()", field.name(db).display(db.upcast()))) + f(&format_args!("{}: ()", field.name(db).display(db.upcast(), edition))) } }); let types = fields.iter().format_with(", ", |field, f| { - f(&format_args!("{}: {}", field.name(db).display(db.upcast()), field.ty(db).display(db))) + f(&format_args!( + "{}: {}", + field.name(db).display(db.upcast(), edition), + field.ty(db).display(db, edition) + )) }); RenderedLiteral { @@ -50,6 +59,7 @@ pub(crate) fn render_tuple_lit( snippet_cap: Option, fields: &[hir::Field], path: &str, + edition: Edition, ) -> RenderedLiteral { if snippet_cap.is_none() { return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() }; @@ -62,7 +72,7 @@ pub(crate) fn render_tuple_lit( } }); - let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db))); + let types = fields.iter().format_with(", ", |field, f| f(&field.ty(db).display(db, edition))); RenderedLiteral { literal: format!("{path}({completions})"), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 415f2afeebbe..04ba7e1f41b6 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -17,6 +17,7 @@ mod item_list; mod pattern; mod predicate; mod proc_macros; +mod raw_identifiers; mod record; mod special; mod type_pos; @@ -105,22 +106,35 @@ pub(crate) fn completion_list_with_trigger_character( completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character) } +fn completion_list_with_config_raw( + config: CompletionConfig, + ra_fixture: &str, + include_keywords: bool, + trigger_character: Option, +) -> Vec { + // filter out all but one built-in type completion for smaller test outputs + let items = get_all_items(config, ra_fixture, trigger_character); + items + .into_iter() + .filter(|it| it.kind != CompletionItemKind::BuiltinType || it.label == "u32") + .filter(|it| include_keywords || it.kind != CompletionItemKind::Keyword) + .filter(|it| include_keywords || it.kind != CompletionItemKind::Snippet) + .sorted_by_key(|it| (it.kind, it.label.clone(), it.detail.as_ref().map(ToOwned::to_owned))) + .collect() +} + fn completion_list_with_config( config: CompletionConfig, ra_fixture: &str, include_keywords: bool, trigger_character: Option, ) -> String { - // filter out all but one built-in type completion for smaller test outputs - let items = get_all_items(config, ra_fixture, trigger_character); - let items = items - .into_iter() - .filter(|it| it.kind != CompletionItemKind::BuiltinType || it.label == "u32") - .filter(|it| include_keywords || it.kind != CompletionItemKind::Keyword) - .filter(|it| include_keywords || it.kind != CompletionItemKind::Snippet) - .sorted_by_key(|it| (it.kind, it.label.clone(), it.detail.as_ref().map(ToOwned::to_owned))) - .collect(); - render_completion_list(items) + render_completion_list(completion_list_with_config_raw( + config, + ra_fixture, + include_keywords, + trigger_character, + )) } /// Creates analysis from a multi-file fixture, returns positions marked with $0. diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs new file mode 100644 index 000000000000..bc630189edc9 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs @@ -0,0 +1,84 @@ +use base_db::SourceDatabase; +use expect_test::{expect, Expect}; +use itertools::Itertools; + +use crate::tests::{completion_list_with_config_raw, position, TEST_CONFIG}; + +fn check(ra_fixture: &str, expect: Expect) { + let completions = completion_list_with_config_raw(TEST_CONFIG, ra_fixture, true, None); + let (db, position) = position(ra_fixture); + let mut actual = db.file_text(position.file_id).to_string(); + completions + .into_iter() + .exactly_one() + .expect("more than one completion") + .text_edit + .apply(&mut actual); + expect.assert_eq(&actual); +} + +#[test] +fn keyword_since_edition_completes_without_raw_on_old_edition() { + check( + r#" +//- /a.rs crate:a edition:2015 +pub fn dyn() {} + +//- /b.rs crate:b edition:2015 deps:a new_source_root:local +fn foo() { + a::dyn$0 +"#, + expect![[r#" + fn foo() { + a::dyn()$0 + "#]], + ); + + check( + r#" +//- /a.rs crate:a edition:2018 +pub fn r#dyn() {} + +//- /b.rs crate:b edition:2015 deps:a new_source_root:local +fn foo() { + a::dyn$0 +"#, + expect![[r#" + fn foo() { + a::dyn()$0 + "#]], + ); +} + +#[test] +fn keyword_since_edition_completes_with_raw_on_new_edition() { + check( + r#" +//- /a.rs crate:a edition:2015 +pub fn dyn() {} + +//- /b.rs crate:b edition:2018 deps:a new_source_root:local +fn foo() { + a::dyn$0 +"#, + expect![[r#" + fn foo() { + a::r#dyn()$0 + "#]], + ); + + check( + r#" +//- /a.rs crate:a edition:2018 +pub fn r#dyn() {} + +//- /b.rs crate:b edition:2018 deps:a new_source_root:local +fn foo() { + a::dyn$0 +"#, + expect![[r#" + fn foo() { + a::r#dyn()$0 + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 991bef344a31..5d4b1999088a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -14,10 +14,11 @@ use hir::{ ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility, }; +use span::Edition; use stdx::{format_to, impl_from}; use syntax::{ ast::{self, AstNode}, - match_ast, SyntaxKind, SyntaxNode, SyntaxToken, ToSmolStr, + match_ast, SyntaxKind, SyntaxNode, SyntaxToken, }; use crate::documentation::{Documentation, HasDocs}; @@ -157,6 +158,7 @@ impl Definition { &self, db: &RootDatabase, famous_defs: Option<&FamousDefs<'_, '_>>, + edition: Edition, ) -> Option { let docs = match self { Definition::Macro(it) => it.docs(db), @@ -173,8 +175,8 @@ impl Definition { Definition::BuiltinType(it) => { famous_defs.and_then(|fd| { // std exposes prim_{} modules with docstrings on the root to document the builtins - let primitive_mod = format!("prim_{}", it.name().display(fd.0.db)); - let doc_owner = find_std_module(fd, &primitive_mod)?; + let primitive_mod = format!("prim_{}", it.name().display(fd.0.db, edition)); + let doc_owner = find_std_module(fd, &primitive_mod, edition)?; doc_owner.docs(fd.0.db) }) } @@ -192,13 +194,18 @@ impl Definition { let AttributeTemplate { word, list, name_value_str } = it.template(db)?; let mut docs = "Valid forms are:".to_owned(); if word { - format_to!(docs, "\n - #\\[{}]", name.display(db)); + format_to!(docs, "\n - #\\[{}]", name.display(db, edition)); } if let Some(list) = list { - format_to!(docs, "\n - #\\[{}({})]", name.display(db), list); + format_to!(docs, "\n - #\\[{}({})]", name.display(db, edition), list); } if let Some(name_value_str) = name_value_str { - format_to!(docs, "\n - #\\[{} = {}]", name.display(db), name_value_str); + format_to!( + docs, + "\n - #\\[{} = {}]", + name.display(db, edition), + name_value_str + ); } Some(Documentation::new(docs.replace('*', "\\*"))) } @@ -218,57 +225,63 @@ impl Definition { }) } - pub fn label(&self, db: &RootDatabase) -> String { + pub fn label(&self, db: &RootDatabase, edition: Edition) -> String { match *self { - Definition::Macro(it) => it.display(db).to_string(), - Definition::Field(it) => it.display(db).to_string(), - Definition::TupleField(it) => it.display(db).to_string(), - Definition::Module(it) => it.display(db).to_string(), - Definition::Function(it) => it.display(db).to_string(), - Definition::Adt(it) => it.display(db).to_string(), - Definition::Variant(it) => it.display(db).to_string(), - Definition::Const(it) => it.display(db).to_string(), - Definition::Static(it) => it.display(db).to_string(), - Definition::Trait(it) => it.display(db).to_string(), - Definition::TraitAlias(it) => it.display(db).to_string(), - Definition::TypeAlias(it) => it.display(db).to_string(), - Definition::BuiltinType(it) => it.name().display(db).to_string(), - Definition::BuiltinLifetime(it) => it.name().display(db).to_string(), + Definition::Macro(it) => it.display(db, edition).to_string(), + Definition::Field(it) => it.display(db, edition).to_string(), + Definition::TupleField(it) => it.display(db, edition).to_string(), + Definition::Module(it) => it.display(db, edition).to_string(), + Definition::Function(it) => it.display(db, edition).to_string(), + Definition::Adt(it) => it.display(db, edition).to_string(), + Definition::Variant(it) => it.display(db, edition).to_string(), + Definition::Const(it) => it.display(db, edition).to_string(), + Definition::Static(it) => it.display(db, edition).to_string(), + Definition::Trait(it) => it.display(db, edition).to_string(), + Definition::TraitAlias(it) => it.display(db, edition).to_string(), + Definition::TypeAlias(it) => it.display(db, edition).to_string(), + Definition::BuiltinType(it) => it.name().display(db, edition).to_string(), + Definition::BuiltinLifetime(it) => it.name().display(db, edition).to_string(), Definition::Local(it) => { let ty = it.ty(db); - let ty_display = ty.display_truncated(db, None); + let ty_display = ty.display_truncated(db, None, edition); let is_mut = if it.is_mut(db) { "mut " } else { "" }; if it.is_self(db) { format!("{is_mut}self: {ty_display}") } else { let name = it.name(db); let let_kw = if it.is_param(db) { "" } else { "let " }; - format!("{let_kw}{is_mut}{}: {ty_display}", name.display(db)) + format!("{let_kw}{is_mut}{}: {ty_display}", name.display(db, edition)) } } Definition::SelfType(impl_def) => { let self_ty = &impl_def.self_ty(db); match self_ty.as_adt() { - Some(it) => it.display(db).to_string(), - None => self_ty.display(db).to_string(), + Some(it) => it.display(db, edition).to_string(), + None => self_ty.display(db, edition).to_string(), } } - Definition::GenericParam(it) => it.display(db).to_string(), - Definition::Label(it) => it.name(db).display(db).to_string(), - Definition::ExternCrateDecl(it) => it.display(db).to_string(), - Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db).display(db)), - Definition::ToolModule(it) => it.name(db).display(db).to_string(), - Definition::DeriveHelper(it) => format!("derive_helper {}", it.name(db).display(db)), + Definition::GenericParam(it) => it.display(db, edition).to_string(), + Definition::Label(it) => it.name(db).display(db, edition).to_string(), + Definition::ExternCrateDecl(it) => it.display(db, edition).to_string(), + Definition::BuiltinAttr(it) => format!("#[{}]", it.name(db).display(db, edition)), + Definition::ToolModule(it) => it.name(db).display(db, edition).to_string(), + Definition::DeriveHelper(it) => { + format!("derive_helper {}", it.name(db).display(db, edition)) + } } } } -fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option { +fn find_std_module( + famous_defs: &FamousDefs<'_, '_>, + name: &str, + edition: Edition, +) -> Option { let db = famous_defs.0.db; let std_crate = famous_defs.std()?; let std_root_module = std_crate.root_module(); std_root_module.children(db).find(|module| { - module.name(db).map_or(false, |module| module.display(db).to_string() == name) + module.name(db).map_or(false, |module| module.display(db, edition).to_string() == name) }) } @@ -670,7 +683,7 @@ impl NameRefClass { hir::AssocItem::TypeAlias(it) => Some(it), _ => None, }) - .find(|alias| alias.name(sema.db).display_no_db().to_smolstr() == name_ref.text().as_str()) + .find(|alias| alias.name(sema.db).eq_ident(name_ref.text().as_str())) { return Some(NameRefClass::Definition(Definition::TypeAlias(ty))); } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs index 1a16a567f36b..ba6e50abf658 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs @@ -2,7 +2,6 @@ use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase}; use hir::{Crate, Enum, Function, Macro, Module, ScopeDef, Semantics, Trait}; -use syntax::ToSmolStr; use crate::RootDatabase; @@ -199,18 +198,14 @@ impl FamousDefs<'_, '_> { for segment in path { module = module.children(db).find_map(|child| { let name = child.name(db)?; - if name.display_no_db().to_smolstr() == segment { + if name.eq_ident(segment) { Some(child) } else { None } })?; } - let def = module - .scope(db, None) - .into_iter() - .find(|(name, _def)| name.display_no_db().to_smolstr() == trait_)? - .1; + let def = module.scope(db, None).into_iter().find(|(name, _def)| name.eq_ident(trait_))?.1; Some(def) } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs index e6638dde5d40..63c09af3d687 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/helpers.rs @@ -4,7 +4,7 @@ use std::collections::VecDeque; use base_db::SourceRootDatabase; use hir::{Crate, DescendPreference, ItemInNs, ModuleDef, Name, Semantics}; -use span::FileId; +use span::{Edition, FileId}; use syntax::{ ast::{self, make}, AstToken, SyntaxKind, SyntaxToken, ToSmolStr, TokenAtOffset, @@ -35,7 +35,7 @@ pub fn pick_token(mut tokens: TokenAtOffset) -> Option } /// Converts the mod path struct into its ast representation. -pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { +pub fn mod_path_to_ast(path: &hir::ModPath, edition: Edition) -> ast::Path { let _p = tracing::info_span!("mod_path_to_ast").entered(); let mut segments = Vec::new(); @@ -50,11 +50,9 @@ pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { hir::PathKind::Abs => is_abs = true, } - segments.extend( - path.segments().iter().map(|segment| { - make::path_segment(make::name_ref(&segment.display_no_db().to_smolstr())) - }), - ); + segments.extend(path.segments().iter().map(|segment| { + make::path_segment(make::name_ref(&segment.display_no_db(edition).to_smolstr())) + })); make::path_from_segments(segments, is_abs) } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index 1c4c15f2557d..07e197334706 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -9,7 +9,7 @@ use itertools::{EitherOrBoth, Itertools}; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::{ ast::{self, make, HasName}, - AstNode, SmolStr, SyntaxNode, ToSmolStr, + AstNode, SmolStr, SyntaxNode, }; use crate::{ @@ -459,7 +459,7 @@ fn find_import_for_segment( unresolved_first_segment: &str, ) -> Option { let segment_is_name = item_name(db, original_item) - .map(|name| name.display_no_db().to_smolstr() == unresolved_first_segment) + .map(|name| name.eq_ident(unresolved_first_segment)) .unwrap_or(false); Some(if segment_is_name { @@ -483,7 +483,7 @@ fn module_with_segment_name( }; while let Some(module) = current_module { if let Some(module_name) = module.name(db) { - if module_name.display_no_db().to_smolstr() == segment_name { + if module_name.eq_ident(segment_name) { return Some(module); } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 0afa9163e31d..49b3ca290f07 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -5,6 +5,7 @@ use either::Either; use hir::{AsAssocItem, HirDisplay, ImportPathConfig, ModuleDef, SemanticsScope}; use itertools::Itertools; use rustc_hash::FxHashMap; +use span::Edition; use syntax::{ ast::{self, make, AstNode, HasGenericArgs}, ted, NodeOrToken, SyntaxNode, @@ -146,6 +147,7 @@ impl<'a> PathTransform<'a> { let mut type_substs: FxHashMap = Default::default(); let mut const_substs: FxHashMap = Default::default(); let mut defaulted_params: Vec = Default::default(); + let target_edition = target_module.krate().edition(self.source_scope.db); self.generic_def .into_iter() .flat_map(|it| it.type_or_const_params(db)) @@ -190,7 +192,7 @@ impl<'a> PathTransform<'a> { } } (Either::Left(k), None) => { - if let Some(default) = k.default(db) { + if let Some(default) = k.default(db, target_edition) { if let Some(default) = default.expr() { const_substs.insert(k, default.syntax().clone_for_update()); defaulted_params.push(Either::Right(k)); @@ -204,7 +206,9 @@ impl<'a> PathTransform<'a> { .into_iter() .flat_map(|it| it.lifetime_params(db)) .zip(self.substs.lifetimes.clone()) - .filter_map(|(k, v)| Some((k.name(db).display(db.upcast()).to_string(), v.lifetime()?))) + .filter_map(|(k, v)| { + Some((k.name(db).display(db.upcast(), target_edition).to_string(), v.lifetime()?)) + }) .collect(); let ctx = Ctx { type_substs, @@ -213,6 +217,7 @@ impl<'a> PathTransform<'a> { target_module, source_scope: self.source_scope, same_self_type: self.target_scope.has_same_self_type(self.source_scope), + target_edition, }; ctx.transform_default_values(defaulted_params); ctx @@ -226,6 +231,7 @@ struct Ctx<'a> { target_module: hir::Module, source_scope: &'a SemanticsScope<'a>, same_self_type: bool, + target_edition: Edition, } fn preorder_rev(item: &SyntaxNode) -> impl Iterator { @@ -318,7 +324,7 @@ impl Ctx<'_> { hir::ModuleDef::Trait(trait_ref), cfg, )?; - match make::ty_path(mod_path_to_ast(&found_path)) { + match make::ty_path(mod_path_to_ast(&found_path, self.target_edition)) { ast::Type::PathType(path_ty) => Some(path_ty), _ => None, } @@ -374,7 +380,7 @@ impl Ctx<'_> { }; let found_path = self.target_module.find_path(self.source_scope.db.upcast(), def, cfg)?; - let res = mod_path_to_ast(&found_path).clone_for_update(); + let res = mod_path_to_ast(&found_path, self.target_edition).clone_for_update(); if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) { if let Some(segment) = res.segment() { let old = segment.get_or_create_generic_arg_list(); @@ -417,7 +423,9 @@ impl Ctx<'_> { cfg, )?; - if let Some(qual) = mod_path_to_ast(&found_path).qualifier() { + if let Some(qual) = + mod_path_to_ast(&found_path, self.target_edition).qualifier() + { let res = make::path_concat(qual, path_ty.path()?).clone_for_update(); ted::replace(path.syntax(), res.syntax()); return Some(()); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index 232f24282877..262eefeec00e 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -29,6 +29,7 @@ use span::{Edition, EditionedFileId, FileId, SyntaxContextId}; use stdx::{never, TupleExt}; use syntax::{ ast::{self, HasName}, + utils::is_raw_identifier, AstNode, SyntaxKind, TextRange, T, }; use text_edit::{TextEdit, TextEditBuilder}; @@ -72,6 +73,9 @@ impl Definition { sema: &Semantics<'_, RootDatabase>, new_name: &str, ) -> Result { + // We append `r#` if needed. + let new_name = new_name.trim_start_matches("r#"); + // self.krate() returns None if // self is a built-in attr, built-in type or tool module. // it is not allowed for these defs to be renamed. @@ -227,8 +231,7 @@ fn rename_mod( module: hir::Module, new_name: &str, ) -> Result { - if IdentifierKind::classify(module.krate().edition(sema.db), new_name)? != IdentifierKind::Ident - { + if IdentifierKind::classify(new_name)? != IdentifierKind::Ident { bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); } @@ -240,7 +243,6 @@ fn rename_mod( let InFile { file_id, value: def_source } = module.definition_source(sema.db); if let ModuleSource::SourceFile(..) = def_source { - let new_name = new_name.trim_start_matches("r#"); let anchor = file_id.original_file(sema.db).file_id(); let is_mod_rs = module.is_mod_rs(sema.db); @@ -289,9 +291,14 @@ fn rename_mod( .original_file_range_opt(sema.db) .map(TupleExt::head) { + let new_name = if is_raw_identifier(new_name, file_id.edition()) { + format!("r#{new_name}") + } else { + new_name.to_owned() + }; source_change.insert_source_edit( file_id.file_id(), - TextEdit::replace(file_range.range, new_name.to_owned()), + TextEdit::replace(file_range.range, new_name), ) }; } @@ -302,7 +309,10 @@ fn rename_mod( let def = Definition::Module(module); let usages = def.usages(sema).all(); let ref_edits = usages.iter().map(|(file_id, references)| { - (EditionedFileId::file_id(file_id), source_edit_from_references(references, def, new_name)) + ( + EditionedFileId::file_id(file_id), + source_edit_from_references(references, def, new_name, file_id.edition()), + ) }); source_change.extend(ref_edits); @@ -314,12 +324,7 @@ fn rename_reference( def: Definition, new_name: &str, ) -> Result { - let ident_kind = IdentifierKind::classify( - def.krate(sema.db) - .ok_or_else(|| RenameError("definition has no krate?".into()))? - .edition(sema.db), - new_name, - )?; + let ident_kind = IdentifierKind::classify(new_name)?; if matches!( def, @@ -351,7 +356,10 @@ fn rename_reference( } let mut source_change = SourceChange::default(); source_change.extend(usages.iter().map(|(file_id, references)| { - (EditionedFileId::file_id(file_id), source_edit_from_references(references, def, new_name)) + ( + EditionedFileId::file_id(file_id), + source_edit_from_references(references, def, new_name, file_id.edition()), + ) })); let mut insert_def_edit = |def| { @@ -367,7 +375,13 @@ pub fn source_edit_from_references( references: &[FileReference], def: Definition, new_name: &str, + edition: Edition, ) -> TextEdit { + let new_name = if is_raw_identifier(new_name, edition) { + format!("r#{new_name}") + } else { + new_name.to_owned() + }; let mut edit = TextEdit::builder(); // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far let mut edited_ranges = Vec::new(); @@ -383,10 +397,10 @@ pub fn source_edit_from_references( // to make special rewrites like shorthand syntax and such, so just rename the node in // the macro input FileReferenceNode::NameRef(name_ref) if name_range == range => { - source_edit_from_name_ref(&mut edit, name_ref, new_name, def) + source_edit_from_name_ref(&mut edit, name_ref, &new_name, def) } FileReferenceNode::Name(name) if name_range == range => { - source_edit_from_name(&mut edit, name, new_name) + source_edit_from_name(&mut edit, name, &new_name) } _ => false, }; @@ -394,7 +408,7 @@ pub fn source_edit_from_references( let (range, new_name) = match name { FileReferenceNode::Lifetime(_) => ( TextRange::new(range.start() + syntax::TextSize::from(1), range.end()), - new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(), + new_name.strip_prefix('\'').unwrap_or(&new_name).to_owned(), ), _ => (range, new_name.to_owned()), }; @@ -522,6 +536,13 @@ fn source_edit_from_def( def: Definition, new_name: &str, ) -> Result<(FileId, TextEdit)> { + let new_name_edition_aware = |new_name: &str, file_id: EditionedFileId| { + if is_raw_identifier(new_name, file_id.edition()) { + format!("r#{new_name}") + } else { + new_name.to_owned() + } + }; let mut edit = TextEdit::builder(); if let Definition::Local(local) = def { let mut file_id = None; @@ -536,7 +557,7 @@ fn source_edit_from_def( { Some(FileRange { file_id: file_id2, range }) => { file_id = Some(file_id2); - edit.replace(range, new_name.to_owned()); + edit.replace(range, new_name_edition_aware(new_name, file_id2)); continue; } None => { @@ -550,7 +571,9 @@ fn source_edit_from_def( // special cases required for renaming fields/locals in Record patterns if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) { if let Some(name_ref) = pat_field.name_ref() { - if new_name == name_ref.text() && pat.at_token().is_none() { + if new_name == name_ref.text().as_str().trim_start_matches("r#") + && pat.at_token().is_none() + { // Foo { field: ref mut local } -> Foo { ref mut field } // ^^^^^^ delete this // ^^^^^ replace this with `field` @@ -566,7 +589,10 @@ fn source_edit_from_def( // Foo { field: ref mut local @ local 2} -> Foo { field: ref mut new_name @ local2 } // Foo { field: ref mut local } -> Foo { field: ref mut new_name } // ^^^^^ replace this with `new_name` - edit.replace(name_range, new_name.to_owned()); + edit.replace( + name_range, + new_name_edition_aware(new_name, source.file_id), + ); } } else { // Foo { ref mut field } -> Foo { field: ref mut new_name } @@ -576,10 +602,10 @@ fn source_edit_from_def( pat.syntax().text_range().start(), format!("{}: ", pat_field.field_name().unwrap()), ); - edit.replace(name_range, new_name.to_owned()); + edit.replace(name_range, new_name_edition_aware(new_name, source.file_id)); } } else { - edit.replace(name_range, new_name.to_owned()); + edit.replace(name_range, new_name_edition_aware(new_name, source.file_id)); } } } @@ -599,7 +625,7 @@ fn source_edit_from_def( } _ => (range, new_name.to_owned()), }; - edit.replace(range, new_name); + edit.replace(range, new_name_edition_aware(&new_name, file_id)); Ok((file_id.file_id(), edit.finish())) } @@ -611,8 +637,9 @@ pub enum IdentifierKind { } impl IdentifierKind { - pub fn classify(edition: Edition, new_name: &str) -> Result { - match parser::LexedStr::single_token(edition, new_name) { + pub fn classify(new_name: &str) -> Result { + let new_name = new_name.trim_start_matches("r#"); + match parser::LexedStr::single_token(Edition::LATEST, new_name) { Some(res) => match res { (SyntaxKind::IDENT, _) => { if let Some(inner) = new_name.strip_prefix("r#") { @@ -626,6 +653,7 @@ impl IdentifierKind { (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { Ok(IdentifierKind::Lifetime) } + _ if is_raw_identifier(new_name, Edition::LATEST) => Ok(IdentifierKind::Ident), (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), }, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs index 6714e411e2f7..dd4a665e8eb4 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/insert_whitespace_into_node.rs @@ -1,5 +1,4 @@ //! Utilities for formatting macro expanded nodes until we get a proper formatter. -use span::Edition; use syntax::{ ast::make, ted::{self, Position}, @@ -132,6 +131,6 @@ pub fn insert_ws_into(syn: SyntaxNode) -> SyntaxNode { } fn is_text(k: SyntaxKind) -> bool { - // FIXME: Edition - k.is_keyword(Edition::CURRENT) || k.is_literal() || k == IDENT || k == UNDERSCORE + // Consider all keywords in all editions. + k.is_any_identifier() || k.is_literal() || k == UNDERSCORE } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs index d10a55120a32..fa82902a74d5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs @@ -457,13 +457,15 @@ impl Iterator for TreeWithDepthIterator { } /// Parses the input token tree as comma separated plain paths. -pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option> { +pub fn parse_tt_as_comma_sep_paths( + input: ast::TokenTree, + edition: Edition, +) -> Option> { let r_paren = input.r_paren_token(); let tokens = input.syntax().children_with_tokens().skip(1).map_while(|it| match it.into_token() { // seeing a keyword means the attribute is unclosed so stop parsing here - // FIXME: Edition - Some(tok) if tok.kind().is_keyword(Edition::CURRENT) => None, + Some(tok) if tok.kind().is_keyword(edition) => None, // don't include the right token tree parenthesis if it exists tok @ Some(_) if tok == r_paren => None, // only nodes that we can find are other TokenTrees, those are unexpected in this parse though diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs index 48a585bf333b..82aca50d0399 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs @@ -34,19 +34,20 @@ pub fn get_missing_assoc_items( // may share the same name as a function or constant. let mut impl_fns_consts = FxHashSet::default(); let mut impl_type = FxHashSet::default(); + let edition = imp.module(sema.db).krate().edition(sema.db); for item in imp.items(sema.db) { match item { hir::AssocItem::Function(it) => { - impl_fns_consts.insert(it.name(sema.db).display(sema.db).to_string()); + impl_fns_consts.insert(it.name(sema.db).display(sema.db, edition).to_string()); } hir::AssocItem::Const(it) => { if let Some(name) = it.name(sema.db) { - impl_fns_consts.insert(name.display(sema.db).to_string()); + impl_fns_consts.insert(name.display(sema.db, edition).to_string()); } } hir::AssocItem::TypeAlias(it) => { - impl_type.insert(it.name(sema.db).display(sema.db).to_string()); + impl_type.insert(it.name(sema.db).display(sema.db, edition).to_string()); } } } @@ -56,15 +57,14 @@ pub fn get_missing_assoc_items( .items(sema.db) .into_iter() .filter(|i| match i { - hir::AssocItem::Function(f) => { - !impl_fns_consts.contains(&f.name(sema.db).display(sema.db).to_string()) - } + hir::AssocItem::Function(f) => !impl_fns_consts + .contains(&f.name(sema.db).display(sema.db, edition).to_string()), hir::AssocItem::TypeAlias(t) => { - !impl_type.contains(&t.name(sema.db).display(sema.db).to_string()) + !impl_type.contains(&t.name(sema.db).display(sema.db, edition).to_string()) } hir::AssocItem::Const(c) => c .name(sema.db) - .map(|n| !impl_fns_consts.contains(&n.display(sema.db).to_string())) + .map(|n| !impl_fns_consts.contains(&n.display(sema.db, edition).to_string())) .unwrap_or_default(), }) .collect() @@ -116,6 +116,7 @@ mod tests { use expect_test::{expect, Expect}; use hir::FilePosition; use hir::Semantics; + use span::Edition; use syntax::ast::{self, AstNode}; use test_fixture::ChangeFixture; @@ -140,7 +141,7 @@ mod tests { sema.find_node_at_offset_with_descend(file.syntax(), position.offset).unwrap(); let trait_ = crate::traits::resolve_target_trait(&sema, &impl_block); let actual = match trait_ { - Some(trait_) => trait_.name(&db).display(&db).to_string(), + Some(trait_) => trait_.name(&db).display(&db, Edition::CURRENT).to_string(), None => String::new(), }; expect.assert_eq(&actual); @@ -155,7 +156,7 @@ mod tests { let items = crate::traits::get_missing_assoc_items(&sema, &impl_block); let actual = items .into_iter() - .map(|item| item.name(&db).unwrap().display(&db).to_string()) + .map(|item| item.name(&db).unwrap().display(&db, Edition::CURRENT).to_string()) .collect::>() .join("\n"); expect.assert_eq(&actual); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs index 5b566c5067d8..515bc418cb46 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs @@ -5,10 +5,7 @@ use std::iter; use hir::Semantics; -use syntax::{ - ast::{self, make, Pat}, - ToSmolStr, -}; +use syntax::ast::{self, make, Pat}; use crate::RootDatabase; @@ -29,7 +26,7 @@ impl TryEnum { _ => return None, }; TryEnum::ALL.iter().find_map(|&var| { - if enum_.name(sema.db).display_no_db().to_smolstr() == var.type_name() { + if enum_.name(sema.db).eq_ident(var.type_name()) { return Some(var); } None diff --git a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs index 965f432407b0..c3f0bf370690 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/use_trivial_constructor.rs @@ -1,6 +1,7 @@ //! Functionality for generating trivial constructors use hir::StructKind; +use span::Edition; use syntax::{ ast::{make, Expr, Path}, ToSmolStr, @@ -11,6 +12,7 @@ pub fn use_trivial_constructor( db: &crate::RootDatabase, path: Path, ty: &hir::Type, + edition: Edition, ) -> Option { match ty.as_adt() { Some(hir::Adt::Enum(x)) => { @@ -19,7 +21,7 @@ pub fn use_trivial_constructor( let path = make::path_qualified( path, make::path_segment(make::name_ref( - &variant.name(db).display_no_db().to_smolstr(), + &variant.name(db).display_no_db(edition).to_smolstr(), )), ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs index 05fb1c29b313..02299197b125 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -12,7 +12,7 @@ pub(crate) fn expected_function( Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0618"), - format!("expected function, found {}", d.found.display(ctx.sema.db)), + format!("expected function, found {}", d.found.display(ctx.sema.db, ctx.edition)), d.call.map(|it| it.into()), ) .experimental() diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 117088ca09c8..ccb33fed1004 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -12,7 +12,7 @@ use itertools::Itertools; use stdx::{format_to, never}; use syntax::{ ast::{self, make}, - SyntaxKind, SyntaxNode, + Edition, SyntaxKind, SyntaxNode, }; use text_edit::TextEdit; @@ -104,6 +104,7 @@ pub(crate) fn json_in_items( file_id: EditionedFileId, node: &SyntaxNode, config: &DiagnosticsConfig, + edition: Edition, ) { (|| { if node.kind() == SyntaxKind::ERROR @@ -156,7 +157,11 @@ pub(crate) fn json_in_items( config.insert_use.prefix_kind, cfg, ) { - insert_use(&scope, mod_path_to_ast(&it), &config.insert_use); + insert_use( + &scope, + mod_path_to_ast(&it, edition), + &config.insert_use, + ); } } } @@ -168,7 +173,11 @@ pub(crate) fn json_in_items( config.insert_use.prefix_kind, cfg, ) { - insert_use(&scope, mod_path_to_ast(&it), &config.insert_use); + insert_use( + &scope, + mod_path_to_ast(&it, edition), + &config.insert_use, + ); } } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index ea7908525ae1..86c237f7b5ec 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -11,7 +11,7 @@ use stdx::format_to; use syntax::{ algo, ast::{self, make}, - AstNode, SyntaxNode, SyntaxNodePtr, ToSmolStr, + AstNode, Edition, SyntaxNode, SyntaxNodePtr, ToSmolStr, }; use text_edit::TextEdit; @@ -31,7 +31,7 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Diagnostic { let mut message = String::from("missing structure fields:\n"); for field in &d.missed_fields { - format_to!(message, "- {}\n", field.display(ctx.sema.db)); + format_to!(message, "- {}\n", field.display(ctx.sema.db, ctx.edition)); } let ptr = InFile::new( @@ -134,8 +134,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option, d: &hir::MissingFields) -> Option, d: &hir::MissingFields) -> Option, d: &hir::MissingFields) -> Option ast::Type { +fn make_ty( + ty: &hir::Type, + db: &dyn HirDatabase, + module: hir::Module, + edition: Edition, +) -> ast::Type { let ty_str = match ty.as_adt() { - Some(adt) => adt.name(db).display(db.upcast()).to_string(), + Some(adt) => adt.name(db).display(db.upcast(), edition).to_string(), None => { ty.display_source_code(db, module.into(), false).ok().unwrap_or_else(|| "_".to_owned()) } @@ -223,13 +229,13 @@ fn get_default_constructor( let famous_defs = FamousDefs(&ctx.sema, krate); if has_new_func { - Some(make::ext::expr_ty_new(&make_ty(ty, ctx.sema.db, module))) + Some(make::ext::expr_ty_new(&make_ty(ty, ctx.sema.db, module, ctx.edition))) } else if ty.as_adt() == famous_defs.core_option_Option()?.ty(ctx.sema.db).as_adt() { Some(make::ext::option_none()) } else if !ty.is_array() && ty.impls_trait(ctx.sema.db, famous_defs.core_default_Default()?, &[]) { - Some(make::ext::expr_ty_default(&make_ty(ty, ctx.sema.db, module))) + Some(make::ext::expr_ty_default(&make_ty(ty, ctx.sema.db, module, ctx.edition))) } else { None } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs index fa9a6577fcf3..06c6b0f3e4c3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs @@ -8,7 +8,7 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0507"), - format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db)), + format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.edition)), d.span, ) .experimental() // spans are broken, and I'm not sure how precise we can detect copy types diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 00352266ddbd..e4b1f3ca9599 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -40,7 +40,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option DiagnosticCode::RustcHardError("E0384"), format!( "cannot mutate immutable variable `{}`", - d.local.name(ctx.sema.db).display(ctx.sema.db) + d.local.name(ctx.sema.db).display(ctx.sema.db, ctx.edition) ), d.span, ) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs index f6ed0d7226a7..fe32c590492d 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_assoc_item.rs @@ -12,7 +12,7 @@ pub(crate) fn private_assoc_item( let name = d .item .name(ctx.sema.db) - .map(|name| format!("`{}` ", name.display(ctx.sema.db))) + .map(|name| format!("`{}` ", name.display(ctx.sema.db, ctx.edition))) .unwrap_or_default(); Diagnostic::new_with_syntax_node_ptr( ctx, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs index e91e64c81b0b..237a9b87871c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs @@ -10,8 +10,8 @@ pub(crate) fn private_field(ctx: &DiagnosticsContext<'_>, d: &hir::PrivateField) DiagnosticCode::RustcHardError("E0616"), format!( "field `{}` of `{}` is private", - d.field.name(ctx.sema.db).display(ctx.sema.db), - d.field.parent_def(ctx.sema.db).name(ctx.sema.db).display(ctx.sema.db) + d.field.name(ctx.sema.db).display(ctx.sema.db, ctx.edition), + d.field.parent_def(ctx.sema.db).name(ctx.sema.db).display(ctx.sema.db, ctx.edition) ), d.expr.map(|it| it.into()), ) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs index 58d1b7f31d2f..a35b67ce9878 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs @@ -17,7 +17,7 @@ pub(crate) fn trait_impl_missing_assoc_item( hir::AssocItem::Const(_) => "`const ", hir::AssocItem::TypeAlias(_) => "`type ", })?; - f(&name.display(ctx.sema.db))?; + f(&name.display(ctx.sema.db, ctx.edition))?; f(&"`") }); Diagnostic::new( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs index 6d756484ebc0..3de51ca4a30a 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs @@ -18,11 +18,11 @@ pub(crate) fn trait_impl_redundant_assoc_item( ) -> Diagnostic { let db = ctx.sema.db; let name = d.assoc_item.0.clone(); - let redundant_assoc_item_name = name.display(db); + let redundant_assoc_item_name = name.display(db, ctx.edition); let assoc_item = d.assoc_item.1; let default_range = d.impl_.syntax_node_ptr().text_range(); - let trait_name = d.trait_.name(db).display_no_db().to_smolstr(); + let trait_name = d.trait_.name(db).display_no_db(ctx.edition).to_smolstr(); let (redundant_item_name, diagnostic_range, redundant_item_def) = match assoc_item { hir::AssocItem::Function(id) => { @@ -30,7 +30,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( ( format!("`fn {redundant_assoc_item_name}`"), function.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), - format!("\n {};", function.display(db)), + format!("\n {};", function.display(db, ctx.edition)), ) } hir::AssocItem::Const(id) => { @@ -38,7 +38,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( ( format!("`const {redundant_assoc_item_name}`"), constant.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), - format!("\n {};", constant.display(db)), + format!("\n {};", constant.display(db, ctx.edition)), ) } hir::AssocItem::TypeAlias(id) => { @@ -48,7 +48,7 @@ pub(crate) fn trait_impl_redundant_assoc_item( type_alias.source(db).map(|it| it.syntax().text_range()).unwrap_or(default_range), format!( "\n type {};", - type_alias.name(ctx.sema.db).display_no_db().to_smolstr() + type_alias.name(ctx.sema.db).display_no_db(ctx.edition).to_smolstr() ), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 6f5c68d4b5c8..5cce7c4aed56 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -40,8 +40,12 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) DiagnosticCode::RustcHardError("E0308"), format!( "expected {}, found {}", - d.expected.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId), - d.actual.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId), + d.expected + .display(ctx.sema.db, ctx.edition) + .with_closure_style(ClosureStyle::ClosureWithId), + d.actual + .display(ctx.sema.db, ctx.edition) + .with_closure_style(ClosureStyle::ClosureWithId), ), display_range, ) @@ -199,8 +203,8 @@ fn str_ref_to_owned( expr_ptr: &InFile>, acc: &mut Vec, ) -> Option<()> { - let expected = d.expected.display(ctx.sema.db); - let actual = d.actual.display(ctx.sema.db); + let expected = d.expected.display(ctx.sema.db, ctx.edition); + let actual = d.actual.display(ctx.sema.db, ctx.edition); // FIXME do this properly if expected.to_string() != "String" || actual.to_string() != "&str" { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index b4a566e31881..b5c242e1e9f8 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -26,7 +26,9 @@ pub(crate) fn typed_hole(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Di ( format!( "invalid `_` expression, expected type `{}`", - d.expected.display(ctx.sema.db).with_closure_style(ClosureStyle::ClosureWithId), + d.expected + .display(ctx.sema.db, ctx.edition) + .with_closure_style(ClosureStyle::ClosureWithId), ), fixes(ctx, d), ) @@ -69,6 +71,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option prefer_prelude: ctx.config.prefer_prelude, prefer_absolute: ctx.config.prefer_absolute, }, + ctx.edition, ) .ok() }) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs index 97943b7e8b34..6af36fb9e739 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/undeclared_label.rs @@ -9,7 +9,7 @@ pub(crate) fn undeclared_label( Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("undeclared-label"), - format!("use of undeclared label `{}`", name.display(ctx.sema.db)), + format!("use of undeclared label `{}`", name.display(ctx.sema.db, ctx.edition)), d.node.map(|it| it.into()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs index a1573bab8ae9..e0822fc5b338 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -11,7 +11,7 @@ use ide_db::{ use paths::Utf8Component; use syntax::{ ast::{self, edit::IndentLevel, HasModuleItem, HasName}, - AstNode, TextRange, ToSmolStr, + AstNode, TextRange, }; use text_edit::TextEdit; @@ -112,8 +112,7 @@ fn fixes( // shouldn't occur _ => continue 'crates, }; - match current.children.iter().find(|(name, _)| name.display_no_db().to_smolstr() == seg) - { + match current.children.iter().find(|(name, _)| name.eq_ident(seg)) { Some((_, &child)) => current = &crate_def_map[child], None => continue 'crates, } @@ -162,11 +161,7 @@ fn fixes( // try finding a parent that has an inline tree from here on let mut current = module; for s in stack.iter().rev() { - match module - .children - .iter() - .find(|(name, _)| name.display_no_db().to_smolstr() == s) - { + match module.children.iter().find(|(name, _)| name.eq_ident(s)) { Some((_, child)) => { current = &crate_def_map[*child]; } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs index 3601041fc735..bdff2417ca11 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unreachable_label.rs @@ -9,7 +9,7 @@ pub(crate) fn unreachable_label( Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcHardError("E0767"), - format!("use of unreachable label `{}`", name.display(ctx.sema.db)), + format!("use of unreachable label `{}`", name.display(ctx.sema.db, ctx.edition)), d.node.map(|it| it.into()), ) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs index eb8eea69f67f..76d624c47abf 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs @@ -36,8 +36,8 @@ pub(crate) fn unresolved_field( DiagnosticCode::RustcHardError("E0559"), format!( "no field `{}` on type `{}`{method_suffix}", - d.name.display(ctx.sema.db), - d.receiver.display(ctx.sema.db) + d.name.display(ctx.sema.db, ctx.edition), + d.receiver.display(ctx.sema.db, ctx.edition) ), adjusted_display_range(ctx, d.expr, &|expr| { Some( diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs index c8ff54cba3a7..5b596123e75f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs @@ -13,7 +13,7 @@ pub(crate) fn unresolved_macro_call( let bang = if d.is_bang { "!" } else { "" }; Diagnostic::new( DiagnosticCode::RustcHardError("unresolved-macro-call"), - format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db)), + format!("unresolved macro `{}{bang}`", d.path.display(ctx.sema.db, ctx.edition)), display_range, ) .experimental() diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 387d56b890b9..c0d038a238ba 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -30,8 +30,8 @@ pub(crate) fn unresolved_method( DiagnosticCode::RustcHardError("E0599"), format!( "no method `{}` on type `{}`{suffix}", - d.name.display(ctx.sema.db), - d.receiver.display(ctx.sema.db) + d.name.display(ctx.sema.db, ctx.edition), + d.receiver.display(ctx.sema.db, ctx.edition) ), adjusted_display_range(ctx, d.expr, &|expr| { Some( @@ -154,9 +154,10 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - }; let mut receiver_type_adt_name = - receiver_type.as_adt()?.name(db).display_no_db().to_smolstr(); + receiver_type.as_adt()?.name(db).display_no_db(ctx.edition).to_smolstr(); - let generic_parameters: Vec = receiver_type.generic_parameters(db).collect(); + let generic_parameters: Vec = + receiver_type.generic_parameters(db, ctx.edition).collect(); // if receiver should be pass as first arg in the assoc func, // we could omit generic parameters cause compiler can deduce it automatically if !need_to_take_receiver_as_first_arg && !generic_parameters.is_empty() { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs index bf19331d9fdd..c594754bd440 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -5,7 +5,7 @@ use ide_db::{ source_change::SourceChange, FileRange, RootDatabase, }; -use syntax::TextRange; +use syntax::{Edition, TextRange}; use text_edit::TextEdit; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; @@ -42,7 +42,14 @@ pub(crate) fn unused_variables( ast, ) .with_fixes(name_range.and_then(|it| { - fixes(ctx.sema.db, var_name, it.range, diagnostic_range.into(), ast.file_id.is_macro()) + fixes( + ctx.sema.db, + var_name, + it.range, + diagnostic_range.into(), + ast.file_id.is_macro(), + ctx.edition, + ) })) .experimental(), ) @@ -54,6 +61,7 @@ fn fixes( name_range: TextRange, diagnostic_range: FileRange, is_in_marco: bool, + edition: Edition, ) -> Option> { if is_in_marco { return None; @@ -63,14 +71,14 @@ fn fixes( id: AssistId("unscore_unused_variable_name", AssistKind::QuickFix), label: Label::new(format!( "Rename unused {} to _{}", - var_name.display(db), - var_name.display(db) + var_name.display(db, edition), + var_name.display(db, edition) )), group: None, target: diagnostic_range.range, source_change: Some(SourceChange::from_text_edit( diagnostic_range.file_id, - TextEdit::replace(name_range, format!("_{}", var_name.display(db))), + TextEdit::replace(name_range, format!("_{}", var_name.display(db, edition))), )), command: None, }]) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index a61c5f0cd4db..bf320794afc3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -90,7 +90,7 @@ use once_cell::sync::Lazy; use stdx::never; use syntax::{ ast::{self, AstNode}, - AstPtr, SyntaxNode, SyntaxNodePtr, TextRange, + AstPtr, Edition, SyntaxNode, SyntaxNodePtr, TextRange, }; // FIXME: Make this an enum @@ -279,6 +279,7 @@ struct DiagnosticsContext<'a> { config: &'a DiagnosticsConfig, sema: Semantics<'a, RootDatabase>, resolve: &'a AssistResolveStrategy, + edition: Edition, } impl DiagnosticsContext<'_> { @@ -359,12 +360,19 @@ pub fn semantic_diagnostics( for node in parse.syntax().descendants() { handlers::useless_braces::useless_braces(&mut res, file_id, &node); handlers::field_shorthand::field_shorthand(&mut res, file_id, &node); - handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, config); + handlers::json_is_not_rust::json_in_items( + &sema, + &mut res, + file_id, + &node, + config, + file_id.edition(), + ); } let module = sema.file_to_module_def(file_id); - let ctx = DiagnosticsContext { config, sema, resolve }; + let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition() }; let mut diags = Vec::new(); match module { @@ -490,6 +498,7 @@ pub fn semantic_diagnostics( &mut rustc_stack, &mut clippy_stack, &mut diagnostics_of_range, + ctx.edition, ); res.retain(|d| d.severity != Severity::Allow); @@ -544,6 +553,7 @@ fn handle_lint_attributes( rustc_stack: &mut FxHashMap>, clippy_stack: &mut FxHashMap>, diagnostics_of_range: &mut FxHashMap, &mut Diagnostic>, + edition: Edition, ) { let _g = tracing::info_span!("handle_lint_attributes").entered(); let file_id = sema.hir_file_for(root); @@ -552,9 +562,15 @@ fn handle_lint_attributes( match ev { syntax::WalkEvent::Enter(node) => { for attr in node.children().filter_map(ast::Attr::cast) { - parse_lint_attribute(attr, rustc_stack, clippy_stack, |stack, severity| { - stack.push(severity); - }); + parse_lint_attribute( + attr, + rustc_stack, + clippy_stack, + |stack, severity| { + stack.push(severity); + }, + edition, + ); } if let Some(it) = diagnostics_of_range.get_mut(&InFile { file_id, value: node.clone() }) @@ -591,6 +607,7 @@ fn handle_lint_attributes( rustc_stack, clippy_stack, diagnostics_of_range, + edition, ); for stack in [&mut *rustc_stack, &mut *clippy_stack] { stack.entry("__RA_EVERY_LINT".to_owned()).or_default().pop(); @@ -605,17 +622,24 @@ fn handle_lint_attributes( rustc_stack, clippy_stack, diagnostics_of_range, + edition, ); } } } syntax::WalkEvent::Leave(node) => { for attr in node.children().filter_map(ast::Attr::cast) { - parse_lint_attribute(attr, rustc_stack, clippy_stack, |stack, severity| { - if stack.pop() != Some(severity) { - never!("Mismatched serevity in walking lint attributes"); - } - }); + parse_lint_attribute( + attr, + rustc_stack, + clippy_stack, + |stack, severity| { + if stack.pop() != Some(severity) { + never!("Mismatched serevity in walking lint attributes"); + } + }, + edition, + ); } } } @@ -627,6 +651,7 @@ fn parse_lint_attribute( rustc_stack: &mut FxHashMap>, clippy_stack: &mut FxHashMap>, job: impl Fn(&mut Vec, Severity), + edition: Edition, ) { let Some((tag, args_tt)) = attr.as_simple_call() else { return; @@ -637,7 +662,7 @@ fn parse_lint_attribute( "forbid" | "deny" => Severity::Error, _ => return, }; - for lint in parse_tt_as_comma_sep_paths(args_tt).into_iter().flatten() { + for lint in parse_tt_as_comma_sep_paths(args_tt, edition).into_iter().flatten() { if let Some(lint) = lint.as_single_name_ref() { job(rustc_stack.entry(lint.to_string()).or_default(), severity); } diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index 5f6d77c064ca..6569f0f5552f 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -8,6 +8,7 @@ use crate::{ }; use hir::{FileRange, ImportPathConfig, Semantics}; use ide_db::FxHashMap; +use parser::Edition; use std::{cell::Cell, iter::Peekable}; use syntax::{ ast::{self, AstNode, AstToken, HasGenericArgs}, @@ -626,6 +627,11 @@ impl<'db, 'sema> Matcher<'db, 'sema> { match_error!("Failed to get receiver type for `{}`", expr.syntax().text()) })? .original; + let edition = self + .sema + .scope(expr.syntax()) + .map(|it| it.krate().edition(self.sema.db)) + .unwrap_or(Edition::CURRENT); // Temporary needed to make the borrow checker happy. let res = code_type .autoderef(self.sema.db) @@ -635,8 +641,8 @@ impl<'db, 'sema> Matcher<'db, 'sema> { .ok_or_else(|| { match_error!( "Pattern type `{}` didn't match code type `{}`", - pattern_type.display(self.sema.db), - code_type.display(self.sema.db) + pattern_type.display(self.sema.db, edition), + code_type.display(self.sema.db, edition) ) }); res diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs index b4b83f62da24..65756601f66a 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/replacing.rs @@ -2,6 +2,7 @@ use ide_db::{FxHashMap, FxHashSet}; use itertools::Itertools; +use parser::Edition; use syntax::{ ast::{self, AstNode, AstToken}, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, @@ -33,7 +34,7 @@ fn matches_to_edit_at_offset( for m in &matches.matches { edit_builder.replace( m.range.range.checked_sub(relative_start).unwrap(), - render_replace(db, m, file_src, rules), + render_replace(db, m, file_src, rules, m.range.file_id.edition()), ); } edit_builder.finish() @@ -54,6 +55,7 @@ struct ReplacementRenderer<'a> { // is parsed, placeholders don't get split. e.g. if a template of `$a.to_string()` results in `1 // + 2.to_string()` then the placeholder value `1 + 2` was split and needs parenthesis. placeholder_tokens_requiring_parenthesis: FxHashSet, + edition: Edition, } fn render_replace( @@ -61,6 +63,7 @@ fn render_replace( match_info: &Match, file_src: &str, rules: &[ResolvedRule], + edition: Edition, ) -> String { let rule = &rules[match_info.rule_index]; let template = rule @@ -76,6 +79,7 @@ fn render_replace( out: String::new(), placeholder_tokens_requiring_parenthesis: FxHashSet::default(), placeholder_tokens_by_range: FxHashMap::default(), + edition, }; renderer.render_node(&template.node); renderer.maybe_rerender_with_extra_parenthesis(&template.node); @@ -105,7 +109,7 @@ impl ReplacementRenderer<'_> { fn render_node(&mut self, node: &SyntaxNode) { if let Some(mod_path) = self.match_info.rendered_template_paths.get(node) { - self.out.push_str(&mod_path.display(self.db).to_string()); + self.out.push_str(&mod_path.display(self.db, self.edition).to_string()); // Emit everything except for the segment's name-ref, since we already effectively // emitted that as part of `mod_path`. if let Some(path) = ast::Path::cast(node.clone()) { diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index e9e5240897e1..cad0d06eeab1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -413,7 +413,8 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option< fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option { def.canonical_module_path(db).map(|it| { let mut path = String::new(); - it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name.display(db))); + it.flat_map(|it| it.name(db)) + .for_each(|name| format_to!(path, "{}/", name.unescaped().display(db))); path }) } @@ -588,9 +589,11 @@ fn filename_and_frag_for_def( let res = match def { Definition::Adt(adt) => match adt { - Adt::Struct(s) => format!("struct.{}.html", s.name(db).display(db.upcast())), - Adt::Enum(e) => format!("enum.{}.html", e.name(db).display(db.upcast())), - Adt::Union(u) => format!("union.{}.html", u.name(db).display(db.upcast())), + Adt::Struct(s) => { + format!("struct.{}.html", s.name(db).unescaped().display(db.upcast())) + } + Adt::Enum(e) => format!("enum.{}.html", e.name(db).unescaped().display(db.upcast())), + Adt::Union(u) => format!("union.{}.html", u.name(db).unescaped().display(db.upcast())), }, Definition::Module(m) => match m.name(db) { // `#[doc(keyword = "...")]` is internal used only by rust compiler @@ -599,34 +602,48 @@ fn filename_and_frag_for_def( Some(kw) => { format!("keyword.{}.html", kw) } - None => format!("{}/index.html", name.display(db.upcast())), + None => format!("{}/index.html", name.unescaped().display(db.upcast())), } } None => String::from("index.html"), }, - Definition::Trait(t) => format!("trait.{}.html", t.name(db).display(db.upcast())), - Definition::TraitAlias(t) => format!("traitalias.{}.html", t.name(db).display(db.upcast())), - Definition::TypeAlias(t) => format!("type.{}.html", t.name(db).display(db.upcast())), - Definition::BuiltinType(t) => format!("primitive.{}.html", t.name().display(db.upcast())), - Definition::Function(f) => format!("fn.{}.html", f.name(db).display(db.upcast())), + Definition::Trait(t) => { + format!("trait.{}.html", t.name(db).unescaped().display(db.upcast())) + } + Definition::TraitAlias(t) => { + format!("traitalias.{}.html", t.name(db).unescaped().display(db.upcast())) + } + Definition::TypeAlias(t) => { + format!("type.{}.html", t.name(db).unescaped().display(db.upcast())) + } + Definition::BuiltinType(t) => { + format!("primitive.{}.html", t.name().unescaped().display(db.upcast())) + } + Definition::Function(f) => { + format!("fn.{}.html", f.name(db).unescaped().display(db.upcast())) + } Definition::Variant(ev) => { format!( "enum.{}.html#variant.{}", - ev.parent_enum(db).name(db).display(db.upcast()), - ev.name(db).display(db.upcast()) + ev.parent_enum(db).name(db).unescaped().display(db.upcast()), + ev.name(db).unescaped().display(db.upcast()) ) } - Definition::Const(c) => format!("const.{}.html", c.name(db)?.display(db.upcast())), - Definition::Static(s) => format!("static.{}.html", s.name(db).display(db.upcast())), + Definition::Const(c) => { + format!("const.{}.html", c.name(db)?.unescaped().display(db.upcast())) + } + Definition::Static(s) => { + format!("static.{}.html", s.name(db).unescaped().display(db.upcast())) + } Definition::Macro(mac) => match mac.kind(db) { hir::MacroKind::Declarative | hir::MacroKind::BuiltIn | hir::MacroKind::Attr | hir::MacroKind::ProcMacro => { - format!("macro.{}.html", mac.name(db).display(db.upcast())) + format!("macro.{}.html", mac.name(db).unescaped().display(db.upcast())) } hir::MacroKind::Derive => { - format!("derive.{}.html", mac.name(db).display(db.upcast())) + format!("derive.{}.html", mac.name(db).unescaped().display(db.upcast())) } }, Definition::Field(field) => { @@ -639,7 +656,7 @@ fn filename_and_frag_for_def( return Some(( def, file, - Some(format!("structfield.{}", field.name(db).display(db.upcast()))), + Some(format!("structfield.{}", field.name(db).unescaped().display(db.upcast()))), )); } Definition::SelfType(impl_) => { @@ -649,7 +666,7 @@ fn filename_and_frag_for_def( return Some((adt, file, Some(String::from("impl")))); } Definition::ExternCrateDecl(it) => { - format!("{}/index.html", it.name(db).display(db.upcast())) + format!("{}/index.html", it.name(db).unescaped().display(db.upcast())) } Definition::Local(_) | Definition::GenericParam(_) @@ -679,14 +696,16 @@ fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) -> // Rustdoc makes this decision based on whether a method 'has defaultness'. // Currently this is only the case for provided trait methods. if is_trait_method && !function.has_body(db) { - format!("tymethod.{}", function.name(db).display(db.upcast())) + format!("tymethod.{}", function.name(db).unescaped().display(db.upcast())) } else { - format!("method.{}", function.name(db).display(db.upcast())) + format!("method.{}", function.name(db).unescaped().display(db.upcast())) } } AssocItem::Const(constant) => { - format!("associatedconstant.{}", constant.name(db)?.display(db.upcast())) + format!("associatedconstant.{}", constant.name(db)?.unescaped().display(db.upcast())) + } + AssocItem::TypeAlias(ty) => { + format!("associatedtype.{}", ty.name(db).unescaped().display(db.upcast())) } - AssocItem::TypeAlias(ty) => format!("associatedtype.{}", ty.name(db).display(db.upcast())), }) } diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index c8fe45c9cf0f..9788c0154423 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -3,6 +3,7 @@ use ide_db::{ helpers::pick_best_token, syntax_helpers::insert_whitespace_into_node::insert_ws_into, FileId, RootDatabase, }; +use span::Edition; use syntax::{ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T}; use crate::FilePosition; @@ -83,7 +84,14 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option< if let Some(item) = ast::Item::cast(node.clone()) { if let Some(def) = sema.resolve_attr_macro_call(&item) { break ( - def.name(db).display(db).to_string(), + def.name(db) + .display( + db, + sema.attach_first_edition(position.file_id) + .map(|it| it.edition()) + .unwrap_or(Edition::CURRENT), + ) + .to_string(), expand_macro_recur(&sema, &item)?, SyntaxKind::MACRO_ITEMS, ); diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index b1d2b34ea48d..6a6fbcb9a6b7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -44,6 +44,8 @@ pub(crate) fn goto_definition( ) -> Option>> { let sema = &Semantics::new(db); let file = sema.parse_guess_edition(file_id).syntax().clone(); + let edition = + sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { IDENT | INT_NUMBER @@ -55,7 +57,7 @@ pub(crate) fn goto_definition( | COMMENT => 4, // index and prefix ops T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] => 3, - kind if kind.is_keyword(Edition::CURRENT) => 2, + kind if kind.is_keyword(edition) => 2, T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, _ => 1, diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 946dca85d461..a88261df1063 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -11,7 +11,7 @@ use ide_db::{ }, FxHashMap, FxHashSet, RootDatabase, }; -use span::{Edition, EditionedFileId}; +use span::EditionedFileId; use syntax::{ ast::{self, HasLoopBody}, match_ast, AstNode, @@ -65,7 +65,7 @@ pub(crate) fn highlight_related( let token = pick_best_token(syntax.token_at_offset(offset), |kind| match kind { T![?] => 4, // prefer `?` when the cursor is sandwiched like in `await$0?` T![->] => 4, - kind if kind.is_keyword(Edition::CURRENT) => 3, + kind if kind.is_keyword(file_id.edition()) => 3, IDENT | INT_NUMBER => 2, T![|] => 1, _ => 0, diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 75f8ac2d2b1b..6c646cf4ee1f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -67,7 +67,11 @@ pub enum HoverAction { } impl HoverAction { - fn goto_type_from_targets(db: &RootDatabase, targets: Vec) -> Option { + fn goto_type_from_targets( + db: &RootDatabase, + targets: Vec, + edition: Edition, + ) -> Option { let targets = targets .into_iter() .filter_map(|it| { @@ -75,7 +79,8 @@ impl HoverAction { mod_path: render::path( db, it.module(db)?, - it.name(db).map(|name| name.display(db).to_string()), + it.name(db).map(|name| name.display(db, edition).to_string()), + edition, ), nav: it.try_to_nav(db)?.call_site(), }) @@ -111,10 +116,12 @@ pub(crate) fn hover( ) -> Option> { let sema = &hir::Semantics::new(db); let file = sema.parse_guess_edition(file_id).syntax().clone(); + let edition = + sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); let mut res = if range.is_empty() { - hover_simple(sema, FilePosition { file_id, offset: range.start() }, file, config) + hover_simple(sema, FilePosition { file_id, offset: range.start() }, file, config, edition) } else { - hover_ranged(sema, frange, file, config) + hover_ranged(sema, frange, file, config, edition) }?; if let HoverDocFormat::PlainText = config.format { @@ -129,6 +136,7 @@ fn hover_simple( FilePosition { file_id, offset }: FilePosition, file: SyntaxNode, config: &HoverConfig, + edition: Edition, ) -> Option> { let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind { IDENT @@ -141,7 +149,7 @@ fn hover_simple( | T![_] => 4, // index and prefix ops and closure pipe T!['['] | T![']'] | T![?] | T![*] | T![-] | T![!] | T![|] => 3, - kind if kind.is_keyword(Edition::CURRENT) => 2, + kind if kind.is_keyword(edition) => 2, T!['('] | T![')'] => 2, kind if kind.is_trivia() => 0, _ => 1, @@ -150,7 +158,7 @@ fn hover_simple( if let Some(doc_comment) = token_as_doc_comment(&original_token) { cov_mark::hit!(no_highlight_on_comment_hover); return doc_comment.get_definition_with_descend_at(sema, offset, |def, node, range| { - let res = hover_for_definition(sema, file_id, def, &node, None, config); + let res = hover_for_definition(sema, file_id, def, &node, None, config, edition); Some(RangeInfo::new(range, res)) }); } @@ -165,6 +173,7 @@ fn hover_simple( &original_token.parent()?, None, config, + edition, ); return Some(RangeInfo::new(range, res)); } @@ -240,7 +249,7 @@ fn hover_simple( .flatten() .unique_by(|&(def, _, _)| def) .map(|(def, macro_arm, node)| { - hover_for_definition(sema, file_id, def, &node, macro_arm, config) + hover_for_definition(sema, file_id, def, &node, macro_arm, config, edition) }) .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| { acc.actions.extend(actions); @@ -249,9 +258,9 @@ fn hover_simple( }) }) // try keywords - .or_else(|| descended().find_map(|token| render::keyword(sema, config, token))) + .or_else(|| descended().find_map(|token| render::keyword(sema, config, token, edition))) // try _ hovers - .or_else(|| descended().find_map(|token| render::underscore(sema, config, token))) + .or_else(|| descended().find_map(|token| render::underscore(sema, config, token, edition))) // try rest pattern hover .or_else(|| { descended().find_map(|token| { @@ -266,7 +275,7 @@ fn hover_simple( let record_pat = record_pat_field_list.syntax().parent().and_then(ast::RecordPat::cast)?; - Some(render::struct_rest_pat(sema, config, &record_pat)) + Some(render::struct_rest_pat(sema, config, &record_pat, edition)) }) }) // try () call hovers @@ -283,7 +292,7 @@ fn hover_simple( _ => return None, } }; - render::type_info_of(sema, config, &Either::Left(call_expr)) + render::type_info_of(sema, config, &Either::Left(call_expr), edition) }) }) // try closure @@ -293,12 +302,12 @@ fn hover_simple( return None; } let c = token.parent().and_then(|x| x.parent()).and_then(ast::ClosureExpr::cast)?; - render::closure_expr(sema, config, c) + render::closure_expr(sema, config, c, edition) }) }) // tokens .or_else(|| { - render::literal(sema, original_token.clone()) + render::literal(sema, original_token.clone(), edition) .map(|markup| HoverResult { markup, actions: vec![] }) }); @@ -313,6 +322,7 @@ fn hover_ranged( FileRange { range, .. }: FileRange, file: SyntaxNode, config: &HoverConfig, + edition: Edition, ) -> Option> { // FIXME: make this work in attributes let expr_or_pat = file @@ -321,15 +331,17 @@ fn hover_ranged( .take_while(|it| ast::MacroCall::can_cast(it.kind()) || !ast::Item::can_cast(it.kind())) .find_map(Either::::cast)?; let res = match &expr_or_pat { - Either::Left(ast::Expr::TryExpr(try_expr)) => render::try_expr(sema, config, try_expr), + Either::Left(ast::Expr::TryExpr(try_expr)) => { + render::try_expr(sema, config, try_expr, edition) + } Either::Left(ast::Expr::PrefixExpr(prefix_expr)) if prefix_expr.op_kind() == Some(ast::UnaryOp::Deref) => { - render::deref_expr(sema, config, prefix_expr) + render::deref_expr(sema, config, prefix_expr, edition) } _ => None, }; - let res = res.or_else(|| render::type_info_of(sema, config, &expr_or_pat)); + let res = res.or_else(|| render::type_info_of(sema, config, &expr_or_pat, edition)); res.map(|it| { let range = match expr_or_pat { Either::Left(it) => it.syntax().text_range(), @@ -347,6 +359,7 @@ pub(crate) fn hover_for_definition( scope_node: &SyntaxNode, macro_arm: Option, config: &HoverConfig, + edition: Edition, ) -> HoverResult { let famous_defs = match &def { Definition::BuiltinType(_) => sema.scope(scope_node).map(|it| FamousDefs(sema, it.krate())), @@ -370,15 +383,22 @@ pub(crate) fn hover_for_definition( }; let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default(); - let markup = - render::definition(sema.db, def, famous_defs.as_ref(), ¬able_traits, macro_arm, config); + let markup = render::definition( + sema.db, + def, + famous_defs.as_ref(), + ¬able_traits, + macro_arm, + config, + edition, + ); HoverResult { markup: render::process_markup(sema.db, def, &markup, config), actions: [ show_fn_references_action(sema.db, def), show_implementations_action(sema.db, def), runnable_action(sema, def, file_id), - goto_type_action_for_def(sema.db, def, ¬able_traits), + goto_type_action_for_def(sema.db, def, ¬able_traits, edition), ] .into_iter() .flatten() @@ -470,6 +490,7 @@ fn goto_type_action_for_def( db: &RootDatabase, def: Definition, notable_traits: &[(hir::Trait, Vec<(Option, hir::Name)>)], + edition: Edition, ) -> Option { let mut targets: Vec = Vec::new(); let mut push_new_def = |item: hir::ModuleDef| { @@ -500,13 +521,13 @@ fn goto_type_action_for_def( Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db), Definition::Field(field) => field.ty(db), Definition::Function(function) => function.ret_type(db), - _ => return HoverAction::goto_type_from_targets(db, targets), + _ => return HoverAction::goto_type_from_targets(db, targets, edition), }; walk_and_push_ty(db, &ty, &mut push_new_def); } - HoverAction::goto_type_from_targets(db, targets) + HoverAction::goto_type_from_targets(db, targets, edition) } fn walk_and_push_ty( diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 13b7ba1e2ba8..3e41b42be44b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -35,27 +35,30 @@ pub(super) fn type_info_of( sema: &Semantics<'_, RootDatabase>, _config: &HoverConfig, expr_or_pat: &Either, + edition: Edition, ) -> Option { let ty_info = match expr_or_pat { Either::Left(expr) => sema.type_of_expr(expr)?, Either::Right(pat) => sema.type_of_pat(pat)?, }; - type_info(sema, _config, ty_info) + type_info(sema, _config, ty_info, edition) } pub(super) fn closure_expr( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, c: ast::ClosureExpr, + edition: Edition, ) -> Option { let TypeInfo { original, .. } = sema.type_of_expr(&c.into())?; - closure_ty(sema, config, &TypeInfo { original, adjusted: None }) + closure_ty(sema, config, &TypeInfo { original, adjusted: None }, edition) } pub(super) fn try_expr( sema: &Semantics<'_, RootDatabase>, _config: &HoverConfig, try_expr: &ast::TryExpr, + edition: Edition, ) -> Option { let inner_ty = sema.type_of_expr(&try_expr.expr()?)?.original; let mut ancestors = try_expr.syntax().ancestors(); @@ -118,12 +121,12 @@ pub(super) fn try_expr( }; walk_and_push_ty(sema.db, &inner_ty, &mut push_new_def); walk_and_push_ty(sema.db, &body_ty, &mut push_new_def); - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) { res.actions.push(actions); } - let inner_ty = inner_ty.display(sema.db).to_string(); - let body_ty = body_ty.display(sema.db).to_string(); + let inner_ty = inner_ty.display(sema.db, edition).to_string(); + let body_ty = body_ty.display(sema.db, edition).to_string(); let ty_len_max = inner_ty.len().max(body_ty.len()); let l = "Propagated as: ".len() - " Type: ".len(); @@ -147,6 +150,7 @@ pub(super) fn deref_expr( sema: &Semantics<'_, RootDatabase>, _config: &HoverConfig, deref_expr: &ast::PrefixExpr, + edition: Edition, ) -> Option { let inner_ty = sema.type_of_expr(&deref_expr.expr()?)?.original; let TypeInfo { original, adjusted } = @@ -164,9 +168,9 @@ pub(super) fn deref_expr( res.markup = if let Some(adjusted_ty) = adjusted { walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def); - let original = original.display(sema.db).to_string(); - let adjusted = adjusted_ty.display(sema.db).to_string(); - let inner = inner_ty.display(sema.db).to_string(); + let original = original.display(sema.db, edition).to_string(); + let adjusted = adjusted_ty.display(sema.db, edition).to_string(); + let inner = inner_ty.display(sema.db, edition).to_string(); let type_len = "To type: ".len(); let coerced_len = "Coerced to: ".len(); let deref_len = "Dereferenced from: ".len(); @@ -184,8 +188,8 @@ pub(super) fn deref_expr( ) .into() } else { - let original = original.display(sema.db).to_string(); - let inner = inner_ty.display(sema.db).to_string(); + let original = original.display(sema.db, edition).to_string(); + let inner = inner_ty.display(sema.db, edition).to_string(); let type_len = "To type: ".len(); let deref_len = "Dereferenced from: ".len(); let max_len = (original.len() + type_len).max(inner.len() + deref_len); @@ -198,7 +202,7 @@ pub(super) fn deref_expr( ) .into() }; - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) { res.actions.push(actions); } @@ -209,6 +213,7 @@ pub(super) fn underscore( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, token: &SyntaxToken, + edition: Edition, ) -> Option { if token.kind() != T![_] { return None; @@ -217,8 +222,8 @@ pub(super) fn underscore( let _it = match_ast! { match parent { ast::InferType(it) => it, - ast::UnderscoreExpr(it) => return type_info_of(sema, config, &Either::Left(ast::Expr::UnderscoreExpr(it))), - ast::WildcardPat(it) => return type_info_of(sema, config, &Either::Right(ast::Pat::WildcardPat(it))), + ast::UnderscoreExpr(it) => return type_info_of(sema, config, &Either::Left(ast::Expr::UnderscoreExpr(it)),edition), + ast::WildcardPat(it) => return type_info_of(sema, config, &Either::Right(ast::Pat::WildcardPat(it)),edition), _ => return None, } }; @@ -251,16 +256,18 @@ pub(super) fn keyword( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, token: &SyntaxToken, + edition: Edition, ) -> Option { - if !token.kind().is_keyword(Edition::CURRENT) || !config.documentation || !config.keywords { + if !token.kind().is_keyword(edition) || !config.documentation || !config.keywords { return None; } let parent = token.parent()?; let famous_defs = FamousDefs(sema, sema.scope(&parent)?.krate()); - let KeywordHint { description, keyword_mod, actions } = keyword_hints(sema, token, parent); + let KeywordHint { description, keyword_mod, actions } = + keyword_hints(sema, token, parent, edition); - let doc_owner = find_std_module(&famous_defs, &keyword_mod)?; + let doc_owner = find_std_module(&famous_defs, &keyword_mod, edition)?; let docs = doc_owner.docs(sema.db)?; let markup = process_markup( sema.db, @@ -278,6 +285,7 @@ pub(super) fn struct_rest_pat( sema: &Semantics<'_, RootDatabase>, _config: &HoverConfig, pattern: &ast::RecordPat, + edition: Edition, ) -> HoverResult { let missing_fields = sema.record_pattern_missing_fields(pattern); @@ -299,7 +307,7 @@ pub(super) fn struct_rest_pat( res.markup = { let mut s = String::from(".., "); for (f, _) in &missing_fields { - s += f.display(sema.db).to_string().as_ref(); + s += f.display(sema.db, edition).to_string().as_ref(); s += ", "; } // get rid of trailing comma @@ -307,7 +315,7 @@ pub(super) fn struct_rest_pat( Markup::fenced_block(&s) }; - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) { res.actions.push(actions); } res @@ -366,7 +374,7 @@ pub(super) fn process_markup( Markup::from(markup) } -fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option { +fn definition_owner_name(db: &RootDatabase, def: &Definition, edition: Edition) -> Option { match def { Definition::Field(f) => Some(f.parent_def(db).name(db)), Definition::Local(l) => l.parent(db).name(db), @@ -385,17 +393,22 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option } } } - .map(|name| name.display(db).to_string()) + .map(|name| name.display(db, edition).to_string()) } -pub(super) fn path(db: &RootDatabase, module: hir::Module, item_name: Option) -> String { +pub(super) fn path( + db: &RootDatabase, + module: hir::Module, + item_name: Option, + edition: Edition, +) -> String { let crate_name = db.crate_graph()[module.krate().into()].display_name.as_ref().map(|it| it.to_string()); let module_path = module .path_to_root(db) .into_iter() .rev() - .flat_map(|it| it.name(db).map(|name| name.display(db).to_string())); + .flat_map(|it| it.name(db).map(|name| name.display(db, edition).to_string())); crate_name.into_iter().chain(module_path).chain(item_name).join("::") } @@ -406,39 +419,42 @@ pub(super) fn definition( notable_traits: &[(Trait, Vec<(Option, Name)>)], macro_arm: Option, config: &HoverConfig, + edition: Edition, ) -> Markup { - let mod_path = definition_mod_path(db, &def); + let mod_path = definition_mod_path(db, &def, edition); let label = match def { Definition::Trait(trait_) => { - trait_.display_limited(db, config.max_trait_assoc_items_count).to_string() + trait_.display_limited(db, config.max_trait_assoc_items_count, edition).to_string() } Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => { - adt.display_limited(db, config.max_fields_count).to_string() + adt.display_limited(db, config.max_fields_count, edition).to_string() } Definition::Variant(variant) => { - variant.display_limited(db, config.max_fields_count).to_string() + variant.display_limited(db, config.max_fields_count, edition).to_string() } Definition::Adt(adt @ Adt::Enum(_)) => { - adt.display_limited(db, config.max_enum_variants_count).to_string() + adt.display_limited(db, config.max_enum_variants_count, edition).to_string() } Definition::SelfType(impl_def) => { let self_ty = &impl_def.self_ty(db); match self_ty.as_adt() { - Some(adt) => adt.display_limited(db, config.max_fields_count).to_string(), - None => self_ty.display(db).to_string(), + Some(adt) => adt.display_limited(db, config.max_fields_count, edition).to_string(), + None => self_ty.display(db, edition).to_string(), } } Definition::Macro(it) => { - let mut label = it.display(db).to_string(); + let mut label = it.display(db, edition).to_string(); if let Some(macro_arm) = macro_arm { format_to!(label, " // matched arm #{}", macro_arm); } label } - Definition::Function(fn_) => fn_.display_with_container_bounds(db, true).to_string(), - _ => def.label(db), + Definition::Function(fn_) => { + fn_.display_with_container_bounds(db, true, edition).to_string() + } + _ => def.label(db, edition), }; - let docs = def.docs(db, famous_defs); + let docs = def.docs(db, famous_defs, edition); let value = (|| match def { Definition::Variant(it) => { if !it.parent_enum(db).is_data_carrying(db) { @@ -453,7 +469,7 @@ pub(super) fn definition( } } Definition::Const(it) => { - let body = it.render_eval(db); + let body = it.render_eval(db, edition); match body { Ok(it) => Some(it), Err(_) => { @@ -511,7 +527,7 @@ pub(super) fn definition( }; let mut desc = String::new(); - if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits) { + if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits, edition) { desc.push_str(¬able_traits); desc.push('\n'); } @@ -528,7 +544,11 @@ pub(super) fn definition( markup(docs.map(Into::into), desc, mod_path) } -pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { +pub(super) fn literal( + sema: &Semantics<'_, RootDatabase>, + token: SyntaxToken, + edition: Edition, +) -> Option { let lit = token.parent().and_then(ast::Literal::cast)?; let ty = if let Some(p) = lit.syntax().parent().and_then(ast::Pat::cast) { sema.type_of_pat(&p)? @@ -575,7 +595,7 @@ pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> _ => return None } }; - let ty = ty.display(sema.db); + let ty = ty.display(sema.db, edition); let mut s = format!("```rust\n{ty}\n```\n___\n\n"); match value { @@ -594,6 +614,7 @@ pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> fn render_notable_trait_comment( db: &RootDatabase, notable_traits: &[(Trait, Vec<(Option, Name)>)], + edition: Edition, ) -> Option { let mut desc = String::new(); let mut needs_impl_header = true; @@ -603,17 +624,17 @@ fn render_notable_trait_comment( } else { ", " }); - format_to!(desc, "{}", trait_.name(db).display(db),); + format_to!(desc, "{}", trait_.name(db).display(db, edition)); if !assoc_types.is_empty() { desc.push('<'); format_to!( desc, "{}", assoc_types.iter().format_with(", ", |(ty, name), f| { - f(&name.display(db))?; + f(&name.display(db, edition))?; f(&" = ")?; match ty { - Some(ty) => f(&ty.display(db)), + Some(ty) => f(&ty.display(db, edition)), None => f(&"?"), } }) @@ -628,8 +649,9 @@ fn type_info( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, ty: TypeInfo, + edition: Edition, ) -> Option { - if let Some(res) = closure_ty(sema, config, &ty) { + if let Some(res) = closure_ty(sema, config, &ty, edition) { return Some(res); }; let db = sema.db; @@ -655,17 +677,17 @@ fn type_info( } else { ", " }); - format_to!(desc, "{}", trait_.name(db).display(db),); + format_to!(desc, "{}", trait_.name(db).display(db, edition)); if !assoc_types.is_empty() { desc.push('<'); format_to!( desc, "{}", assoc_types.into_iter().format_with(", ", |(ty, name), f| { - f(&name.display(db))?; + f(&name.display(db, edition))?; f(&" = ")?; match ty { - Some(ty) => f(&ty.display(db)), + Some(ty) => f(&ty.display(db, edition)), None => f(&"?"), } }) @@ -679,8 +701,8 @@ fn type_info( desc }; - let original = original.display(db).to_string(); - let adjusted = adjusted_ty.display(db).to_string(); + let original = original.display(db, edition).to_string(); + let adjusted = adjusted_ty.display(db, edition).to_string(); let static_text_diff_len = "Coerced to: ".len() - "Type: ".len(); format!( "```text\nType: {:>apad$}\nCoerced to: {:>opad$}\n{notable}```\n", @@ -691,14 +713,15 @@ fn type_info( ) .into() } else { - let mut desc = match render_notable_trait_comment(db, ¬able_traits(db, &original)) { - Some(desc) => desc + "\n", - None => String::new(), - }; - format_to!(desc, "{}", original.display(db)); + let mut desc = + match render_notable_trait_comment(db, ¬able_traits(db, &original), edition) { + Some(desc) => desc + "\n", + None => String::new(), + }; + format_to!(desc, "{}", original.display(db, edition)); Markup::fenced_block(&desc) }; - if let Some(actions) = HoverAction::goto_type_from_targets(db, targets) { + if let Some(actions) = HoverAction::goto_type_from_targets(db, targets, edition) { res.actions.push(actions); } Some(res) @@ -708,6 +731,7 @@ fn closure_ty( sema: &Semantics<'_, RootDatabase>, config: &HoverConfig, TypeInfo { original, adjusted }: &TypeInfo, + edition: Edition, ) -> Option { let c = original.as_closure()?; let mut captures_rendered = c.captured_items(sema.db) @@ -740,12 +764,12 @@ fn closure_ty( walk_and_push_ty(sema.db, adjusted_ty, &mut push_new_def); format!( "\nCoerced to: {}", - adjusted_ty.display(sema.db).with_closure_style(hir::ClosureStyle::ImplFn) + adjusted_ty.display(sema.db, edition).with_closure_style(hir::ClosureStyle::ImplFn) ) } else { String::new() }; - let mut markup = format!("```rust\n{}", c.display_with_id(sema.db),); + let mut markup = format!("```rust\n{}", c.display_with_id(sema.db, edition)); if let Some(layout) = render_memory_layout(config.memory_layout, || original.layout(sema.db), |_| None, |_| None) @@ -758,23 +782,23 @@ fn closure_ty( format_to!( markup, "\n{}\n```{adjusted}\n\n## Captures\n{}", - c.display_with_impl(sema.db), + c.display_with_impl(sema.db, edition), captures_rendered, ); let mut res = HoverResult::default(); - if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) { + if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets, edition) { res.actions.push(actions); } res.markup = markup.into(); Some(res) } -fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option { +fn definition_mod_path(db: &RootDatabase, def: &Definition, edition: Edition) -> Option { if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) { return None; } - def.module(db).map(|module| path(db, module, definition_owner_name(db, def))) + def.module(db).map(|module| path(db, module, definition_owner_name(db, def, edition), edition)) } fn markup(docs: Option, desc: String, mod_path: Option) -> Markup { @@ -793,12 +817,16 @@ fn markup(docs: Option, desc: String, mod_path: Option) -> Marku buf.into() } -fn find_std_module(famous_defs: &FamousDefs<'_, '_>, name: &str) -> Option { +fn find_std_module( + famous_defs: &FamousDefs<'_, '_>, + name: &str, + edition: Edition, +) -> Option { let db = famous_defs.0.db; let std_crate = famous_defs.std()?; let std_root_module = std_crate.root_module(); std_root_module.children(db).find(|module| { - module.name(db).map_or(false, |module| module.display(db).to_string() == name) + module.name(db).map_or(false, |module| module.display(db, edition).to_string() == name) }) } @@ -889,6 +917,7 @@ fn keyword_hints( sema: &Semantics<'_, RootDatabase>, token: &SyntaxToken, parent: syntax::SyntaxNode, + edition: Edition, ) -> KeywordHint { match token.kind() { T![await] | T![loop] | T![match] | T![unsafe] | T![as] | T![try] | T![if] | T![else] => { @@ -906,12 +935,12 @@ fn keyword_hints( walk_and_push_ty(sema.db, &ty.original, &mut push_new_def); let ty = ty.adjusted(); - let description = format!("{}: {}", token.text(), ty.display(sema.db)); + let description = format!("{}: {}", token.text(), ty.display(sema.db, edition)); KeywordHint { description, keyword_mod, - actions: HoverAction::goto_type_from_targets(sema.db, targets) + actions: HoverAction::goto_type_from_targets(sema.db, targets, edition) .into_iter() .collect(), } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 18f0aeba29ea..8b60e562d7b8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -8630,3 +8630,75 @@ fn main() { "#]], ); } + +#[test] +fn raw_keyword_different_editions() { + check( + r#" +//- /lib1.rs crate:with_edition_2015 edition:2015 +pub fn dyn() {} + +//- /lib2.rs crate:with_edition_2018 edition:2018 deps:with_edition_2015 new_source_root:local +fn foo() { + with_edition_2015::r#dyn$0(); +} + "#, + expect![[r#" + *r#dyn* + + ```rust + with_edition_2015 + ``` + + ```rust + pub fn r#dyn() + ``` + "#]], + ); + + check( + r#" +//- /lib1.rs crate:with_edition_2018 edition:2018 +pub fn r#dyn() {} + +//- /lib2.rs crate:with_edition_2015 edition:2015 deps:with_edition_2018 new_source_root:local +fn foo() { + with_edition_2018::dyn$0(); +} + "#, + expect![[r#" + *dyn* + + ```rust + with_edition_2018 + ``` + + ```rust + pub fn dyn() + ``` + "#]], + ); + + check( + r#" +//- /lib1.rs crate:escaping_needlessly edition:2015 +pub fn r#dyn() {} + +//- /lib2.rs crate:dependent edition:2015 deps:escaping_needlessly new_source_root:local +fn foo() { + escaping_needlessly::dyn$0(); +} + "#, + expect![[r#" + *dyn* + + ```rust + escaping_needlessly + ``` + + ```rust + pub fn dyn() + ``` + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 0a8d2727575d..6a5d5e26a4f0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -11,7 +11,7 @@ use hir::{ use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase}; use itertools::Itertools; use smallvec::{smallvec, SmallVec}; -use span::EditionedFileId; +use span::{Edition, EditionedFileId}; use stdx::never; use syntax::{ ast::{self, AstNode}, @@ -372,6 +372,7 @@ fn label_of_ty( famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, ty: &hir::Type, + edition: Edition, ) -> Option { fn rec( sema: &Semantics<'_, RootDatabase>, @@ -380,6 +381,7 @@ fn label_of_ty( ty: &hir::Type, label_builder: &mut InlayHintLabelBuilder<'_>, config: &InlayHintsConfig, + edition: Edition, ) -> Result<(), HirDisplayError> { let iter_item_type = hint_iterator(sema, famous_defs, ty); match iter_item_type { @@ -410,12 +412,12 @@ fn label_of_ty( label_builder.write_str(LABEL_ITEM)?; label_builder.end_location_link(); label_builder.write_str(LABEL_MIDDLE2)?; - rec(sema, famous_defs, max_length, &ty, label_builder, config)?; + rec(sema, famous_defs, max_length, &ty, label_builder, config, edition)?; label_builder.write_str(LABEL_END)?; Ok(()) } None => ty - .display_truncated(sema.db, max_length) + .display_truncated(sema.db, max_length, edition) .with_closure_style(config.closure_style) .write_to(label_builder), } @@ -427,7 +429,7 @@ fn label_of_ty( location: None, result: InlayHintLabel::default(), }; - let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config); + let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, edition); let r = label_builder.finish(); Some(r) } @@ -569,7 +571,7 @@ fn hints( match node { ast::Expr(expr) => { chaining::hints(hints, famous_defs, config, file_id, &expr); - adjustment::hints(hints, sema, config, &expr); + adjustment::hints(hints, sema, config, file_id, &expr); match expr { ast::Expr::CallExpr(it) => param_name::hints(hints, sema, config, ast::Expr::from(it)), ast::Expr::MethodCallExpr(it) => { @@ -600,7 +602,7 @@ fn hints( // FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints ast::Item::Impl(_) => None, ast::Item::Fn(it) => { - implicit_drop::hints(hints, sema, config, &it); + implicit_drop::hints(hints, sema, config, file_id, &it); fn_lifetime_fn::hints(hints, config, it) }, // static type elisions diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 7932d8efbcf1..756198d0c011 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -10,6 +10,7 @@ use hir::{ }; use ide_db::RootDatabase; +use span::EditionedFileId; use stdx::never; use syntax::{ ast::{self, make, AstNode}, @@ -25,6 +26,7 @@ pub(super) fn hints( acc: &mut Vec, sema: &Semantics<'_, RootDatabase>, config: &InlayHintsConfig, + file_id: EditionedFileId, expr: &ast::Expr, ) -> Option<()> { if config.adjustment_hints_hide_outside_unsafe && !sema.is_inside_unsafe(expr) { @@ -141,8 +143,8 @@ pub(super) fn hints( if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, Some(InlayTooltip::Markdown(format!( "`{}` → `{}` ({coercion} coercion)", - source.display(sema.db), - target.display(sema.db), + source.display(sema.db, file_id.edition()), + target.display(sema.db, file_id.edition()), ))), None, ); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 7310852b8ed5..d67afe14d7c9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -22,7 +22,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + file_id: EditionedFileId, pat: &ast::IdentPat, ) -> Option<()> { if !config.type_hints { @@ -67,7 +67,7 @@ pub(super) fn hints( return None; } - let mut label = label_of_ty(famous_defs, config, &ty)?; + let mut label = label_of_ty(famous_defs, config, &ty, file_id.edition())?; if config.hide_named_constructor_hints && is_named_constructor(sema, pat, &label.to_string()).is_some() diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index 4e15213b8bbf..35f4d46e187c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -14,7 +14,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + file_id: EditionedFileId, expr: &ast::Expr, ) -> Option<()> { if !config.chaining_hints { @@ -58,7 +58,7 @@ pub(super) fn hints( } } } - let label = label_of_ty(famous_defs, config, &ty)?; + let label = label_of_ty(famous_defs, config, &ty, file_id.edition())?; acc.push(InlayHint { range: expr.syntax().text_range(), kind: InlayKind::Chaining, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index 8f2777f3928d..d78fd64bdf4d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -36,8 +36,12 @@ pub(super) fn hints( let ty = imp.self_ty(sema.db); let trait_ = imp.trait_(sema.db); let hint_text = match trait_ { - Some(tr) => format!("impl {} for {}", tr.name(sema.db).display(sema.db), ty.display_truncated(sema.db, config.max_length)), - None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)), + Some(tr) => format!( + "impl {} for {}", + tr.name(sema.db).display(sema.db, file_id.edition()), + ty.display_truncated(sema.db, config.max_length, file_id.edition(), + )), + None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, file_id.edition())), }; (hint_text, None) }, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs index f6bd7ca064fd..325c2040691b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs @@ -14,7 +14,7 @@ pub(super) fn hints( acc: &mut Vec, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, + file_id: EditionedFileId, closure: ast::ClosureExpr, ) -> Option<()> { if config.closure_return_type_hints == ClosureReturnTypeHints::Never { @@ -43,7 +43,7 @@ pub(super) fn hints( return None; } - let mut label = label_of_ty(famous_defs, config, &ty)?; + let mut label = label_of_ty(famous_defs, config, &ty, file_id.edition())?; if arrow.is_none() { label.prepend_str(" -> "); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index 7f901db28d36..b4695a2b3519 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -12,6 +12,7 @@ use hir::{ }; use ide_db::{FileRange, RootDatabase}; +use span::EditionedFileId; use syntax::{ ast::{self, AstNode}, match_ast, ToSmolStr, @@ -23,6 +24,7 @@ pub(super) fn hints( acc: &mut Vec, sema: &Semantics<'_, RootDatabase>, config: &InlayHintsConfig, + file_id: EditionedFileId, def: &ast::Fn, ) -> Option<()> { if !config.implicit_drop_hints { @@ -100,7 +102,7 @@ pub(super) fn hints( }) }); let binding = &hir.bindings[*binding]; - let name = binding.name.display_no_db().to_smolstr(); + let name = binding.name.display_no_db(file_id.edition()).to_smolstr(); if name.starts_with(" Some(it.name(sema.db).display_no_db().to_smolstr()), + hir::CallableKind::Function(it) => { + Some(it.name(sema.db).unescaped().display_no_db().to_smolstr()) + } _ => None, }; let fn_name = fn_name.as_deref(); diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 1b64bc926039..7b5fd651e3d7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -249,10 +249,11 @@ pub(crate) fn def_to_moniker( let module = def.module(db)?; let krate = module.krate(); + let edition = krate.edition(db); let mut description = vec![]; description.extend(module.path_to_root(db).into_iter().filter_map(|x| { Some(MonikerDescriptor { - name: x.name(db)?.display(db).to_string(), + name: x.name(db)?.display(db, edition).to_string(), desc: def_to_kind(db, x.into()).into(), }) })); @@ -265,7 +266,7 @@ pub(crate) fn def_to_moniker( // Because different traits can have functions with the same name, // we have to include the trait name as part of the moniker for uniqueness. description.push(MonikerDescriptor { - name: trait_.name(db).display(db).to_string(), + name: trait_.name(db).display(db, edition).to_string(), desc: def_to_kind(db, trait_.into()).into(), }); } @@ -274,14 +275,14 @@ pub(crate) fn def_to_moniker( // we add both the struct name and the trait name to the path if let Some(adt) = impl_.self_ty(db).as_adt() { description.push(MonikerDescriptor { - name: adt.name(db).display(db).to_string(), + name: adt.name(db).display(db, edition).to_string(), desc: def_to_kind(db, adt.into()).into(), }); } if let Some(trait_) = impl_.trait_(db) { description.push(MonikerDescriptor { - name: trait_.name(db).display(db).to_string(), + name: trait_.name(db).display(db, edition).to_string(), desc: def_to_kind(db, trait_.into()).into(), }); } @@ -291,7 +292,7 @@ pub(crate) fn def_to_moniker( if let Definition::Field(it) = def { description.push(MonikerDescriptor { - name: it.parent_def(db).name(db).display(db).to_string(), + name: it.parent_def(db).name(db).display(db, edition).to_string(), desc: def_to_kind(db, it.parent_def(db).into()).into(), }); } @@ -303,7 +304,7 @@ pub(crate) fn def_to_moniker( let parent_name = parent.name(db); if let Some(name) = parent_name { description.push(MonikerDescriptor { - name: name.display(db).to_string(), + name: name.display(db, edition).to_string(), desc: def_to_kind(db, parent).into(), }); } @@ -326,53 +327,53 @@ pub(crate) fn def_to_moniker( return None; } - MonikerDescriptor { name: local.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: local.name(db).display(db, edition).to_string(), desc } } Definition::Macro(m) => { - MonikerDescriptor { name: m.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: m.name(db).display(db, edition).to_string(), desc } } Definition::Function(f) => { - MonikerDescriptor { name: f.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: f.name(db).display(db, edition).to_string(), desc } } Definition::Variant(v) => { - MonikerDescriptor { name: v.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: v.name(db).display(db, edition).to_string(), desc } } Definition::Const(c) => { - MonikerDescriptor { name: c.name(db)?.display(db).to_string(), desc } + MonikerDescriptor { name: c.name(db)?.display(db, edition).to_string(), desc } } Definition::Trait(trait_) => { - MonikerDescriptor { name: trait_.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: trait_.name(db).display(db, edition).to_string(), desc } } Definition::TraitAlias(ta) => { - MonikerDescriptor { name: ta.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: ta.name(db).display(db, edition).to_string(), desc } } Definition::TypeAlias(ta) => { - MonikerDescriptor { name: ta.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: ta.name(db).display(db, edition).to_string(), desc } } Definition::Module(m) => { - MonikerDescriptor { name: m.name(db)?.display(db).to_string(), desc } + MonikerDescriptor { name: m.name(db)?.display(db, edition).to_string(), desc } } Definition::BuiltinType(b) => { - MonikerDescriptor { name: b.name().display(db).to_string(), desc } + MonikerDescriptor { name: b.name().display(db, edition).to_string(), desc } } Definition::SelfType(imp) => MonikerDescriptor { - name: imp.self_ty(db).as_adt()?.name(db).display(db).to_string(), + name: imp.self_ty(db).as_adt()?.name(db).display(db, edition).to_string(), desc, }, Definition::Field(it) => { - MonikerDescriptor { name: it.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: it.name(db).display(db, edition).to_string(), desc } } Definition::TupleField(it) => { - MonikerDescriptor { name: it.name().display(db).to_string(), desc } + MonikerDescriptor { name: it.name().display(db, edition).to_string(), desc } } Definition::Adt(adt) => { - MonikerDescriptor { name: adt.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: adt.name(db).display(db, edition).to_string(), desc } } Definition::Static(s) => { - MonikerDescriptor { name: s.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: s.name(db).display(db, edition).to_string(), desc } } Definition::ExternCrateDecl(m) => { - MonikerDescriptor { name: m.name(db).display(db).to_string(), desc } + MonikerDescriptor { name: m.name(db).display(db, edition).to_string(), desc } } }; diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 066141d36f16..9ace9fda62b9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -5,14 +5,15 @@ use std::fmt; use arrayvec::ArrayVec; use either::Either; use hir::{ - db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasSource, - HirDisplay, HirFileId, InFile, LocalSource, ModuleSource, + db::ExpandDatabase, symbols::FileSymbol, AssocItem, FieldSource, HasContainer, HasCrate, + HasSource, HirDisplay, HirFileId, HirFileIdExt, InFile, LocalSource, ModuleSource, }; use ide_db::{ defs::Definition, documentation::{Documentation, HasDocs}, FileId, FileRange, RootDatabase, SymbolKind, }; +use span::Edition; use stdx::never; use syntax::{ ast::{self, HasName}, @@ -97,7 +98,9 @@ impl NavigationTarget { db: &RootDatabase, module: hir::Module, ) -> UpmappingResult { - let name = module.name(db).map(|it| it.display_no_db().to_smolstr()).unwrap_or_default(); + let edition = module.krate().edition(db); + let name = + module.name(db).map(|it| it.display_no_db(edition).to_smolstr()).unwrap_or_default(); match module.declaration_source(db) { Some(InFile { value, file_id }) => { orig_range_with_focus(db, file_id, value.syntax(), value.name()).map( @@ -110,7 +113,7 @@ impl NavigationTarget { SymbolKind::Module, ); res.docs = module.docs(db); - res.description = Some(module.display(db).to_string()); + res.description = Some(module.display(db, edition).to_string()); res }, ) @@ -175,6 +178,8 @@ impl NavigationTarget { impl TryToNav for FileSymbol { fn try_to_nav(&self, db: &RootDatabase) -> Option> { + let edition = + self.def.module(db).map(|it| it.krate().edition(db)).unwrap_or(Edition::CURRENT); Some( orig_range_with_focus_r( db, @@ -185,27 +190,26 @@ impl TryToNav for FileSymbol { .map(|(FileRange { file_id, range: full_range }, focus_range)| { NavigationTarget { file_id, - name: self - .is_alias - .then(|| self.def.name(db)) - .flatten() - .map_or_else(|| self.name.clone(), |it| it.display_no_db().to_smolstr()), + name: self.is_alias.then(|| self.def.name(db)).flatten().map_or_else( + || self.name.clone(), + |it| it.display_no_db(edition).to_smolstr(), + ), alias: self.is_alias.then(|| self.name.clone()), kind: Some(hir::ModuleDefId::from(self.def).into()), full_range, focus_range, container_name: self.container_name.clone(), description: match self.def { - hir::ModuleDef::Module(it) => Some(it.display(db).to_string()), - hir::ModuleDef::Function(it) => Some(it.display(db).to_string()), - hir::ModuleDef::Adt(it) => Some(it.display(db).to_string()), - hir::ModuleDef::Variant(it) => Some(it.display(db).to_string()), - hir::ModuleDef::Const(it) => Some(it.display(db).to_string()), - hir::ModuleDef::Static(it) => Some(it.display(db).to_string()), - hir::ModuleDef::Trait(it) => Some(it.display(db).to_string()), - hir::ModuleDef::TraitAlias(it) => Some(it.display(db).to_string()), - hir::ModuleDef::TypeAlias(it) => Some(it.display(db).to_string()), - hir::ModuleDef::Macro(it) => Some(it.display(db).to_string()), + hir::ModuleDef::Module(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Function(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Adt(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Variant(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Const(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Static(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Trait(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::TraitAlias(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::TypeAlias(it) => Some(it.display(db, edition).to_string()), + hir::ModuleDef::Macro(it) => Some(it.display(db, edition).to_string()), hir::ModuleDef::BuiltinType(_) => None, }, docs: None, @@ -271,11 +275,13 @@ pub(crate) trait ToNavFromAst: Sized { } } -fn container_name(db: &RootDatabase, t: impl HasContainer) -> Option { +fn container_name(db: &RootDatabase, t: impl HasContainer, edition: Edition) -> Option { match t.container(db) { - hir::ItemContainer::Trait(it) => Some(it.name(db).display_no_db().to_smolstr()), + hir::ItemContainer::Trait(it) => Some(it.name(db).display_no_db(edition).to_smolstr()), // FIXME: Handle owners of blocks correctly here - hir::ItemContainer::Module(it) => it.name(db).map(|name| name.display_no_db().to_smolstr()), + hir::ItemContainer::Module(it) => { + it.name(db).map(|name| name.display_no_db(edition).to_smolstr()) + } _ => None, } } @@ -283,32 +289,32 @@ fn container_name(db: &RootDatabase, t: impl HasContainer) -> Option { impl ToNavFromAst for hir::Function { const KIND: SymbolKind = SymbolKind::Function; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } impl ToNavFromAst for hir::Const { const KIND: SymbolKind = SymbolKind::Const; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } impl ToNavFromAst for hir::Static { const KIND: SymbolKind = SymbolKind::Static; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } impl ToNavFromAst for hir::Struct { const KIND: SymbolKind = SymbolKind::Struct; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } impl ToNavFromAst for hir::Enum { const KIND: SymbolKind = SymbolKind::Enum; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } impl ToNavFromAst for hir::Variant { @@ -317,25 +323,25 @@ impl ToNavFromAst for hir::Variant { impl ToNavFromAst for hir::Union { const KIND: SymbolKind = SymbolKind::Union; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } impl ToNavFromAst for hir::TypeAlias { const KIND: SymbolKind = SymbolKind::TypeAlias; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } impl ToNavFromAst for hir::Trait { const KIND: SymbolKind = SymbolKind::Trait; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } impl ToNavFromAst for hir::TraitAlias { const KIND: SymbolKind = SymbolKind::TraitAlias; fn container_name(self, db: &RootDatabase) -> Option { - container_name(db, self) + container_name(db, self, self.krate(db).edition(db)) } } @@ -346,6 +352,7 @@ where { fn try_to_nav(&self, db: &RootDatabase) -> Option> { let src = self.source(db)?; + let edition = src.file_id.original_file(db).edition(); Some( NavigationTarget::from_named( db, @@ -354,7 +361,7 @@ where ) .map(|mut res| { res.docs = self.docs(db); - res.description = Some(self.display(db).to_string()); + res.description = Some(self.display(db, edition).to_string()); res.container_name = self.container_name(db); res }), @@ -365,8 +372,10 @@ where impl ToNav for hir::Module { fn to_nav(&self, db: &RootDatabase) -> UpmappingResult { let InFile { file_id, value } = self.definition_source(db); + let edition = self.krate(db).edition(db); - let name = self.name(db).map(|it| it.display_no_db().to_smolstr()).unwrap_or_default(); + let name = + self.name(db).map(|it| it.display_no_db(edition).to_smolstr()).unwrap_or_default(); let (syntax, focus) = match &value { ModuleSource::SourceFile(node) => (node.syntax(), None), ModuleSource::Module(node) => (node.syntax(), node.name()), @@ -418,6 +427,7 @@ impl TryToNav for hir::ExternCrateDecl { let focus = value .rename() .map_or_else(|| value.name_ref().map(Either::Left), |it| it.name().map(Either::Right)); + let edition = self.module(db).krate().edition(db); Some(orig_range_with_focus(db, file_id, value.syntax(), focus).map( |(FileRange { file_id, range: full_range }, focus_range)| { @@ -425,7 +435,7 @@ impl TryToNav for hir::ExternCrateDecl { file_id, self.alias_or_name(db) .unwrap_or_else(|| self.name(db)) - .display_no_db() + .display_no_db(edition) .to_smolstr(), focus_range, full_range, @@ -433,8 +443,8 @@ impl TryToNav for hir::ExternCrateDecl { ); res.docs = self.docs(db); - res.description = Some(self.display(db).to_string()); - res.container_name = container_name(db, *self); + res.description = Some(self.display(db, edition).to_string()); + res.container_name = container_name(db, *self, edition); res }, )) @@ -444,13 +454,14 @@ impl TryToNav for hir::ExternCrateDecl { impl TryToNav for hir::Field { fn try_to_nav(&self, db: &RootDatabase) -> Option> { let src = self.source(db)?; + let edition = self.parent_def(db).module(db).krate().edition(db); let field_source = match &src.value { FieldSource::Named(it) => { NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field).map( |mut res| { res.docs = self.docs(db); - res.description = Some(self.display(db).to_string()); + res.description = Some(self.display(db, edition).to_string()); res }, ) @@ -531,10 +542,11 @@ impl ToNav for LocalSource { Either::Left(bind_pat) => (bind_pat.syntax(), bind_pat.name()), Either::Right(it) => (it.syntax(), it.name()), }; + let edition = self.local.parent(db).module(db).krate().edition(db); orig_range_with_focus(db, file_id, node, name).map( |(FileRange { file_id, range: full_range }, focus_range)| { - let name = local.name(db).display_no_db().to_smolstr(); + let name = local.name(db).display_no_db(edition).to_smolstr(); let kind = if local.is_self(db) { SymbolKind::SelfParam } else if local.is_param(db) { @@ -567,7 +579,8 @@ impl ToNav for hir::Local { impl TryToNav for hir::Label { fn try_to_nav(&self, db: &RootDatabase) -> Option> { let InFile { file_id, value } = self.source(db)?; - let name = self.name(db).display_no_db().to_smolstr(); + // Labels can't be keywords, so no escaping needed. + let name = self.name(db).display_no_db(Edition::Edition2015).to_smolstr(); Some(orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()).map( |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget { @@ -588,7 +601,8 @@ impl TryToNav for hir::Label { impl TryToNav for hir::TypeParam { fn try_to_nav(&self, db: &RootDatabase) -> Option> { let InFile { file_id, value } = self.merge().source(db)?; - let name = self.name(db).display_no_db().to_smolstr(); + let edition = self.module(db).krate().edition(db); + let name = self.name(db).display_no_db(edition).to_smolstr(); let value = match value { Either::Left(ast::TypeOrConstParam::Type(x)) => Either::Left(x), @@ -630,7 +644,8 @@ impl TryToNav for hir::TypeOrConstParam { impl TryToNav for hir::LifetimeParam { fn try_to_nav(&self, db: &RootDatabase) -> Option> { let InFile { file_id, value } = self.source(db)?; - let name = self.name(db).display_no_db().to_smolstr(); + // Lifetimes cannot be keywords, so not escaping needed. + let name = self.name(db).display_no_db(Edition::Edition2015).to_smolstr(); Some(orig_range(db, file_id, value.syntax()).map( |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget { @@ -651,7 +666,8 @@ impl TryToNav for hir::LifetimeParam { impl TryToNav for hir::ConstParam { fn try_to_nav(&self, db: &RootDatabase) -> Option> { let InFile { file_id, value } = self.merge().source(db)?; - let name = self.name(db).display_no_db().to_smolstr(); + let edition = self.module(db).krate().edition(db); + let name = self.name(db).display_no_db(edition).to_smolstr(); let value = match value { Either::Left(ast::TypeOrConstParam::Const(x)) => x, diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index aef162bf0ace..3e3d5ef6e655 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -306,8 +306,9 @@ fn handle_control_flow_keywords( FilePosition { file_id, offset }: FilePosition, ) -> Option { let file = sema.parse_guess_edition(file_id); - let token = - file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(Edition::CURRENT))?; + let edition = + sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); + let token = file.syntax().token_at_offset(offset).find(|t| t.kind().is_keyword(edition))?; let references = match token.kind() { T![fn] | T![return] | T![try] => highlight_related::highlight_exit_points(sema, token), diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index ed0e3d89ddc6..42b7472c645f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -6,19 +6,14 @@ use hir::{AsAssocItem, HirFileIdExt, InFile, Semantics}; use ide_db::{ - base_db::SourceDatabase, defs::{Definition, NameClass, NameRefClass}, rename::{bail, format_err, source_edit_from_references, IdentifierKind}, source_change::SourceChangeBuilder, FileId, FileRange, RootDatabase, }; use itertools::Itertools; -use span::Edition; use stdx::{always, never}; -use syntax::{ - ast, utils::is_raw_identifier, AstNode, SmolStr, SyntaxKind, SyntaxNode, TextRange, TextSize, - ToSmolStr, -}; +use syntax::{ast, AstNode, SyntaxKind, SyntaxNode, TextRange, TextSize}; use text_edit::TextEdit; @@ -103,7 +98,7 @@ pub(crate) fn rename( // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can // properly find "direct" usages/references. .map(|(.., def)| { - match IdentifierKind::classify(Edition::CURRENT_FIXME, new_name)? { + match IdentifierKind::classify(new_name)? { IdentifierKind::Ident => (), IdentifierKind::Lifetime => { bail!("Cannot alias reference to a lifetime identifier") @@ -125,7 +120,10 @@ pub(crate) fn rename( let mut source_change = SourceChange::default(); source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| { - (position.file_id, source_edit_from_references(refs, def, new_name)) + ( + position.file_id, + source_edit_from_references(refs, def, new_name, file_id.edition()), + ) })); Ok(source_change) @@ -163,12 +161,7 @@ pub(crate) fn will_rename_file( let sema = Semantics::new(db); let module = sema.file_to_module_def(file_id)?; let def = Definition::Module(module); - let mut change = - if is_raw_identifier(new_name_stem, db.crate_graph()[module.krate().into()].edition) { - def.rename(&sema, &SmolStr::from_iter(["r#", new_name_stem])).ok()? - } else { - def.rename(&sema, new_name_stem).ok()? - }; + let mut change = def.rename(&sema, new_name_stem).ok()?; change.file_system_edits.clear(); Some(change) } @@ -272,7 +265,7 @@ fn find_definitions( // if the name differs from the definitions name it has to be an alias if def .name(sema.db) - .map_or(false, |it| it.display_no_db().to_smolstr() != name_ref.text().as_str()) + .map_or(false, |it| !it.eq_ident(name_ref.text().as_str())) { Err(format_err!("Renaming aliases is currently unsupported")) } else { @@ -379,7 +372,7 @@ fn rename_to_self( let usages = def.usages(sema).all(); let mut source_change = SourceChange::default(); source_change.extend(usages.iter().map(|(file_id, references)| { - (file_id.into(), source_edit_from_references(references, def, "self")) + (file_id.into(), source_edit_from_references(references, def, "self", file_id.edition())) })); source_change.insert_source_edit( file_id.original_file(sema.db), @@ -400,7 +393,7 @@ fn rename_self_to_param( return Ok(SourceChange::default()); } - let identifier_kind = IdentifierKind::classify(Edition::CURRENT_FIXME, new_name)?; + let identifier_kind = IdentifierKind::classify(new_name)?; let InFile { file_id, value: self_param } = sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?; @@ -415,7 +408,7 @@ fn rename_self_to_param( let mut source_change = SourceChange::default(); source_change.insert_source_edit(file_id.original_file(sema.db), edit); source_change.extend(usages.iter().map(|(file_id, references)| { - (file_id.into(), source_edit_from_references(references, def, new_name)) + (file_id.into(), source_edit_from_references(references, def, new_name, file_id.edition())) })); Ok(source_change) } @@ -636,9 +629,9 @@ impl Foo { #[test] fn test_rename_to_invalid_identifier3() { check( - "let", + "super", r#"fn main() { let i$0 = 1; }"#, - "error: Invalid name `let`: not an identifier", + "error: Invalid name `super`: not an identifier", ); } @@ -687,11 +680,7 @@ impl Foo { #[test] fn test_rename_mod_invalid_raw_ident() { - check( - "r#self", - r#"mod foo$0 {}"#, - "error: Invalid name: `self` cannot be a raw identifier", - ); + check("r#self", r#"mod foo$0 {}"#, "error: Invalid name `self`: not an identifier"); } #[test] @@ -1545,6 +1534,228 @@ pub fn baz() {} ); } + #[test] + fn test_rename_each_usage_gets_appropriate_rawness() { + check_expect( + "dyn", + r#" +//- /a.rs crate:a edition:2015 +pub fn foo() {} + +//- /b.rs crate:b edition:2018 deps:a new_source_root:local +fn bar() { + a::foo$0(); +} + "#, + expect![[r#" + source_file_edits: [ + ( + FileId( + 0, + ), + [ + Indel { + insert: "dyn", + delete: 7..10, + }, + ], + ), + ( + FileId( + 1, + ), + [ + Indel { + insert: "r#dyn", + delete: 18..21, + }, + ], + ), + ] + file_system_edits: [] + "#]], + ); + + check_expect( + "dyn", + r#" +//- /a.rs crate:a edition:2018 +pub fn foo() {} + +//- /b.rs crate:b edition:2015 deps:a new_source_root:local +fn bar() { + a::foo$0(); +} + "#, + expect![[r#" + source_file_edits: [ + ( + FileId( + 0, + ), + [ + Indel { + insert: "r#dyn", + delete: 7..10, + }, + ], + ), + ( + FileId( + 1, + ), + [ + Indel { + insert: "dyn", + delete: 18..21, + }, + ], + ), + ] + file_system_edits: [] + "#]], + ); + + check_expect( + "r#dyn", + r#" +//- /a.rs crate:a edition:2018 +pub fn foo$0() {} + +//- /b.rs crate:b edition:2015 deps:a new_source_root:local +fn bar() { + a::foo(); +} + "#, + expect![[r#" + source_file_edits: [ + ( + FileId( + 0, + ), + [ + Indel { + insert: "r#dyn", + delete: 7..10, + }, + ], + ), + ( + FileId( + 1, + ), + [ + Indel { + insert: "dyn", + delete: 18..21, + }, + ], + ), + ] + file_system_edits: [] + "#]], + ); + } + + #[test] + fn rename_raw_identifier() { + check_expect( + "abc", + r#" +//- /a.rs crate:a edition:2015 +pub fn dyn() {} + +fn foo() { + dyn$0(); +} + +//- /b.rs crate:b edition:2018 deps:a new_source_root:local +fn bar() { + a::r#dyn(); +} + "#, + expect![[r#" + source_file_edits: [ + ( + FileId( + 0, + ), + [ + Indel { + insert: "abc", + delete: 7..10, + }, + Indel { + insert: "abc", + delete: 32..35, + }, + ], + ), + ( + FileId( + 1, + ), + [ + Indel { + insert: "abc", + delete: 18..23, + }, + ], + ), + ] + file_system_edits: [] + "#]], + ); + + check_expect( + "abc", + r#" +//- /a.rs crate:a edition:2018 +pub fn r#dyn() {} + +fn foo() { + r#dyn$0(); +} + +//- /b.rs crate:b edition:2015 deps:a new_source_root:local +fn bar() { + a::dyn(); +} + "#, + expect![[r#" + source_file_edits: [ + ( + FileId( + 0, + ), + [ + Indel { + insert: "abc", + delete: 7..12, + }, + Indel { + insert: "abc", + delete: 34..39, + }, + ], + ), + ( + FileId( + 1, + ), + [ + Indel { + insert: "abc", + delete: 18..21, + }, + ], + ), + ] + file_system_edits: [] + "#]], + ); + } + #[test] fn test_enum_variant_from_module_1() { cov_mark::check!(rename_non_local); diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 5d4b8b364394..38dc522789d7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -3,7 +3,8 @@ use std::fmt; use ast::HasName; use cfg::{CfgAtom, CfgExpr}; use hir::{ - db::HirDatabase, sym, AsAssocItem, AttrsWithOwner, HasAttrs, HasSource, HirFileIdExt, Semantics, + db::HirDatabase, sym, AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, HirFileIdExt, + Semantics, }; use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn}; use ide_db::{ @@ -14,7 +15,7 @@ use ide_db::{ FilePosition, FxHashMap, FxHashSet, RootDatabase, SymbolKind, }; use itertools::Itertools; -use span::TextSize; +use span::{Edition, TextSize}; use stdx::{always, format_to}; use syntax::{ ast::{self, AstNode}, @@ -321,6 +322,7 @@ pub(crate) fn runnable_fn( sema: &Semantics<'_, RootDatabase>, def: hir::Function, ) -> Option { + let edition = def.krate(sema.db).edition(sema.db); let under_cfg_test = has_cfg_test(def.module(sema.db).attrs(sema.db)); let kind = if !under_cfg_test && def.is_main(sema.db) { RunnableKind::Bin @@ -328,11 +330,11 @@ pub(crate) fn runnable_fn( let test_id = || { let canonical_path = { let def: hir::ModuleDef = def.into(); - def.canonical_path(sema.db) + def.canonical_path(sema.db, edition) }; canonical_path .map(TestId::Path) - .unwrap_or(TestId::Name(def.name(sema.db).display_no_db().to_smolstr())) + .unwrap_or(TestId::Name(def.name(sema.db).display_no_db(edition).to_smolstr())) }; if def.is_test(sema.db) { @@ -367,8 +369,11 @@ pub(crate) fn runnable_mod( .path_to_root(sema.db) .into_iter() .rev() - .filter_map(|it| it.name(sema.db)) - .map(|it| it.display(sema.db).to_string()) + .filter_map(|module| { + module.name(sema.db).map(|mod_name| { + mod_name.display(sema.db, module.krate().edition(sema.db)).to_string() + }) + }) .join("::"); let attrs = def.attrs(sema.db); @@ -381,6 +386,7 @@ pub(crate) fn runnable_impl( sema: &Semantics<'_, RootDatabase>, def: &hir::Impl, ) -> Option { + let edition = def.module(sema.db).krate().edition(sema.db); let attrs = def.attrs(sema.db); if !has_runnable_doc_test(&attrs) { return None; @@ -389,13 +395,13 @@ pub(crate) fn runnable_impl( let nav = def.try_to_nav(sema.db)?.call_site(); let ty = def.self_ty(sema.db); let adt_name = ty.as_adt()?.name(sema.db); - let mut ty_args = ty.generic_parameters(sema.db).peekable(); + let mut ty_args = ty.generic_parameters(sema.db, edition).peekable(); let params = if ty_args.peek().is_some() { format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))) } else { String::new() }; - let mut test_id = format!("{}{params}", adt_name.display(sema.db)); + let mut test_id = format!("{}{params}", adt_name.display(sema.db, edition)); test_id.retain(|c| c != ' '); let test_id = TestId::Path(test_id); @@ -419,8 +425,11 @@ fn runnable_mod_outline_definition( .path_to_root(sema.db) .into_iter() .rev() - .filter_map(|it| it.name(sema.db)) - .map(|it| it.display(sema.db).to_string()) + .filter_map(|module| { + module.name(sema.db).map(|mod_name| { + mod_name.display(sema.db, module.krate().edition(sema.db)).to_string() + }) + }) .join("::"); let attrs = def.attrs(sema.db); @@ -452,6 +461,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { Definition::SelfType(it) => it.attrs(db), _ => return None, }; + let edition = def.krate(db).map(|it| it.edition(db)).unwrap_or(Edition::CURRENT); if !has_runnable_doc_test(&attrs) { return None; } @@ -460,29 +470,29 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option { let mut path = String::new(); def.canonical_module_path(db)? .flat_map(|it| it.name(db)) - .for_each(|name| format_to!(path, "{}::", name.display(db))); + .for_each(|name| format_to!(path, "{}::", name.display(db, edition))); // This probably belongs to canonical_path? if let Some(assoc_item) = def.as_assoc_item(db) { if let Some(ty) = assoc_item.implementing_ty(db) { if let Some(adt) = ty.as_adt() { let name = adt.name(db); - let mut ty_args = ty.generic_parameters(db).peekable(); - format_to!(path, "{}", name.display(db)); + let mut ty_args = ty.generic_parameters(db, edition).peekable(); + format_to!(path, "{}", name.display(db, edition)); if ty_args.peek().is_some() { format_to!(path, "<{}>", ty_args.format_with(",", |ty, cb| cb(&ty))); } - format_to!(path, "::{}", def_name.display(db)); + format_to!(path, "::{}", def_name.display(db, edition)); path.retain(|c| c != ' '); return Some(path); } } } - format_to!(path, "{}", def_name.display(db)); + format_to!(path, "{}", def_name.display(db, edition)); Some(path) })(); - let test_id = - path.map_or_else(|| TestId::Name(def_name.display_no_db().to_smolstr()), TestId::Path); + let test_id = path + .map_or_else(|| TestId::Name(def_name.display_no_db(edition).to_smolstr()), TestId::Path); let mut nav = match def { Definition::Module(def) => NavigationTarget::from_module_to_decl(db, def), diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index b6c9e2f6366a..9d3b8c6ebd19 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -13,6 +13,7 @@ use ide_db::{ documentation::{Documentation, HasDocs}, FilePosition, FxIndexMap, }; +use span::Edition; use stdx::format_to; use syntax::{ algo, @@ -82,6 +83,8 @@ pub(crate) fn signature_help( // this prevents us from leaving the CallExpression .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?; let token = sema.descend_into_macros_single(DescendPreference::None, token); + let edition = + sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); for node in token.parent_ancestors() { match_ast! { @@ -91,49 +94,49 @@ pub(crate) fn signature_help( if cursor_outside { continue; } - return signature_help_for_call(&sema, arg_list, token); + return signature_help_for_call(&sema, arg_list, token, edition); }, ast::GenericArgList(garg_list) => { let cursor_outside = garg_list.r_angle_token().as_ref() == Some(&token); if cursor_outside { continue; } - return signature_help_for_generics(&sema, garg_list, token); + return signature_help_for_generics(&sema, garg_list, token, edition); }, ast::RecordExpr(record) => { let cursor_outside = record.record_expr_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token); if cursor_outside { continue; } - return signature_help_for_record_lit(&sema, record, token); + return signature_help_for_record_lit(&sema, record, token, edition); }, ast::RecordPat(record) => { let cursor_outside = record.record_pat_field_list().and_then(|list| list.r_curly_token()).as_ref() == Some(&token); if cursor_outside { continue; } - return signature_help_for_record_pat(&sema, record, token); + return signature_help_for_record_pat(&sema, record, token, edition); }, ast::TupleStructPat(tuple_pat) => { let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token); if cursor_outside { continue; } - return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token); + return signature_help_for_tuple_struct_pat(&sema, tuple_pat, token, edition); }, ast::TuplePat(tuple_pat) => { let cursor_outside = tuple_pat.r_paren_token().as_ref() == Some(&token); if cursor_outside { continue; } - return signature_help_for_tuple_pat(&sema, tuple_pat, token); + return signature_help_for_tuple_pat(&sema, tuple_pat, token, edition); }, ast::TupleExpr(tuple_expr) => { let cursor_outside = tuple_expr.r_paren_token().as_ref() == Some(&token); if cursor_outside { continue; } - return signature_help_for_tuple_expr(&sema, tuple_expr, token); + return signature_help_for_tuple_expr(&sema, tuple_expr, token, edition); }, _ => (), } @@ -157,6 +160,7 @@ fn signature_help_for_call( sema: &Semantics<'_, RootDatabase>, arg_list: ast::ArgList, token: SyntaxToken, + edition: Edition, ) -> Option { // Find the calling expression and its NameRef let mut nodes = arg_list.syntax().ancestors().skip(1); @@ -181,7 +185,7 @@ fn signature_help_for_call( match callable.kind() { hir::CallableKind::Function(func) => { res.doc = func.docs(db); - format_to!(res.signature, "fn {}", func.name(db).display(db)); + format_to!(res.signature, "fn {}", func.name(db).display(db, edition)); fn_params = Some(match callable.receiver_param(db) { Some(_self) => func.params_without_self(db), None => func.assoc_fn_params(db), @@ -189,15 +193,15 @@ fn signature_help_for_call( } hir::CallableKind::TupleStruct(strukt) => { res.doc = strukt.docs(db); - format_to!(res.signature, "struct {}", strukt.name(db).display(db)); + format_to!(res.signature, "struct {}", strukt.name(db).display(db, edition)); } hir::CallableKind::TupleEnumVariant(variant) => { res.doc = variant.docs(db); format_to!( res.signature, "enum {}::{}", - variant.parent_enum(db).name(db).display(db), - variant.name(db).display(db) + variant.parent_enum(db).name(db).display(db, edition), + variant.name(db).display(db, edition) ); } hir::CallableKind::Closure(closure) => { @@ -210,7 +214,7 @@ fn signature_help_for_call( Some(adt) => format_to!( res.signature, "<{} as {fn_trait}>::{}", - adt.name(db).display(db), + adt.name(db).display(db, edition), fn_trait.function_name() ), None => format_to!(res.signature, "impl {fn_trait}"), @@ -220,7 +224,7 @@ fn signature_help_for_call( res.signature.push('('); { if let Some((self_param, _)) = callable.receiver_param(db) { - format_to!(res.signature, "{}", self_param.display(db)) + format_to!(res.signature, "{}", self_param.display(db, edition)) } let mut buf = String::new(); for (idx, p) in callable.params().into_iter().enumerate() { @@ -240,8 +244,10 @@ fn signature_help_for_call( // This is overly conservative: we do not substitute known type vars // (see FIXME in tests::impl_trait) and falling back on any unknowns. match (p.ty().contains_unknown(), fn_params.as_deref()) { - (true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)), - _ => format_to!(buf, "{}", p.ty().display(db)), + (true, Some(fn_params)) => { + format_to!(buf, "{}", fn_params[idx].ty().display(db, edition)) + } + _ => format_to!(buf, "{}", p.ty().display(db, edition)), } res.push_call_param(&buf); } @@ -250,7 +256,7 @@ fn signature_help_for_call( let mut render = |ret_type: hir::Type| { if !ret_type.is_unit() { - format_to!(res.signature, " -> {}", ret_type.display(db)); + format_to!(res.signature, " -> {}", ret_type.display(db, edition)); } }; match callable.kind() { @@ -270,6 +276,7 @@ fn signature_help_for_generics( sema: &Semantics<'_, RootDatabase>, arg_list: ast::GenericArgList, token: SyntaxToken, + edition: Edition, ) -> Option { let (generics_def, mut active_parameter, first_arg_is_non_lifetime, variant) = generic_def_for_node(sema, &arg_list, &token)?; @@ -284,11 +291,11 @@ fn signature_help_for_generics( match generics_def { hir::GenericDef::Function(it) => { res.doc = it.docs(db); - format_to!(res.signature, "fn {}", it.name(db).display(db)); + format_to!(res.signature, "fn {}", it.name(db).display(db, edition)); } hir::GenericDef::Adt(hir::Adt::Enum(it)) => { res.doc = it.docs(db); - format_to!(res.signature, "enum {}", it.name(db).display(db)); + format_to!(res.signature, "enum {}", it.name(db).display(db, edition)); if let Some(variant) = variant { // In paths, generics of an enum can be specified *after* one of its variants. // eg. `None::` @@ -298,23 +305,23 @@ fn signature_help_for_generics( } hir::GenericDef::Adt(hir::Adt::Struct(it)) => { res.doc = it.docs(db); - format_to!(res.signature, "struct {}", it.name(db).display(db)); + format_to!(res.signature, "struct {}", it.name(db).display(db, edition)); } hir::GenericDef::Adt(hir::Adt::Union(it)) => { res.doc = it.docs(db); - format_to!(res.signature, "union {}", it.name(db).display(db)); + format_to!(res.signature, "union {}", it.name(db).display(db, edition)); } hir::GenericDef::Trait(it) => { res.doc = it.docs(db); - format_to!(res.signature, "trait {}", it.name(db).display(db)); + format_to!(res.signature, "trait {}", it.name(db).display(db, edition)); } hir::GenericDef::TraitAlias(it) => { res.doc = it.docs(db); - format_to!(res.signature, "trait {}", it.name(db).display(db)); + format_to!(res.signature, "trait {}", it.name(db).display(db, edition)); } hir::GenericDef::TypeAlias(it) => { res.doc = it.docs(db); - format_to!(res.signature, "type {}", it.name(db).display(db)); + format_to!(res.signature, "type {}", it.name(db).display(db, edition)); } // These don't have generic args that can be specified hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None, @@ -339,11 +346,11 @@ fn signature_help_for_generics( } buf.clear(); - format_to!(buf, "{}", param.display(db)); + format_to!(buf, "{}", param.display(db, edition)); res.push_generic_param(&buf); } if let hir::GenericDef::Trait(tr) = generics_def { - add_assoc_type_bindings(db, &mut res, tr, arg_list); + add_assoc_type_bindings(db, &mut res, tr, arg_list, edition); } res.signature.push('>'); @@ -355,6 +362,7 @@ fn add_assoc_type_bindings( res: &mut SignatureHelp, tr: Trait, args: ast::GenericArgList, + edition: Edition, ) { if args.syntax().ancestors().find_map(ast::TypeBound::cast).is_none() { // Assoc type bindings are only valid in type bound position. @@ -378,7 +386,7 @@ fn add_assoc_type_bindings( for item in tr.items_with_supertraits(db) { if let AssocItem::TypeAlias(ty) = item { - let name = ty.name(db).display_no_db().to_smolstr(); + let name = ty.name(db).display_no_db(edition).to_smolstr(); if !present_bindings.contains(&*name) { buf.clear(); format_to!(buf, "{} = …", name); @@ -392,6 +400,7 @@ fn signature_help_for_record_lit( sema: &Semantics<'_, RootDatabase>, record: ast::RecordExpr, token: SyntaxToken, + edition: Edition, ) -> Option { signature_help_for_record_( sema, @@ -403,6 +412,7 @@ fn signature_help_for_record_lit( .filter_map(|field| sema.resolve_record_field(&field)) .map(|(field, _, ty)| (field, ty)), token, + edition, ) } @@ -410,6 +420,7 @@ fn signature_help_for_record_pat( sema: &Semantics<'_, RootDatabase>, record: ast::RecordPat, token: SyntaxToken, + edition: Edition, ) -> Option { signature_help_for_record_( sema, @@ -420,6 +431,7 @@ fn signature_help_for_record_pat( .fields() .filter_map(|field| sema.resolve_record_pat_field(&field)), token, + edition, ) } @@ -427,6 +439,7 @@ fn signature_help_for_tuple_struct_pat( sema: &Semantics<'_, RootDatabase>, pat: ast::TupleStructPat, token: SyntaxToken, + edition: Edition, ) -> Option { let path = pat.path()?; let path_res = sema.resolve_path(&path)?; @@ -445,8 +458,8 @@ fn signature_help_for_tuple_struct_pat( format_to!( res.signature, "enum {}::{} (", - en.name(db).display(db), - variant.name(db).display(db) + en.name(db).display(db, edition), + variant.name(db).display(db, edition) ); variant.fields(db) } else { @@ -459,7 +472,7 @@ fn signature_help_for_tuple_struct_pat( match adt { hir::Adt::Struct(it) => { res.doc = it.docs(db); - format_to!(res.signature, "struct {} (", it.name(db).display(db)); + format_to!(res.signature, "struct {} (", it.name(db).display(db, edition)); it.fields(db) } _ => return None, @@ -472,6 +485,7 @@ fn signature_help_for_tuple_struct_pat( token, pat.fields(), fields.into_iter().map(|it| it.ty(db)), + edition, )) } @@ -479,6 +493,7 @@ fn signature_help_for_tuple_pat( sema: &Semantics<'_, RootDatabase>, pat: ast::TuplePat, token: SyntaxToken, + edition: Edition, ) -> Option { let db = sema.db; let field_pats = pat.fields(); @@ -498,6 +513,7 @@ fn signature_help_for_tuple_pat( token, field_pats, fields.into_iter(), + edition, )) } @@ -505,6 +521,7 @@ fn signature_help_for_tuple_expr( sema: &Semantics<'_, RootDatabase>, expr: ast::TupleExpr, token: SyntaxToken, + edition: Edition, ) -> Option { let active_parameter = Some( expr.syntax() @@ -526,7 +543,7 @@ fn signature_help_for_tuple_expr( let fields = expr.original.tuple_fields(db); let mut buf = String::new(); for ty in fields { - format_to!(buf, "{}", ty.display_truncated(db, Some(20))); + format_to!(buf, "{}", ty.display_truncated(db, Some(20), edition)); res.push_call_param(&buf); buf.clear(); } @@ -540,6 +557,7 @@ fn signature_help_for_record_( path: &ast::Path, fields2: impl Iterator, token: SyntaxToken, + edition: Edition, ) -> Option { let active_parameter = field_list_children .filter_map(NodeOrToken::into_token) @@ -566,8 +584,8 @@ fn signature_help_for_record_( format_to!( res.signature, "enum {}::{} {{ ", - en.name(db).display(db), - variant.name(db).display(db) + en.name(db).display(db, edition), + variant.name(db).display(db, edition) ); } else { let adt = match path_res { @@ -580,12 +598,12 @@ fn signature_help_for_record_( hir::Adt::Struct(it) => { fields = it.fields(db); res.doc = it.docs(db); - format_to!(res.signature, "struct {} {{ ", it.name(db).display(db)); + format_to!(res.signature, "struct {} {{ ", it.name(db).display(db, edition)); } hir::Adt::Union(it) => { fields = it.fields(db); res.doc = it.docs(db); - format_to!(res.signature, "union {} {{ ", it.name(db).display(db)); + format_to!(res.signature, "union {} {{ ", it.name(db).display(db, edition)); } _ => return None, } @@ -596,7 +614,12 @@ fn signature_help_for_record_( let mut buf = String::new(); for (field, ty) in fields2 { let name = field.name(db); - format_to!(buf, "{}: {}", name.display(db), ty.display_truncated(db, Some(20))); + format_to!( + buf, + "{}: {}", + name.display(db, edition), + ty.display_truncated(db, Some(20), edition) + ); res.push_record_field(&buf); buf.clear(); @@ -606,7 +629,12 @@ fn signature_help_for_record_( } for (name, field) in fields { let Some(field) = field else { continue }; - format_to!(buf, "{}: {}", name.display(db), field.ty(db).display_truncated(db, Some(20))); + format_to!( + buf, + "{}: {}", + name.display(db, edition), + field.ty(db).display_truncated(db, Some(20), edition) + ); res.push_record_field(&buf); buf.clear(); } @@ -621,6 +649,7 @@ fn signature_help_for_tuple_pat_ish( token: SyntaxToken, mut field_pats: AstChildren, fields: impl ExactSizeIterator, + edition: Edition, ) -> SignatureHelp { let rest_pat = field_pats.find(|it| matches!(it, ast::Pat::RestPat(_))); let is_left_of_rest_pat = @@ -647,7 +676,7 @@ fn signature_help_for_tuple_pat_ish( let mut buf = String::new(); for ty in fields { - format_to!(buf, "{}", ty.display_truncated(db, Some(20))); + format_to!(buf, "{}", ty.display_truncated(db, Some(20), edition)); res.push_call_param(&buf); buf.clear(); } diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index eaccee08e8c0..0f8d03c8d559 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -10,6 +10,7 @@ use ide_db::{ helpers::get_definition, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, }; +use span::Edition; use syntax::{AstNode, SyntaxKind::*, SyntaxNode, TextRange, T}; use crate::inlay_hints::InlayFieldsToResolve; @@ -116,7 +117,11 @@ fn documentation_for_definition( _ => None, }; - def.docs(sema.db, famous_defs.as_ref()) + def.docs( + sema.db, + famous_defs.as_ref(), + def.krate(sema.db).map(|it| it.edition(sema.db)).unwrap_or(Edition::CURRENT), + ) } impl StaticIndex<'_> { @@ -161,6 +166,8 @@ impl StaticIndex<'_> { // hovers let sema = hir::Semantics::new(self.db); let tokens_or_nodes = sema.parse_guess_edition(file_id).syntax().clone(); + let edition = + sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT); let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|it| match it { syntax::NodeOrToken::Node(_) => None, syntax::NodeOrToken::Token(it) => Some(it), @@ -201,17 +208,20 @@ impl StaticIndex<'_> { &node, None, &hover_config, + edition, )), definition: def.try_to_nav(self.db).map(UpmappingResult::call_site).map(|it| { FileRange { file_id: it.file_id, range: it.focus_or_full_range() } }), references: vec![], moniker: current_crate.and_then(|cc| def_to_moniker(self.db, def, cc)), - display_name: def.name(self.db).map(|name| name.display(self.db).to_string()), + display_name: def + .name(self.db) + .map(|name| name.display(self.db, edition).to_string()), enclosing_moniker: current_crate .zip(def.enclosing_definition(self.db)) .and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)), - signature: Some(def.label(self.db)), + signature: Some(def.label(self.db, edition)), kind: def_to_kind(self.db, def), }); self.def_map.insert(def, it); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs index 23185920058b..e082fcdc7658 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs @@ -501,7 +501,9 @@ fn traverse( config.syntactic_name_ref_highlighting, name_like, ), - NodeOrToken::Token(token) => highlight::token(sema, token).zip(Some(None)), + NodeOrToken::Token(token) => { + highlight::token(sema, token, file_id.edition()).zip(Some(None)) + } }; if let Some((mut highlight, binding_hash)) = element { if is_unlinked && highlight.tag == HlTag::UnresolvedReference { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 70fdc0a1b3a7..eeba9cf35c99 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -19,7 +19,11 @@ use crate::{ Highlight, HlMod, HlTag, }; -pub(super) fn token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option { +pub(super) fn token( + sema: &Semantics<'_, RootDatabase>, + token: SyntaxToken, + edition: Edition, +) -> Option { if let Some(comment) = ast::Comment::cast(token.clone()) { let h = HlTag::Comment; return Some(match comment.kind().doc { @@ -42,7 +46,7 @@ pub(super) fn token(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> O HlTag::None.into() } p if p.is_punct() => punctuation(sema, token, p), - k if k.is_keyword(Edition::CURRENT) => keyword(sema, token, k)?, + k if k.is_keyword(edition) => keyword(sema, token, k)?, _ => return None, }; Some(highlight) diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs index 460fc4fe141c..b441b4cc90eb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/macro_.rs @@ -1,5 +1,4 @@ //! Syntax highlighting for macro_rules!. -use span::Edition; use syntax::{SyntaxKind, SyntaxToken, TextRange, T}; use crate::{HlRange, HlTag}; @@ -118,7 +117,7 @@ fn update_macro_state(state: &mut MacroMatcherParseState, tok: &SyntaxToken) { fn is_metavariable(token: &SyntaxToken) -> Option { match token.kind() { - kind if kind == SyntaxKind::IDENT || kind.is_keyword(Edition::CURRENT) => { + kind if kind.is_any_identifier() => { if let Some(_dollar) = token.prev_token().filter(|t| t.kind() == T![$]) { return Some(token.text_range()); } diff --git a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs index dae79998dc4e..a6352b99d4f5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs @@ -16,5 +16,5 @@ pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String { let file_id = sema .attach_first_edition(file_id) .unwrap_or_else(|| EditionedFileId::current_edition(file_id)); - db.file_item_tree(file_id.into()).pretty_print(db) + db.file_item_tree(file_id.into()).pretty_print(db, file_id.edition()) } diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index df3f2f18b4cd..830c39e21ea5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -6,6 +6,7 @@ use ide_db::{ helpers::{get_definition, pick_best_token}, RootDatabase, }; +use span::Edition; use syntax::{AstNode, SyntaxKind}; use crate::FilePosition; @@ -85,6 +86,10 @@ pub(crate) fn view_memory_layout( ) -> Option { let sema = Semantics::new(db); let file = sema.parse_guess_edition(position.file_id); + let edition = sema + .attach_first_edition(position.file_id) + .map(|it| it.edition()) + .unwrap_or(Edition::CURRENT); let token = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind { SyntaxKind::IDENT => 3, @@ -111,6 +116,7 @@ pub(crate) fn view_memory_layout( ty: &Type, layout: &Layout, parent_idx: usize, + edition: Edition, ) { let mut fields = ty .fields(db) @@ -141,7 +147,7 @@ pub(crate) fn view_memory_layout( if let Ok(child_layout) = child_ty.layout(db) { nodes.push(MemoryLayoutNode { item_name: field.name(db), - typename: child_ty.display(db).to_string(), + typename: child_ty.display(db, edition).to_string(), size: child_layout.size(), alignment: child_layout.align(), offset: match *field { @@ -157,7 +163,7 @@ pub(crate) fn view_memory_layout( item_name: field.name(db) + format!("(no layout data: {:?})", child_ty.layout(db).unwrap_err()) .as_ref(), - typename: child_ty.display(db).to_string(), + typename: child_ty.display(db, edition).to_string(), size: 0, offset: 0, alignment: 0, @@ -170,7 +176,7 @@ pub(crate) fn view_memory_layout( for (i, (_, child_ty)) in fields.iter().enumerate() { if let Ok(child_layout) = child_ty.layout(db) { - read_layout(nodes, db, child_ty, &child_layout, children_start + i); + read_layout(nodes, db, child_ty, &child_layout, children_start + i, edition); } } } @@ -188,7 +194,7 @@ pub(crate) fn view_memory_layout( def => def.name(db).map(|n| n.as_str().to_owned()).unwrap_or("[ROOT]".to_owned()), }; - let typename = ty.display(db).to_string(); + let typename = ty.display(db, edition).to_string(); let mut nodes = vec![MemoryLayoutNode { item_name, @@ -200,7 +206,7 @@ pub(crate) fn view_memory_layout( children_start: -1, children_len: 0, }]; - read_layout(&mut nodes, db, &ty, &layout, 0); + read_layout(&mut nodes, db, &ty, &layout, 0, edition); RecursiveMemoryLayout { nodes } }) diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs index 3ca6bd4cb111..6a8cca9ccc79 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs @@ -3,6 +3,8 @@ mod generated; +use crate::Edition; + #[allow(unreachable_pub)] pub use self::generated::SyntaxKind; @@ -26,4 +28,11 @@ impl SyntaxKind { pub fn is_trivia(self) -> bool { matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT) } + + /// Returns true if this is an identifier or a keyword. + #[inline] + pub fn is_any_identifier(self) -> bool { + // Assuming no edition removed keywords... + self == SyntaxKind::IDENT || self.is_keyword(Edition::LATEST) + } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs index 0bd6677b6623..5eb6ff664f66 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs @@ -21,7 +21,7 @@ use std::io::Read; use anyhow::Result; use hir::{Module, Name}; use hir_ty::db::HirDatabase; -use ide::AnalysisHost; +use ide::{AnalysisHost, Edition}; use itertools::Itertools; use vfs::Vfs; @@ -85,6 +85,6 @@ fn full_name_of_item(db: &dyn HirDatabase, module: Module, name: Name) -> String .rev() .filter_map(|it| it.name(db)) .chain(Some(name)) - .map(|it| it.display(db.upcast()).to_string()) + .map(|it| it.display(db.upcast(), Edition::LATEST).to_string()) .join("::") } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 06f4ba815d0d..44e56645ba3c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -17,7 +17,7 @@ use hir_def::{ }; use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; use ide::{ - Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, InlayFieldsToResolve, + Analysis, AnalysisHost, AnnotationConfig, DiagnosticsConfig, Edition, InlayFieldsToResolve, InlayHintsConfig, LineCol, RootDatabase, }; use ide_db::{ @@ -309,7 +309,7 @@ impl flags::AnalysisStats { let mut fail = 0; for &c in consts { all += 1; - let Err(error) = c.render_eval(db) else { + let Err(error) = c.render_eval(db, Edition::LATEST) else { continue; }; if verbosity.is_spammy() { @@ -442,6 +442,7 @@ impl flags::AnalysisStats { prefer_prelude: true, prefer_absolute: false, }, + Edition::LATEST, ) .unwrap(); syntax_hit_found |= trim(&original_text) == trim(&generated); @@ -563,7 +564,7 @@ impl flags::AnalysisStats { .rev() .filter_map(|it| it.name(db)) .chain(Some(body.name(db).unwrap_or_else(Name::missing))) - .map(|it| it.display(db).to_string()) + .map(|it| it.display(db, Edition::LATEST).to_string()) .join("::"); println!("Mir body for {full_name} failed due {e:?}"); } @@ -628,12 +629,14 @@ impl flags::AnalysisStats { .filter_map(|it| it.name(db)) .rev() .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) - .map(|it| it.display(db).to_string()), + .map(|it| it.display(db, Edition::LATEST).to_string()), ) .join("::") }; if let Some(only_name) = self.only.as_deref() { - if name.display(db).to_string() != only_name && full_name() != only_name { + if name.display(db, Edition::LATEST).to_string() != only_name + && full_name() != only_name + { continue; } } @@ -687,7 +690,10 @@ impl flags::AnalysisStats { end.col, )); } else { - bar.println(format!("{}: Unknown type", name.display(db))); + bar.println(format!( + "{}: Unknown type", + name.display(db, Edition::LATEST) + )); } } true @@ -708,17 +714,20 @@ impl flags::AnalysisStats { start.col, end.line + 1, end.col, - ty.display(db) + ty.display(db, Edition::LATEST) )); } else { - bar.println(format!("unknown location: {}", ty.display(db))); + bar.println(format!( + "unknown location: {}", + ty.display(db, Edition::LATEST) + )); } } if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, location_csv_expr(db, vfs, &sm(), expr_id), - ty.display(db) + ty.display(db, Edition::LATEST) ); } if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { @@ -733,15 +742,15 @@ impl flags::AnalysisStats { start.col, end.line + 1, end.col, - mismatch.expected.display(db), - mismatch.actual.display(db) + mismatch.expected.display(db, Edition::LATEST), + mismatch.actual.display(db, Edition::LATEST) )); } else { bar.println(format!( "{}: Expected {}, got {}", - name.display(db), - mismatch.expected.display(db), - mismatch.actual.display(db) + name.display(db, Edition::LATEST), + mismatch.expected.display(db, Edition::LATEST), + mismatch.actual.display(db, Edition::LATEST) )); } } @@ -749,8 +758,8 @@ impl flags::AnalysisStats { println!( r#"{},mismatch,"{}","{}""#, location_csv_expr(db, vfs, &sm(), expr_id), - mismatch.expected.display(db), - mismatch.actual.display(db) + mismatch.expected.display(db, Edition::LATEST), + mismatch.actual.display(db, Edition::LATEST) ); } } @@ -785,7 +794,10 @@ impl flags::AnalysisStats { end.col, )); } else { - bar.println(format!("{}: Unknown type", name.display(db))); + bar.println(format!( + "{}: Unknown type", + name.display(db, Edition::LATEST) + )); } } true @@ -806,17 +818,20 @@ impl flags::AnalysisStats { start.col, end.line + 1, end.col, - ty.display(db) + ty.display(db, Edition::LATEST) )); } else { - bar.println(format!("unknown location: {}", ty.display(db))); + bar.println(format!( + "unknown location: {}", + ty.display(db, Edition::LATEST) + )); } } if unknown_or_partial && self.output == Some(OutputFormat::Csv) { println!( r#"{},type,"{}""#, location_csv_pat(db, vfs, &sm(), pat_id), - ty.display(db) + ty.display(db, Edition::LATEST) ); } if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat_id) { @@ -830,15 +845,15 @@ impl flags::AnalysisStats { start.col, end.line + 1, end.col, - mismatch.expected.display(db), - mismatch.actual.display(db) + mismatch.expected.display(db, Edition::LATEST), + mismatch.actual.display(db, Edition::LATEST) )); } else { bar.println(format!( "{}: Expected {}, got {}", - name.display(db), - mismatch.expected.display(db), - mismatch.actual.display(db) + name.display(db, Edition::LATEST), + mismatch.expected.display(db, Edition::LATEST), + mismatch.actual.display(db, Edition::LATEST) )); } } @@ -846,8 +861,8 @@ impl flags::AnalysisStats { println!( r#"{},mismatch,"{}","{}""#, location_csv_pat(db, vfs, &sm(), pat_id), - mismatch.expected.display(db), - mismatch.actual.display(db) + mismatch.expected.display(db, Edition::LATEST), + mismatch.actual.display(db, Edition::LATEST) ); } } @@ -923,12 +938,16 @@ impl flags::AnalysisStats { .filter_map(|it| it.name(db)) .rev() .chain(Some(body_id.name(db).unwrap_or_else(Name::missing))) - .map(|it| it.display(db).to_string()), + .map(|it| it.display(db, Edition::LATEST).to_string()), ) .join("::") }; if let Some(only_name) = self.only.as_deref() { - if body_id.name(db).unwrap_or_else(Name::missing).display(db).to_string() + if body_id + .name(db) + .unwrap_or_else(Name::missing) + .display(db, Edition::LATEST) + .to_string() != only_name && full_name() != only_name { diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index 5153db237275..56e43e82ed27 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -301,14 +301,11 @@ where }; } let leaf: tt::Leaf<_> = match kind { - T![true] | T![false] => make_ident!(), - IDENT => { + k if k.is_any_identifier() => { let text = token.to_text(conv); tt::Ident::new(&text, conv.span_for(abs_range)).into() } UNDERSCORE => make_ident!(), - // FIXME: Edition - k if k.is_keyword(Edition::CURRENT) => make_ident!(), k if k.is_literal() => { let text = token.to_text(conv); let span = conv.span_for(abs_range); diff --git a/src/tools/rust-analyzer/crates/syntax/src/utils.rs b/src/tools/rust-analyzer/crates/syntax/src/utils.rs index 77d49b442e0a..d1f60f0b71bc 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/utils.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/utils.rs @@ -2,6 +2,7 @@ use crate::SyntaxKind; +#[inline] pub fn is_raw_identifier(name: &str, edition: parser::Edition) -> bool { let is_keyword = SyntaxKind::from_keyword(name, edition).is_some(); is_keyword && !matches!(name, "self" | "crate" | "super" | "Self")