Skip to content

Commit 19387d3

Browse files
committed
Auto merge of rust-lang#16060 - Veykril:format-args-orphans, r=Veykril
fix: Fix completion failing in `format_args!` with invalid template
2 parents 0395328 + cf083fe commit 19387d3

File tree

6 files changed

+187
-8
lines changed

6 files changed

+187
-8
lines changed

crates/hir-def/src/body/lower.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,11 @@ impl ExprCollector<'_> {
16111611
}
16121612
},
16131613
),
1614-
None => FormatArgs { template: Default::default(), arguments: args.finish() },
1614+
None => FormatArgs {
1615+
template: Default::default(),
1616+
arguments: args.finish(),
1617+
orphans: Default::default(),
1618+
},
16151619
};
16161620

16171621
// Create a list of all _unique_ (argument, format trait) combinations.
@@ -1750,7 +1754,13 @@ impl ExprCollector<'_> {
17501754
});
17511755
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
17521756
id: None,
1753-
statements: Box::default(),
1757+
// We collect the unused expressions here so that we still infer them instead of
1758+
// dropping them out of the expression tree
1759+
statements: fmt
1760+
.orphans
1761+
.into_iter()
1762+
.map(|expr| Statement::Expr { expr, has_semi: true })
1763+
.collect(),
17541764
tail: Some(unsafe_arg_new),
17551765
});
17561766

crates/hir-def/src/hir/format_args.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::mem;
33

44
use hir_expand::name::Name;
55
use rustc_dependencies::parse_format as parse;
6+
use stdx::TupleExt;
67
use syntax::{
78
ast::{self, IsString},
89
SmolStr, TextRange, TextSize,
@@ -14,6 +15,7 @@ use crate::hir::ExprId;
1415
pub struct FormatArgs {
1516
pub template: Box<[FormatArgsPiece]>,
1617
pub arguments: FormatArguments,
18+
pub orphans: Vec<ExprId>,
1719
}
1820

1921
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -196,7 +198,11 @@ pub(crate) fn parse(
196198
let is_source_literal = parser.is_source_literal;
197199
if !parser.errors.is_empty() {
198200
// FIXME: Diagnose
199-
return FormatArgs { template: Default::default(), arguments: args.finish() };
201+
return FormatArgs {
202+
template: Default::default(),
203+
arguments: args.finish(),
204+
orphans: vec![],
205+
};
200206
}
201207

202208
let to_span = |inner_span: parse::InnerSpan| {
@@ -419,7 +425,11 @@ pub(crate) fn parse(
419425
// FIXME: Diagnose
420426
}
421427

422-
FormatArgs { template: template.into_boxed_slice(), arguments: args.finish() }
428+
FormatArgs {
429+
template: template.into_boxed_slice(),
430+
arguments: args.finish(),
431+
orphans: unused.into_iter().map(TupleExt::head).collect(),
432+
}
423433
}
424434

425435
#[derive(Debug, Clone, PartialEq, Eq)]

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

+154
Original file line numberDiff line numberDiff line change
@@ -1094,3 +1094,157 @@ pub struct UnstableButWeAreOnNightlyAnyway;
10941094
"#]],
10951095
);
10961096
}
1097+
1098+
#[test]
1099+
fn inside_format_args_completions_work() {
1100+
check_empty(
1101+
r#"
1102+
//- minicore: fmt
1103+
struct Foo;
1104+
impl Foo {
1105+
fn foo(&self) {}
1106+
}
1107+
1108+
fn main() {
1109+
format_args!("{}", Foo.$0);
1110+
}
1111+
"#,
1112+
expect![[r#"
1113+
me foo() fn(&self)
1114+
sn box Box::new(expr)
1115+
sn call function(expr)
1116+
sn dbg dbg!(expr)
1117+
sn dbgr dbg!(&expr)
1118+
sn match match expr {}
1119+
sn ref &expr
1120+
sn refm &mut expr
1121+
sn unsafe unsafe {}
1122+
"#]],
1123+
);
1124+
check_empty(
1125+
r#"
1126+
//- minicore: fmt
1127+
struct Foo;
1128+
impl Foo {
1129+
fn foo(&self) {}
1130+
}
1131+
1132+
fn main() {
1133+
format_args!("{}", Foo.f$0);
1134+
}
1135+
"#,
1136+
expect![[r#"
1137+
me foo() fn(&self)
1138+
sn box Box::new(expr)
1139+
sn call function(expr)
1140+
sn dbg dbg!(expr)
1141+
sn dbgr dbg!(&expr)
1142+
sn match match expr {}
1143+
sn ref &expr
1144+
sn refm &mut expr
1145+
sn unsafe unsafe {}
1146+
"#]],
1147+
);
1148+
}
1149+
1150+
#[test]
1151+
fn inside_faulty_format_args_completions_work() {
1152+
check_empty(
1153+
r#"
1154+
//- minicore: fmt
1155+
struct Foo;
1156+
impl Foo {
1157+
fn foo(&self) {}
1158+
}
1159+
1160+
fn main() {
1161+
format_args!("", Foo.$0);
1162+
}
1163+
"#,
1164+
expect![[r#"
1165+
me foo() fn(&self)
1166+
sn box Box::new(expr)
1167+
sn call function(expr)
1168+
sn dbg dbg!(expr)
1169+
sn dbgr dbg!(&expr)
1170+
sn match match expr {}
1171+
sn ref &expr
1172+
sn refm &mut expr
1173+
sn unsafe unsafe {}
1174+
"#]],
1175+
);
1176+
check_empty(
1177+
r#"
1178+
//- minicore: fmt
1179+
struct Foo;
1180+
impl Foo {
1181+
fn foo(&self) {}
1182+
}
1183+
1184+
fn main() {
1185+
format_args!("", Foo.f$0);
1186+
}
1187+
"#,
1188+
expect![[r#"
1189+
me foo() fn(&self)
1190+
sn box Box::new(expr)
1191+
sn call function(expr)
1192+
sn dbg dbg!(expr)
1193+
sn dbgr dbg!(&expr)
1194+
sn match match expr {}
1195+
sn ref &expr
1196+
sn refm &mut expr
1197+
sn unsafe unsafe {}
1198+
"#]],
1199+
);
1200+
check_empty(
1201+
r#"
1202+
//- minicore: fmt
1203+
struct Foo;
1204+
impl Foo {
1205+
fn foo(&self) {}
1206+
}
1207+
1208+
fn main() {
1209+
format_args!("{} {named} {captured} {named} {}", a, named = c, Foo.f$0);
1210+
}
1211+
"#,
1212+
expect![[r#"
1213+
me foo() fn(&self)
1214+
sn box Box::new(expr)
1215+
sn call function(expr)
1216+
sn dbg dbg!(expr)
1217+
sn dbgr dbg!(&expr)
1218+
sn match match expr {}
1219+
sn ref &expr
1220+
sn refm &mut expr
1221+
sn unsafe unsafe {}
1222+
"#]],
1223+
);
1224+
check_empty(
1225+
r#"
1226+
//- minicore: fmt
1227+
struct Foo;
1228+
impl Foo {
1229+
fn foo(&self) {}
1230+
}
1231+
1232+
fn main() {
1233+
format_args!("{", Foo.f$0);
1234+
}
1235+
"#,
1236+
expect![[r#"
1237+
sn box Box::new(expr)
1238+
sn call function(expr)
1239+
sn dbg dbg!(expr)
1240+
sn dbgr dbg!(&expr)
1241+
sn if if expr {}
1242+
sn match match expr {}
1243+
sn not !expr
1244+
sn ref &expr
1245+
sn refm &mut expr
1246+
sn unsafe unsafe {}
1247+
sn while while expr {}
1248+
"#]],
1249+
);
1250+
}

crates/ide/src/view_hir.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use hir::{DefWithBody, Semantics};
22
use ide_db::base_db::FilePosition;
33
use ide_db::RootDatabase;
4-
use syntax::{algo::find_node_at_offset, ast, AstNode};
4+
use syntax::{algo::ancestors_at_offset, ast, AstNode};
55

66
// Feature: View Hir
77
//
@@ -19,7 +19,9 @@ fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
1919
let sema = Semantics::new(db);
2020
let source_file = sema.parse(position.file_id);
2121

22-
let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
22+
let item = ancestors_at_offset(source_file.syntax(), position.offset)
23+
.filter(|it| ast::MacroCall::can_cast(it.kind()))
24+
.find_map(ast::Item::cast)?;
2325
let def: DefWithBody = match item {
2426
ast::Item::Fn(it) => sema.to_def(&it)?.into(),
2527
ast::Item::Const(it) => sema.to_def(&it)?.into(),

crates/ide/src/view_mir.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use hir::{DefWithBody, Semantics};
22
use ide_db::base_db::FilePosition;
33
use ide_db::RootDatabase;
4-
use syntax::{algo::find_node_at_offset, ast, AstNode};
4+
use syntax::{algo::ancestors_at_offset, ast, AstNode};
55

66
// Feature: View Mir
77
//
@@ -18,7 +18,9 @@ fn body_mir(db: &RootDatabase, position: FilePosition) -> Option<String> {
1818
let sema = Semantics::new(db);
1919
let source_file = sema.parse(position.file_id);
2020

21-
let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
21+
let item = ancestors_at_offset(source_file.syntax(), position.offset)
22+
.filter(|it| ast::MacroCall::can_cast(it.kind()))
23+
.find_map(ast::Item::cast)?;
2224
let def: DefWithBody = match item {
2325
ast::Item::Fn(it) => sema.to_def(&it)?.into(),
2426
ast::Item::Const(it) => sema.to_def(&it)?.into(),

crates/rust-analyzer/tests/slow-tests/tidy.rs

+1
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ fn check_dbg(path: &Path, text: &str) {
250250
// We have .dbg postfix
251251
"ide-completion/src/completions/postfix.rs",
252252
"ide-completion/src/completions/keyword.rs",
253+
"ide-completion/src/tests/expression.rs",
253254
"ide-completion/src/tests/proc_macros.rs",
254255
// The documentation in string literals may contain anything for its own purposes
255256
"ide-completion/src/lib.rs",

0 commit comments

Comments
 (0)