Skip to content

Commit 0b32b65

Browse files
committed
Auto merge of #14043 - lowr:fix/completion-within-str-that-changed, r=Veykril
fix: consider relative offset to fake ident token in expansion for completion Fixes #13836 When we check if the offset of fake ident token is out of bounds in the "actual expansion" (i.e. expansion without the fake ident token), we should take relative offset to it into account to match [how we'd get token after expansion](https://github.com/rust-lang/rust-analyzer/blob/f1b257f4eb4fef74b42fd7135d1cf3884e8b51c9/crates/ide-completion/src/context/analysis.rs#L53-L54).
2 parents 3bc33c7 + a4d0b5c commit 0b32b65

File tree

3 files changed

+96
-5
lines changed

3 files changed

+96
-5
lines changed

crates/base-db/src/fixture.rs

+60-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
66
use test_utils::{
77
extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER,
88
};
9-
use tt::token_id::Subtree;
9+
use tt::token_id::{Leaf, Subtree, TokenTree};
1010
use vfs::{file_set::FileSet, VfsPath};
1111

1212
use crate::{
@@ -310,7 +310,7 @@ impl ChangeFixture {
310310
}
311311
}
312312

313-
fn default_test_proc_macros() -> [(String, ProcMacro); 4] {
313+
fn default_test_proc_macros() -> [(String, ProcMacro); 5] {
314314
[
315315
(
316316
r#"
@@ -368,6 +368,20 @@ pub fn mirror(input: TokenStream) -> TokenStream {
368368
expander: Arc::new(MirrorProcMacroExpander),
369369
},
370370
),
371+
(
372+
r#"
373+
#[proc_macro]
374+
pub fn shorten(input: TokenStream) -> TokenStream {
375+
loop {}
376+
}
377+
"#
378+
.into(),
379+
ProcMacro {
380+
name: "shorten".into(),
381+
kind: crate::ProcMacroKind::FuncLike,
382+
expander: Arc::new(ShortenProcMacroExpander),
383+
},
384+
),
371385
]
372386
}
373387

@@ -508,3 +522,47 @@ impl ProcMacroExpander for MirrorProcMacroExpander {
508522
Ok(traverse(input))
509523
}
510524
}
525+
526+
// Replaces every literal with an empty string literal and every identifier with its first letter,
527+
// but retains all tokens' span. Useful for testing we don't assume token hasn't been modified by
528+
// macros even if it retains its span.
529+
#[derive(Debug)]
530+
struct ShortenProcMacroExpander;
531+
impl ProcMacroExpander for ShortenProcMacroExpander {
532+
fn expand(
533+
&self,
534+
input: &Subtree,
535+
_: Option<&Subtree>,
536+
_: &Env,
537+
) -> Result<Subtree, ProcMacroExpansionError> {
538+
return Ok(traverse(input));
539+
540+
fn traverse(input: &Subtree) -> Subtree {
541+
let token_trees = input
542+
.token_trees
543+
.iter()
544+
.map(|it| match it {
545+
TokenTree::Leaf(leaf) => tt::TokenTree::Leaf(modify_leaf(leaf)),
546+
TokenTree::Subtree(subtree) => tt::TokenTree::Subtree(traverse(subtree)),
547+
})
548+
.collect();
549+
Subtree { delimiter: input.delimiter, token_trees }
550+
}
551+
552+
fn modify_leaf(leaf: &Leaf) -> Leaf {
553+
let mut leaf = leaf.clone();
554+
match &mut leaf {
555+
Leaf::Literal(it) => {
556+
// XXX Currently replaces any literals with an empty string, but supporting
557+
// "shortening" other literals would be nice.
558+
it.text = "\"\"".into();
559+
}
560+
Leaf::Punct(_) => {}
561+
Leaf::Ident(it) => {
562+
it.text = it.text.chars().take(1).collect();
563+
}
564+
}
565+
leaf
566+
}
567+
}
568+
}

crates/ide-completion/src/context/analysis.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ pub(super) fn expand_and_analyze(
4848
// make the offset point to the start of the original token, as that is what the
4949
// intermediate offsets calculated in expansion always points to
5050
let offset = offset - relative_offset;
51-
let expansion = expand(sema, original_file, speculative_file, offset, fake_ident_token);
51+
let expansion =
52+
expand(sema, original_file, speculative_file, offset, fake_ident_token, relative_offset);
53+
5254
// add the relative offset back, so that left_biased finds the proper token
5355
let offset = expansion.offset + relative_offset;
5456
let token = expansion.original_file.token_at_offset(offset).left_biased()?;
@@ -67,6 +69,7 @@ fn expand(
6769
mut speculative_file: SyntaxNode,
6870
mut offset: TextSize,
6971
mut fake_ident_token: SyntaxToken,
72+
relative_offset: TextSize,
7073
) -> ExpansionResult {
7174
let _p = profile::span("CompletionContext::expand");
7275
let mut derive_ctx = None;
@@ -97,7 +100,7 @@ fn expand(
97100
// successful expansions
98101
(Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
99102
let new_offset = fake_mapped_token.text_range().start();
100-
if new_offset > actual_expansion.text_range().end() {
103+
if new_offset + relative_offset > actual_expansion.text_range().end() {
101104
// offset outside of bounds from the original expansion,
102105
// stop here to prevent problems from happening
103106
break 'expansion;
@@ -176,7 +179,7 @@ fn expand(
176179
// successful expansions
177180
(Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
178181
let new_offset = fake_mapped_token.text_range().start();
179-
if new_offset > actual_expansion.text_range().end() {
182+
if new_offset + relative_offset > actual_expansion.text_range().end() {
180183
// offset outside of bounds from the original expansion,
181184
// stop here to prevent problems from happening
182185
break 'expansion;

crates/ide-completion/src/tests/proc_macros.rs

+30
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,33 @@ fn main() {}
131131
"#]],
132132
)
133133
}
134+
135+
#[test]
136+
fn issue_13836_str() {
137+
check(
138+
r#"
139+
//- proc_macros: shorten
140+
fn main() {
141+
let s = proc_macros::shorten!("text.$0");
142+
}
143+
"#,
144+
expect![[r#""#]],
145+
)
146+
}
147+
148+
#[test]
149+
fn issue_13836_ident() {
150+
check(
151+
r#"
152+
//- proc_macros: shorten
153+
struct S;
154+
impl S {
155+
fn foo(&self) {}
156+
}
157+
fn main() {
158+
let s = proc_macros::shorten!(S.fo$0);
159+
}
160+
"#,
161+
expect![[r#""#]],
162+
)
163+
}

0 commit comments

Comments
 (0)