mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
Fix 14142: Annotate lifetime paramaters in doctest runnables
This commit is contained in:
parent
c867cbf9b6
commit
9942cc425b
3 changed files with 155 additions and 6 deletions
|
@ -459,6 +459,13 @@ impl Resolver {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generic_params(&self) -> Option<&Interned<GenericParams>> {
|
||||||
|
self.scopes().find_map(|scope| match scope {
|
||||||
|
Scope::GenericParams { params, .. } => Some(params),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn body_owner(&self) -> Option<DefWithBodyId> {
|
pub fn body_owner(&self) -> Option<DefWithBodyId> {
|
||||||
self.scopes().find_map(|scope| match scope {
|
self.scopes().find_map(|scope| match scope {
|
||||||
Scope::ExprScope(it) => Some(it.owner),
|
Scope::ExprScope(it) => Some(it.owner),
|
||||||
|
|
|
@ -42,7 +42,7 @@ use hir_def::{
|
||||||
adt::VariantData,
|
adt::VariantData,
|
||||||
body::{BodyDiagnostic, SyntheticSyntax},
|
body::{BodyDiagnostic, SyntheticSyntax},
|
||||||
expr::{BindingAnnotation, ExprOrPatId, LabelId, Pat, PatId},
|
expr::{BindingAnnotation, ExprOrPatId, LabelId, Pat, PatId},
|
||||||
generics::{TypeOrConstParamData, TypeParamProvenance},
|
generics::{TypeOrConstParamData, TypeParamProvenance, LifetimeParamData},
|
||||||
item_tree::ItemTreeNode,
|
item_tree::ItemTreeNode,
|
||||||
lang_item::{LangItem, LangItemTarget},
|
lang_item::{LangItem, LangItemTarget},
|
||||||
layout::{Layout, LayoutError, ReprOptions},
|
layout::{Layout, LayoutError, ReprOptions},
|
||||||
|
@ -1170,6 +1170,22 @@ impl Adt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the lifetime of the DataType
|
||||||
|
pub fn lifetime(&self, db: &dyn HirDatabase) -> Option<LifetimeParamData> {
|
||||||
|
let resolver = match self {
|
||||||
|
Adt::Struct(s) => s.id.resolver(db.upcast()),
|
||||||
|
Adt::Union(u) => u.id.resolver(db.upcast()),
|
||||||
|
Adt::Enum(e) => e.id.resolver(db.upcast()),
|
||||||
|
};
|
||||||
|
resolver.generic_params().and_then(|gp| {
|
||||||
|
(&gp.lifetimes)
|
||||||
|
.iter()
|
||||||
|
// there should only be a single lifetime
|
||||||
|
// but `Arena` requires to use an iterator
|
||||||
|
.nth(0)
|
||||||
|
}).map(|arena| arena.1.clone())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_enum(&self) -> Option<Enum> {
|
pub fn as_enum(&self) -> Option<Enum> {
|
||||||
if let Self::Enum(v) = self {
|
if let Self::Enum(v) = self {
|
||||||
Some(*v)
|
Some(*v)
|
||||||
|
@ -3339,6 +3355,25 @@ impl Type {
|
||||||
.map(move |ty| self.derived(ty))
|
.map(move |ty| self.derived(ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Combines lifetime indicators and type arguments into a single `Vec<SmolStr>`
|
||||||
|
pub fn lifetime_and_type_arguments<'a>(&'a self, db: &'a dyn HirDatabase) -> Vec<SmolStr> {
|
||||||
|
let mut names = if let Some(lt) = self
|
||||||
|
.as_adt()
|
||||||
|
.and_then(|a| {
|
||||||
|
a.lifetime(db)
|
||||||
|
.and_then(|lt| Some((<.name).to_smol_str().clone()))
|
||||||
|
}) {
|
||||||
|
vec![lt]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
for ty in self.type_arguments() {
|
||||||
|
names.push(SmolStr::new(ty.display(db).to_string()))
|
||||||
|
}
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
pub fn iterate_method_candidates_with_traits<T>(
|
pub fn iterate_method_candidates_with_traits<T>(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
||||||
|
|
||||||
use ast::HasName;
|
use ast::HasName;
|
||||||
use cfg::CfgExpr;
|
use cfg::CfgExpr;
|
||||||
use hir::{AsAssocItem, HasAttrs, HasSource, HirDisplay, Semantics};
|
use hir::{AsAssocItem, HasAttrs, HasSource, Semantics};
|
||||||
use ide_assists::utils::test_related_attribute;
|
use ide_assists::utils::test_related_attribute;
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::{FilePosition, FileRange},
|
base_db::{FilePosition, FileRange},
|
||||||
|
@ -370,9 +370,9 @@ pub(crate) fn runnable_impl(
|
||||||
let nav = def.try_to_nav(sema.db)?;
|
let nav = def.try_to_nav(sema.db)?;
|
||||||
let ty = def.self_ty(sema.db);
|
let ty = def.self_ty(sema.db);
|
||||||
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.lifetime_and_type_arguments(sema.db).into_iter().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)))
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
};
|
};
|
||||||
|
@ -436,13 +436,13 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
|
||||||
let ty = imp.self_ty(db);
|
let ty = imp.self_ty(db);
|
||||||
if let Some(adt) = ty.as_adt() {
|
if let Some(adt) = ty.as_adt() {
|
||||||
let name = adt.name(db);
|
let name = adt.name(db);
|
||||||
let mut ty_args = ty.type_arguments().peekable();
|
let mut ty_args = ty.lifetime_and_type_arguments(db).into_iter().peekable();
|
||||||
format_to!(path, "{}", name);
|
format_to!(path, "{}", name);
|
||||||
if ty_args.peek().is_some() {
|
if ty_args.peek().is_some() {
|
||||||
format_to!(
|
format_to!(
|
||||||
path,
|
path,
|
||||||
"<{}>",
|
"<{}>",
|
||||||
ty_args.format_with(",", |ty, cb| cb(&ty.display(db)))
|
ty_args.format_with(",", |ty, cb| cb(&ty))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
format_to!(path, "::{}", def_name);
|
format_to!(path, "::{}", def_name);
|
||||||
|
@ -999,6 +999,113 @@ impl Data {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_runnables_doc_test_in_impl_with_lifetime() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs
|
||||||
|
$0
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
struct Data<'a>;
|
||||||
|
impl Data<'a> {
|
||||||
|
/// ```
|
||||||
|
/// let x = 5;
|
||||||
|
/// ```
|
||||||
|
fn foo() {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
&[Bin, DocTest],
|
||||||
|
expect![[r#"
|
||||||
|
[
|
||||||
|
Runnable {
|
||||||
|
use_name_in_title: false,
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
full_range: 1..13,
|
||||||
|
focus_range: 4..8,
|
||||||
|
name: "main",
|
||||||
|
kind: Function,
|
||||||
|
},
|
||||||
|
kind: Bin,
|
||||||
|
cfg: None,
|
||||||
|
},
|
||||||
|
Runnable {
|
||||||
|
use_name_in_title: false,
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
full_range: 52..106,
|
||||||
|
name: "foo",
|
||||||
|
},
|
||||||
|
kind: DocTest {
|
||||||
|
test_id: Path(
|
||||||
|
"Data<'a>::foo",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
cfg: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_runnables_doc_test_in_impl_with_lifetime_and_types() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs
|
||||||
|
$0
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
struct Data<'a, T, U>;
|
||||||
|
impl<T, U> Data<'a, T, U> {
|
||||||
|
/// ```
|
||||||
|
/// let x = 5;
|
||||||
|
/// ```
|
||||||
|
fn foo() {}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
&[Bin, DocTest],
|
||||||
|
expect![[r#"
|
||||||
|
[
|
||||||
|
Runnable {
|
||||||
|
use_name_in_title: false,
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
full_range: 1..13,
|
||||||
|
focus_range: 4..8,
|
||||||
|
name: "main",
|
||||||
|
kind: Function,
|
||||||
|
},
|
||||||
|
kind: Bin,
|
||||||
|
cfg: None,
|
||||||
|
},
|
||||||
|
Runnable {
|
||||||
|
use_name_in_title: false,
|
||||||
|
nav: NavigationTarget {
|
||||||
|
file_id: FileId(
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
full_range: 70..124,
|
||||||
|
name: "foo",
|
||||||
|
},
|
||||||
|
kind: DocTest {
|
||||||
|
test_id: Path(
|
||||||
|
"Data<'a,T,U>::foo",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
cfg: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_runnables_module() {
|
fn test_runnables_module() {
|
||||||
check(
|
check(
|
||||||
|
|
Loading…
Reference in a new issue