From 9957bb361dac0f1edcadf3753bef13f543d57228 Mon Sep 17 00:00:00 2001 From: Jonas Marcello Date: Fri, 24 Feb 2023 21:09:16 +0100 Subject: [PATCH] Add const generics to doctest names for structt --- crates/hir/src/lib.rs | 35 +++++++++++- crates/ide/src/runnables.rs | 108 ++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 2 deletions(-) diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 883838293e..369f9192d1 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -42,7 +42,7 @@ use hir_def::{ adt::VariantData, body::{BodyDiagnostic, SyntheticSyntax}, expr::{BindingAnnotation, ExprOrPatId, LabelId, Pat, PatId}, - generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, + generics::{ConstParamData, LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, item_tree::ItemTreeNode, lang_item::{LangItem, LangItemTarget}, layout::{Layout, LayoutError, ReprOptions}, @@ -1189,6 +1189,31 @@ impl Adt { .map(|arena| arena.1.clone()) } + /// Returns an iterator of all `const` generic paramaters + /// + /// This method is not well optimized, I could not statisfy the borrow + /// checker. I'm sure there are smarter ways to return the consts names + pub fn consts(&self, db: &dyn HirDatabase) -> impl Iterator { + 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() + .map_or(vec![], |gp| { + gp.as_ref() + .type_or_consts + .iter() + .filter_map(|arena| match arena.1 { + TypeOrConstParamData::ConstParamData(consts) => Some(consts.clone()), + _ => None, + }) + .collect::>() + }) + .into_iter() + } + pub fn as_enum(&self) -> Option { if let Self::Enum(v) = self { Some(*v) @@ -3358,15 +3383,21 @@ impl Type { .map(move |ty| self.derived(ty)) } - /// Combines lifetime indicators and type arguments into a single `Iterator` + /// Combines lifetime indicators, type and constant parameters into a single `Iterator` pub fn lifetime_and_type_arguments<'a>( &'a self, db: &'a dyn HirDatabase, ) -> impl Iterator + 'a { + // iterate the lifetime self.as_adt() .and_then(|a| a.lifetime(db).and_then(|lt| Some((<.name).to_smol_str()))) .into_iter() + // add the type paramaters .chain(self.type_arguments().map(|ty| SmolStr::new(ty.display(db).to_string()))) + // add const paramameters + .chain(self.as_adt().map_or(vec![], |a| { + a.consts(db).map(|cs| cs.name.to_smol_str()).collect::>() + })) } pub fn iterate_method_candidates_with_traits( diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index b0477e9678..7af969c5d0 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs @@ -1102,6 +1102,114 @@ impl Data<'a, T, U> { "#]], ); } + + #[test] + fn test_runnables_doc_test_in_impl_with_const() { + check( + r#" +//- /lib.rs +$0 +fn main() {} + +struct Data; +impl Data { + /// ``` + /// 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: 79..133, + name: "foo", + }, + kind: DocTest { + test_id: Path( + "Data::foo", + ), + }, + cfg: None, + }, + ] + "#]], + ); + } + + #[test] + fn test_runnables_doc_test_in_impl_with_lifetime_types_and_const() { + check( + r#" +//- /lib.rs +$0 +fn main() {} + +struct Data<'a, T, const N: usize>; +impl<'a, T, const N: usize> Data<'a, T, N> { + /// ``` + /// 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: 100..154, + name: "foo", + }, + kind: DocTest { + test_id: Path( + "Data<'a,T,N>::foo", + ), + }, + cfg: None, + }, + ] + "#]], + ); + } #[test] fn test_runnables_module() { check(