mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 15:01:51 +00:00
fix: Fix completion failing in format_args! with invalid template
This commit is contained in:
parent
b1a8f83a0c
commit
cf083fefc4
@ -1611,7 +1611,11 @@ impl ExprCollector<'_> {
|
||||
}
|
||||
},
|
||||
),
|
||||
None => FormatArgs { template: Default::default(), arguments: args.finish() },
|
||||
None => FormatArgs {
|
||||
template: Default::default(),
|
||||
arguments: args.finish(),
|
||||
orphans: Default::default(),
|
||||
},
|
||||
};
|
||||
|
||||
// Create a list of all _unique_ (argument, format trait) combinations.
|
||||
@ -1750,7 +1754,13 @@ impl ExprCollector<'_> {
|
||||
});
|
||||
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
|
||||
id: None,
|
||||
statements: Box::default(),
|
||||
// We collect the unused expressions here so that we still infer them instead of
|
||||
// dropping them out of the expression tree
|
||||
statements: fmt
|
||||
.orphans
|
||||
.into_iter()
|
||||
.map(|expr| Statement::Expr { expr, has_semi: true })
|
||||
.collect(),
|
||||
tail: Some(unsafe_arg_new),
|
||||
});
|
||||
|
||||
|
@ -3,6 +3,7 @@ use std::mem;
|
||||
|
||||
use hir_expand::name::Name;
|
||||
use rustc_dependencies::parse_format as parse;
|
||||
use stdx::TupleExt;
|
||||
use syntax::{
|
||||
ast::{self, IsString},
|
||||
SmolStr, TextRange, TextSize,
|
||||
@ -14,6 +15,7 @@ use crate::hir::ExprId;
|
||||
pub struct FormatArgs {
|
||||
pub template: Box<[FormatArgsPiece]>,
|
||||
pub arguments: FormatArguments,
|
||||
pub orphans: Vec<ExprId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -196,7 +198,11 @@ pub(crate) fn parse(
|
||||
let is_source_literal = parser.is_source_literal;
|
||||
if !parser.errors.is_empty() {
|
||||
// FIXME: Diagnose
|
||||
return FormatArgs { template: Default::default(), arguments: args.finish() };
|
||||
return FormatArgs {
|
||||
template: Default::default(),
|
||||
arguments: args.finish(),
|
||||
orphans: vec![],
|
||||
};
|
||||
}
|
||||
|
||||
let to_span = |inner_span: parse::InnerSpan| {
|
||||
@ -419,7 +425,11 @@ pub(crate) fn parse(
|
||||
// FIXME: Diagnose
|
||||
}
|
||||
|
||||
FormatArgs { template: template.into_boxed_slice(), arguments: args.finish() }
|
||||
FormatArgs {
|
||||
template: template.into_boxed_slice(),
|
||||
arguments: args.finish(),
|
||||
orphans: unused.into_iter().map(TupleExt::head).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
|
@ -1094,3 +1094,157 @@ pub struct UnstableButWeAreOnNightlyAnyway;
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inside_format_args_completions_work() {
|
||||
check_empty(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
format_args!("{}", Foo.$0);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
format_args!("{}", Foo.f$0);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inside_faulty_format_args_completions_work() {
|
||||
check_empty(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
format_args!("", Foo.$0);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
format_args!("", Foo.f$0);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
format_args!("{} {named} {captured} {named} {}", a, named = c, Foo.f$0);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() fn(&self)
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn match match expr {}
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn unsafe unsafe {}
|
||||
"#]],
|
||||
);
|
||||
check_empty(
|
||||
r#"
|
||||
//- minicore: fmt
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
format_args!("{", Foo.f$0);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
sn box Box::new(expr)
|
||||
sn call function(expr)
|
||||
sn dbg dbg!(expr)
|
||||
sn dbgr dbg!(&expr)
|
||||
sn if if expr {}
|
||||
sn match match expr {}
|
||||
sn not !expr
|
||||
sn ref &expr
|
||||
sn refm &mut expr
|
||||
sn unsafe unsafe {}
|
||||
sn while while expr {}
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use hir::{DefWithBody, Semantics};
|
||||
use ide_db::base_db::FilePosition;
|
||||
use ide_db::RootDatabase;
|
||||
use syntax::{algo::find_node_at_offset, ast, AstNode};
|
||||
use syntax::{algo::ancestors_at_offset, ast, AstNode};
|
||||
|
||||
// Feature: View Hir
|
||||
//
|
||||
@ -19,7 +19,9 @@ fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
|
||||
let sema = Semantics::new(db);
|
||||
let source_file = sema.parse(position.file_id);
|
||||
|
||||
let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
|
||||
let item = ancestors_at_offset(source_file.syntax(), position.offset)
|
||||
.filter(|it| ast::MacroCall::can_cast(it.kind()))
|
||||
.find_map(ast::Item::cast)?;
|
||||
let def: DefWithBody = match item {
|
||||
ast::Item::Fn(it) => sema.to_def(&it)?.into(),
|
||||
ast::Item::Const(it) => sema.to_def(&it)?.into(),
|
||||
|
@ -1,7 +1,7 @@
|
||||
use hir::{DefWithBody, Semantics};
|
||||
use ide_db::base_db::FilePosition;
|
||||
use ide_db::RootDatabase;
|
||||
use syntax::{algo::find_node_at_offset, ast, AstNode};
|
||||
use syntax::{algo::ancestors_at_offset, ast, AstNode};
|
||||
|
||||
// Feature: View Mir
|
||||
//
|
||||
@ -18,7 +18,9 @@ fn body_mir(db: &RootDatabase, position: FilePosition) -> Option<String> {
|
||||
let sema = Semantics::new(db);
|
||||
let source_file = sema.parse(position.file_id);
|
||||
|
||||
let item = find_node_at_offset::<ast::Item>(source_file.syntax(), position.offset)?;
|
||||
let item = ancestors_at_offset(source_file.syntax(), position.offset)
|
||||
.filter(|it| ast::MacroCall::can_cast(it.kind()))
|
||||
.find_map(ast::Item::cast)?;
|
||||
let def: DefWithBody = match item {
|
||||
ast::Item::Fn(it) => sema.to_def(&it)?.into(),
|
||||
ast::Item::Const(it) => sema.to_def(&it)?.into(),
|
||||
|
@ -250,6 +250,7 @@ fn check_dbg(path: &Path, text: &str) {
|
||||
// We have .dbg postfix
|
||||
"ide-completion/src/completions/postfix.rs",
|
||||
"ide-completion/src/completions/keyword.rs",
|
||||
"ide-completion/src/tests/expression.rs",
|
||||
"ide-completion/src/tests/proc_macros.rs",
|
||||
// The documentation in string literals may contain anything for its own purposes
|
||||
"ide-completion/src/lib.rs",
|
||||
|
Loading…
Reference in New Issue
Block a user