mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
Auto merge of #12918 - lowr:fix/doctest-names, r=Veykril
fix: remove whitespaces from doctest names When rustdoc runs doctests, it removes whitespaces from the tests' path ([code](25bb1c13bd/src/librustdoc/doctest.rs (L951)
)). See https://github.com/rust-lang/rust/pull/89422 for details. Interestingly enough, "Run doctest" has been working without much problem even though rust-analyzer hasn't followed the change. This is because cargo passes the test name to rustdoc via `--test-args` option, and then rustdoc [splits it by whitespace](25bb1c13bd/src/librustdoc/config.rs (L513-L514)
); the last element of the split test name **always** matches the test name that rustdoc generates. However, it may run other tests unexpectedly (to be precise, this has long since been a thing because of the split). Consider the following example: ```rust struct A<T, U>(T, U); struct B<T, U>(T, U); /// ``` /// doctest here /// ``` impl<T, U> A<T, U> {} /// ``` /// doctest here /// ``` impl<T, U> B<T, U> {} ``` When you "Run doctest" either of the two, rustdoc considers "U>" one of the test specs and both doctests are run. This patch fixes it by following rustdoc and removing the whitespace from the doctests' name.
This commit is contained in:
commit
5edbdd127a
1 changed files with 71 additions and 6 deletions
|
@ -373,11 +373,13 @@ pub(crate) fn runnable_impl(
|
||||||
let adt_name = ty.as_adt()?.name(sema.db);
|
let adt_name = ty.as_adt()?.name(sema.db);
|
||||||
let mut ty_args = ty.type_arguments().peekable();
|
let mut ty_args = ty.type_arguments().peekable();
|
||||||
let params = if ty_args.peek().is_some() {
|
let params = if ty_args.peek().is_some() {
|
||||||
format!("<{}>", ty_args.format_with(", ", |ty, cb| cb(&ty.display(sema.db))))
|
format!("<{}>", ty_args.format_with(",", |ty, cb| cb(&ty.display(sema.db))))
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
let test_id = TestId::Path(format!("{}{}", adt_name, params));
|
let mut test_id = format!("{}{}", adt_name, params);
|
||||||
|
test_id.retain(|c| c != ' ');
|
||||||
|
let test_id = TestId::Path(test_id);
|
||||||
|
|
||||||
Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg })
|
Some(Runnable { use_name_in_title: false, nav, kind: RunnableKind::DocTest { test_id }, cfg })
|
||||||
}
|
}
|
||||||
|
@ -441,10 +443,11 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
|
||||||
format_to!(
|
format_to!(
|
||||||
path,
|
path,
|
||||||
"<{}>",
|
"<{}>",
|
||||||
ty_args.format_with(", ", |ty, cb| cb(&ty.display(db)))
|
ty_args.format_with(",", |ty, cb| cb(&ty.display(db)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
format_to!(path, "::{}", def_name);
|
format_to!(path, "::{}", def_name);
|
||||||
|
path.retain(|c| c != ' ');
|
||||||
return Some(path);
|
return Some(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2067,13 +2070,23 @@ mod tests {
|
||||||
$0
|
$0
|
||||||
struct Foo<T, U>;
|
struct Foo<T, U>;
|
||||||
|
|
||||||
|
/// ```
|
||||||
|
/// ```
|
||||||
impl<T, U> Foo<T, U> {
|
impl<T, U> Foo<T, U> {
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// ````
|
/// ````
|
||||||
fn t() {}
|
fn t() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ```
|
||||||
|
/// ```
|
||||||
|
impl Foo<Foo<(), ()>, ()> {
|
||||||
|
/// ```
|
||||||
|
/// ```
|
||||||
|
fn t() {}
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
&[DocTest],
|
&[DocTest, DocTest, DocTest, DocTest],
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
[
|
[
|
||||||
Runnable {
|
Runnable {
|
||||||
|
@ -2082,12 +2095,64 @@ impl<T, U> Foo<T, U> {
|
||||||
file_id: FileId(
|
file_id: FileId(
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
full_range: 47..85,
|
full_range: 20..103,
|
||||||
|
focus_range: 47..56,
|
||||||
|
name: "impl",
|
||||||
|
kind: Impl,
|
||||||
|
},
|
||||||
|
kind: DocTest {
|
||||||
|
test_id: Path(
|
||||||
|
"Foo<T,U>",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
cfg: None,
|
||||||
|
},
|
||||||
|
Runnable {
|
||||||
|
use_name_in_title: false,
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
full_range: 63..101,
|
||||||
name: "t",
|
name: "t",
|
||||||
},
|
},
|
||||||
kind: DocTest {
|
kind: DocTest {
|
||||||
test_id: Path(
|
test_id: Path(
|
||||||
"Foo<T, U>::t",
|
"Foo<T,U>::t",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
cfg: None,
|
||||||
|
},
|
||||||
|
Runnable {
|
||||||
|
use_name_in_title: false,
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
full_range: 105..188,
|
||||||
|
focus_range: 126..146,
|
||||||
|
name: "impl",
|
||||||
|
kind: Impl,
|
||||||
|
},
|
||||||
|
kind: DocTest {
|
||||||
|
test_id: Path(
|
||||||
|
"Foo<Foo<(),()>,()>",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
cfg: None,
|
||||||
|
},
|
||||||
|
Runnable {
|
||||||
|
use_name_in_title: false,
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
full_range: 153..186,
|
||||||
|
name: "t",
|
||||||
|
},
|
||||||
|
kind: DocTest {
|
||||||
|
test_id: Path(
|
||||||
|
"Foo<Foo<(),()>,()>::t",
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
cfg: None,
|
cfg: None,
|
||||||
|
|
Loading…
Reference in a new issue