summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/ide-db
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide-db')
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/line_index.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs70
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs60
4 files changed, 84 insertions, 55 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index cf0bcd5c9..f48cce58c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
description = "TBD"
license = "MIT OR Apache-2.0"
edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
[lib]
doctest = false
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
index 75d49ff2f..1b8f56187 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
@@ -58,8 +58,11 @@ impl LineIndex {
let mut utf16_lines = NoHashHashMap::default();
let mut utf16_chars = Vec::new();
- let mut newlines = vec![0.into()];
- let mut curr_row @ mut curr_col = 0.into();
+ let mut newlines = Vec::with_capacity(16);
+ newlines.push(TextSize::from(0));
+
+ let mut curr_row = 0.into();
+ let mut curr_col = 0.into();
let mut line = 0;
for c in text.chars() {
let c_len = TextSize::of(c);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index 82b85f2fa..aa5d7e9be 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -446,33 +446,47 @@ impl<'a> FindUsages<'a> {
})
}
- // FIXME: There should be optimization potential here
- // Currently we try to descend everything we find which
- // means we call `Semantics::descend_into_macros` on
- // every textual hit. That function is notoriously
- // expensive even for things that do not get down mapped
- // into macros.
+ let find_nodes = move |name: &str, node: &syntax::SyntaxNode, offset: TextSize| {
+ node.token_at_offset(offset).find(|it| it.text() == name).map(|token| {
+ // FIXME: There should be optimization potential here
+ // Currently we try to descend everything we find which
+ // means we call `Semantics::descend_into_macros` on
+ // every textual hit. That function is notoriously
+ // expensive even for things that do not get down mapped
+ // into macros.
+ sema.descend_into_macros(token).into_iter().filter_map(|it| it.parent())
+ })
+ };
+
for (text, file_id, search_range) in scope_files(sema, &search_scope) {
let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
// Search for occurrences of the items name
for offset in match_indices(&text, finder, search_range) {
- for name in sema.find_nodes_at_offset_with_descend(&tree, offset) {
- if match name {
- ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink),
- ast::NameLike::Name(name) => self.found_name(&name, sink),
- ast::NameLike::Lifetime(lifetime) => self.found_lifetime(&lifetime, sink),
- } {
- return;
+ if let Some(iter) = find_nodes(name, &tree, offset) {
+ for name in iter.filter_map(ast::NameLike::cast) {
+ if match name {
+ ast::NameLike::NameRef(name_ref) => {
+ self.found_name_ref(&name_ref, sink)
+ }
+ ast::NameLike::Name(name) => self.found_name(&name, sink),
+ ast::NameLike::Lifetime(lifetime) => {
+ self.found_lifetime(&lifetime, sink)
+ }
+ } {
+ return;
+ }
}
}
}
// Search for occurrences of the `Self` referring to our type
if let Some((self_ty, finder)) = &include_self_kw_refs {
for offset in match_indices(&text, finder, search_range) {
- for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
- if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
- return;
+ if let Some(iter) = find_nodes("Self", &tree, offset) {
+ for name_ref in iter.filter_map(ast::NameRef::cast) {
+ if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
+ return;
+ }
}
}
}
@@ -493,17 +507,21 @@ impl<'a> FindUsages<'a> {
let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
for offset in match_indices(&text, finder, search_range) {
- for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
- if self.found_name_ref(&name_ref, sink) {
- return;
+ if let Some(iter) = find_nodes("super", &tree, offset) {
+ for name_ref in iter.filter_map(ast::NameRef::cast) {
+ if self.found_name_ref(&name_ref, sink) {
+ return;
+ }
}
}
}
if let Some(finder) = &is_crate_root {
for offset in match_indices(&text, finder, search_range) {
- for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
- if self.found_name_ref(&name_ref, sink) {
- return;
+ if let Some(iter) = find_nodes("crate", &tree, offset) {
+ for name_ref in iter.filter_map(ast::NameRef::cast) {
+ if self.found_name_ref(&name_ref, sink) {
+ return;
+ }
}
}
}
@@ -544,9 +562,11 @@ impl<'a> FindUsages<'a> {
let finder = &Finder::new("self");
for offset in match_indices(&text, finder, search_range) {
- for name_ref in sema.find_nodes_at_offset_with_descend(&tree, offset) {
- if self.found_self_module_name_ref(&name_ref, sink) {
- return;
+ if let Some(iter) = find_nodes("self", &tree, offset) {
+ for name_ref in iter.filter_map(ast::NameRef::cast) {
+ if self.found_self_module_name_ref(&name_ref, sink) {
+ return;
+ }
}
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
index ac6c6e8fe..313346ee1 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
@@ -104,6 +104,11 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec<Arg>), ()> {
extracted_expressions.push(Arg::Placeholder);
state = State::NotArg;
}
+ (State::MaybeArg, ':') => {
+ output.push(chr);
+ extracted_expressions.push(Arg::Placeholder);
+ state = State::FormatOpts;
+ }
(State::MaybeArg, _) => {
if matches!(chr, '\\' | '$') {
current_expr.push('\\');
@@ -118,44 +123,41 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec<Arg>), ()> {
state = State::Expr;
}
}
- (State::Ident | State::Expr, '}') => {
- if inexpr_open_count == 0 {
- output.push(chr);
-
- if matches!(state, State::Expr) {
- extracted_expressions.push(Arg::Expr(current_expr.trim().into()));
- } else {
- extracted_expressions.push(Arg::Ident(current_expr.trim().into()));
- }
-
- current_expr = String::new();
- state = State::NotArg;
- } else {
- // We're closing one brace met before inside of the expression.
- current_expr.push(chr);
- inexpr_open_count -= 1;
- }
- }
(State::Ident | State::Expr, ':') if matches!(chars.peek(), Some(':')) => {
// path separator
state = State::Expr;
current_expr.push_str("::");
chars.next();
}
- (State::Ident | State::Expr, ':') => {
+ (State::Ident | State::Expr, ':' | '}') => {
if inexpr_open_count == 0 {
- // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
- output.push(chr);
+ let trimmed = current_expr.trim();
- if matches!(state, State::Expr) {
- extracted_expressions.push(Arg::Expr(current_expr.trim().into()));
+ // if the expression consists of a single number, like "0" or "12", it can refer to
+ // format args in the order they are specified.
+ // see: https://doc.rust-lang.org/std/fmt/#positional-parameters
+ if trimmed.chars().fold(true, |only_num, c| c.is_ascii_digit() && only_num) {
+ output.push_str(trimmed);
+ } else if matches!(state, State::Expr) {
+ extracted_expressions.push(Arg::Expr(trimmed.into()));
} else {
- extracted_expressions.push(Arg::Ident(current_expr.trim().into()));
+ extracted_expressions.push(Arg::Ident(trimmed.into()));
}
- current_expr = String::new();
- state = State::FormatOpts;
- } else {
+ output.push(chr);
+ current_expr.clear();
+ state = if chr == ':' {
+ State::FormatOpts
+ } else if chr == '}' {
+ State::NotArg
+ } else {
+ unreachable!()
+ };
+ } else if chr == '}' {
+ // We're closing one brace met before inside of the expression.
+ current_expr.push(chr);
+ inexpr_open_count -= 1;
+ } else if chr == ':' {
// We're inside of braced expression, assume that it's a struct field name/value delimiter.
current_expr.push(chr);
}
@@ -219,6 +221,10 @@ mod tests {
("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]),
("{expr:?}", expect![["{:?}; expr"]]),
("{expr:1$}", expect![[r"{:1\$}; expr"]]),
+ ("{:1$}", expect![[r"{:1\$}; $1"]]),
+ ("{:>padding$}", expect![[r"{:>padding\$}; $1"]]),
+ ("{}, {}, {0}", expect![[r"{}, {}, {0}; $1, $2"]]),
+ ("{}, {}, {0:b}", expect![[r"{}, {}, {0:b}; $1, $2"]]),
("{$0}", expect![[r"{}; \$0"]]),
("{malformed", expect![["-"]]),
("malformed}", expect![["-"]]),