let kind = self.token.kind();
if kind == IDENT || kind == LIFETIME_IDENT || kind == UNDERSCORE || kind.is_keyword() {
cov_mark::hit!(completes_if_prefix_is_keyword);
- return self.original_token.text_range();
+ self.original_token.text_range()
} else if kind == CHAR {
// assume we are completing a lifetime but the user has only typed the '
cov_mark::hit!(completes_if_lifetime_without_idents);
- return TextRange::at(self.original_token.text_range().start(), TextSize::from(1));
- } else if kind == BANG {
- if let Some(n) = self.token.parent() {
- if n.kind() == SyntaxKind::MACRO_CALL {
- cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
- return n.text_range();
- }
- }
+ TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
+ } else {
+ TextRange::empty(self.position.offset)
}
-
- TextRange::empty(self.position.offset)
}
pub(crate) fn previous_token_is(&self, kind: SyntaxKind) -> bool {
}
}
+ pub(crate) fn is_immediately_after_macro_bang(&self) -> bool {
+ self.token.kind() == BANG && self.token.parent().map_or(false, |it| it.kind() == MACRO_CALL)
+ }
+
/// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
pub(crate) fn process_all_names(&self, f: &mut dyn FnMut(Name, ScopeDef)) {
self.scope.process_all_names(&mut |name, def| {
}
fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
- let mut item =
- CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label());
+ let source_range = if self.ctx.completion.is_immediately_after_macro_bang() {
+ cov_mark::hit!(completes_macro_call_if_cursor_at_bang_token);
+ self.ctx.completion.token.parent().map(|it| it.text_range())
+ } else {
+ Some(self.ctx.source_range())
+ }?;
+ let mut item = CompletionItem::new(CompletionKind::Reference, source_range, &self.label());
item.kind(SymbolKind::Macro)
.set_documentation(self.docs.clone())
.set_deprecated(self.ctx.is_deprecated(self.macro_))
"#,
)
}
+
+ #[test]
+ fn completes_macro_call_if_cursor_at_bang_token() {
+ // Regression test for https://github.com/rust-analyzer/rust-analyzer/issues/9904
+ cov_mark::check!(completes_macro_call_if_cursor_at_bang_token);
+ check_edit(
+ "foo!",
+ r#"
+macro_rules! foo {
+ () => {}
+}
+
+fn main() {
+ foo!$0
+}
+"#,
+ r#"
+macro_rules! foo {
+ () => {}
+}
+
+fn main() {
+ foo!($0)
+}
+"#,
+ );
+ }
}