Merge #7260
7260: Render Fn* trait objects and impl types as rust does r=matklad a=Veykril Also fixes raw ptr impl types being rendered ambiguously with multiple predicates. This moves out the `FamousDefs::Fixture` into its own file as well, cause I figured it is big enough to get its own file at this point + we also get highlighting this way when editing it. Fixes #3012 Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
39167b97d8
@ -1,14 +1,15 @@
|
|||||||
//! FIXME: write short doc here
|
//! FIXME: write short doc here
|
||||||
|
|
||||||
use std::fmt;
|
use std::{borrow::Cow, fmt};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate,
|
db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate,
|
||||||
Lifetime, Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
|
Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
|
||||||
};
|
};
|
||||||
|
use arrayvec::ArrayVec;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
|
db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId,
|
||||||
Lookup, ModuleId,
|
AssocContainerId, HasModule, Lookup, ModuleId, TraitId,
|
||||||
};
|
};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
|
|
||||||
@ -257,25 +258,45 @@ impl HirDisplay for ApplicationTy {
|
|||||||
t.hir_fmt(f)?;
|
t.hir_fmt(f)?;
|
||||||
write!(f, "; _]")?;
|
write!(f, "; _]")?;
|
||||||
}
|
}
|
||||||
TypeCtor::RawPtr(m) => {
|
TypeCtor::RawPtr(m) | TypeCtor::Ref(m) => {
|
||||||
let t = self.parameters.as_single();
|
|
||||||
|
|
||||||
write!(f, "*{}", m.as_keyword_for_ptr())?;
|
|
||||||
if matches!(t, Ty::Dyn(predicates) if predicates.len() > 1) {
|
|
||||||
write!(f, "(")?;
|
|
||||||
t.hir_fmt(f)?;
|
|
||||||
write!(f, ")")?;
|
|
||||||
} else {
|
|
||||||
t.hir_fmt(f)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeCtor::Ref(m) => {
|
|
||||||
let t = self.parameters.as_single();
|
let t = self.parameters.as_single();
|
||||||
let ty_display =
|
let ty_display =
|
||||||
t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
|
t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
|
||||||
|
|
||||||
write!(f, "&{}", m.as_keyword_for_ref())?;
|
if matches!(self.ctor, TypeCtor::RawPtr(_)) {
|
||||||
if matches!(t, Ty::Dyn(predicates) if predicates.len() > 1) {
|
write!(f, "*{}", m.as_keyword_for_ptr())?;
|
||||||
|
} else {
|
||||||
|
write!(f, "&{}", m.as_keyword_for_ref())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let datas;
|
||||||
|
let predicates = match t {
|
||||||
|
Ty::Dyn(predicates) if predicates.len() > 1 => {
|
||||||
|
Cow::Borrowed(predicates.as_ref())
|
||||||
|
}
|
||||||
|
&Ty::Opaque(OpaqueTy {
|
||||||
|
opaque_ty_id: OpaqueTyId::ReturnTypeImplTrait(func, idx),
|
||||||
|
ref parameters,
|
||||||
|
}) => {
|
||||||
|
datas =
|
||||||
|
f.db.return_type_impl_traits(func).expect("impl trait id without data");
|
||||||
|
let data = (*datas)
|
||||||
|
.as_ref()
|
||||||
|
.map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
|
||||||
|
let bounds = data.subst(parameters);
|
||||||
|
Cow::Owned(bounds.value)
|
||||||
|
}
|
||||||
|
_ => Cow::Borrowed(&[][..]),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() {
|
||||||
|
let trait_ = trait_ref.trait_;
|
||||||
|
if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) {
|
||||||
|
return write!(f, "{}", ty_display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if predicates.len() > 1 {
|
||||||
write!(f, "(")?;
|
write!(f, "(")?;
|
||||||
write!(f, "{}", ty_display)?;
|
write!(f, "{}", ty_display)?;
|
||||||
write!(f, ")")?;
|
write!(f, ")")?;
|
||||||
@ -595,6 +616,17 @@ impl HirDisplay for FnSig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> {
|
||||||
|
let krate = trait_.lookup(db).container.module(db).krate;
|
||||||
|
let fn_traits = [
|
||||||
|
db.lang_item(krate, "fn".into()),
|
||||||
|
db.lang_item(krate, "fn_mut".into()),
|
||||||
|
db.lang_item(krate, "fn_once".into()),
|
||||||
|
];
|
||||||
|
// FIXME: Replace ArrayVec when into_iter is a thing on arrays
|
||||||
|
ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_bounds_like_dyn_trait(
|
pub fn write_bounds_like_dyn_trait(
|
||||||
predicates: &[GenericPredicate],
|
predicates: &[GenericPredicate],
|
||||||
f: &mut HirFormatter,
|
f: &mut HirFormatter,
|
||||||
@ -607,10 +639,15 @@ pub fn write_bounds_like_dyn_trait(
|
|||||||
// predicate for that trait).
|
// predicate for that trait).
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
let mut angle_open = false;
|
let mut angle_open = false;
|
||||||
|
let mut is_fn_trait = false;
|
||||||
for p in predicates.iter() {
|
for p in predicates.iter() {
|
||||||
match p {
|
match p {
|
||||||
GenericPredicate::Implemented(trait_ref) => {
|
GenericPredicate::Implemented(trait_ref) => {
|
||||||
if angle_open {
|
let trait_ = trait_ref.trait_;
|
||||||
|
if !is_fn_trait {
|
||||||
|
is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
|
||||||
|
}
|
||||||
|
if !is_fn_trait && angle_open {
|
||||||
write!(f, ">")?;
|
write!(f, ">")?;
|
||||||
angle_open = false;
|
angle_open = false;
|
||||||
}
|
}
|
||||||
@ -620,14 +657,27 @@ pub fn write_bounds_like_dyn_trait(
|
|||||||
// We assume that the self type is $0 (i.e. the
|
// We assume that the self type is $0 (i.e. the
|
||||||
// existential) here, which is the only thing that's
|
// existential) here, which is the only thing that's
|
||||||
// possible in actual Rust, and hence don't print it
|
// possible in actual Rust, and hence don't print it
|
||||||
write!(f, "{}", f.db.trait_data(trait_ref.trait_).name)?;
|
write!(f, "{}", f.db.trait_data(trait_).name)?;
|
||||||
if trait_ref.substs.len() > 1 {
|
if let [_, params @ ..] = &*trait_ref.substs.0 {
|
||||||
write!(f, "<")?;
|
if is_fn_trait {
|
||||||
f.write_joined(&trait_ref.substs[1..], ", ")?;
|
if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
|
||||||
// there might be assoc type bindings, so we leave the angle brackets open
|
write!(f, "(")?;
|
||||||
angle_open = true;
|
f.write_joined(&*args.0, ", ")?;
|
||||||
|
write!(f, ")")?;
|
||||||
|
}
|
||||||
|
} else if !params.is_empty() {
|
||||||
|
write!(f, "<")?;
|
||||||
|
f.write_joined(params, ", ")?;
|
||||||
|
// there might be assoc type bindings, so we leave the angle brackets open
|
||||||
|
angle_open = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GenericPredicate::Projection(projection_pred) if is_fn_trait => {
|
||||||
|
is_fn_trait = false;
|
||||||
|
write!(f, " -> ")?;
|
||||||
|
projection_pred.ty.hir_fmt(f)?;
|
||||||
|
}
|
||||||
GenericPredicate::Projection(projection_pred) => {
|
GenericPredicate::Projection(projection_pred) => {
|
||||||
// in types in actual Rust, these will always come
|
// in types in actual Rust, these will always come
|
||||||
// after the corresponding Implemented predicate
|
// after the corresponding Implemented predicate
|
||||||
|
@ -39,3 +39,18 @@ fn main() {
|
|||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_raw_ptr_impl_ty() {
|
||||||
|
check_types_source_code(
|
||||||
|
r#"
|
||||||
|
trait Sized {}
|
||||||
|
trait Unpin {}
|
||||||
|
fn foo() -> *const (impl Unpin + Sized) { loop {} }
|
||||||
|
fn main() {
|
||||||
|
let foo = foo();
|
||||||
|
foo;
|
||||||
|
} //^ *const (impl Unpin + Sized)
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -3038,16 +3038,16 @@ fn infer_box_fn_arg() {
|
|||||||
406..417 '&self.inner': &*mut T
|
406..417 '&self.inner': &*mut T
|
||||||
407..411 'self': &Box<T>
|
407..411 'self': &Box<T>
|
||||||
407..417 'self.inner': *mut T
|
407..417 'self.inner': *mut T
|
||||||
478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)>
|
478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
|
||||||
488..489 's': Option<i32>
|
488..489 's': Option<i32>
|
||||||
492..504 'Option::None': Option<i32>
|
492..504 'Option::None': Option<i32>
|
||||||
514..515 'f': Box<dyn FnOnce<(&Option<i32>,)>>
|
514..515 'f': Box<dyn FnOnce(&Option<i32>)>
|
||||||
549..562 'box (|ps| {})': Box<|{unknown}| -> ()>
|
549..562 'box (|ps| {})': Box<|{unknown}| -> ()>
|
||||||
554..561 '|ps| {}': |{unknown}| -> ()
|
554..561 '|ps| {}': |{unknown}| -> ()
|
||||||
555..557 'ps': {unknown}
|
555..557 'ps': {unknown}
|
||||||
559..561 '{}': ()
|
559..561 '{}': ()
|
||||||
568..569 'f': Box<dyn FnOnce<(&Option<i32>,)>>
|
568..569 'f': Box<dyn FnOnce(&Option<i32>)>
|
||||||
568..573 'f(&s)': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)>
|
568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
|
||||||
570..572 '&s': &Option<i32>
|
570..572 '&s': &Option<i32>
|
||||||
571..572 's': Option<i32>
|
571..572 's': Option<i32>
|
||||||
"#]],
|
"#]],
|
||||||
|
@ -1398,6 +1398,43 @@ fn main() {
|
|||||||
Foo::bar(&Foo);
|
Foo::bar(&Foo);
|
||||||
//^^^^ self
|
//^^^^ self
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fn_hints() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
trait Sized {}
|
||||||
|
|
||||||
|
fn foo() -> impl Fn() { loop {} }
|
||||||
|
fn foo1() -> impl Fn(f64) { loop {} }
|
||||||
|
fn foo2() -> impl Fn(f64, f64) { loop {} }
|
||||||
|
fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
|
||||||
|
fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
|
||||||
|
fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
|
||||||
|
fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
|
||||||
|
fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let foo = foo();
|
||||||
|
// ^^^ impl Fn()
|
||||||
|
let foo = foo1();
|
||||||
|
// ^^^ impl Fn(f64)
|
||||||
|
let foo = foo2();
|
||||||
|
// ^^^ impl Fn(f64, f64)
|
||||||
|
let foo = foo3();
|
||||||
|
// ^^^ impl Fn(f64, f64) -> u32
|
||||||
|
let foo = foo4();
|
||||||
|
// ^^^ &dyn Fn(f64, f64) -> u32
|
||||||
|
let foo = foo5();
|
||||||
|
// ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
|
||||||
|
let foo = foo6();
|
||||||
|
// ^^^ impl Fn(f64, f64) -> u32 + Sized
|
||||||
|
let foo = foo7();
|
||||||
|
// ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -38,94 +38,7 @@ pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Cr
|
|||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl FamousDefs<'_, '_> {
|
impl FamousDefs<'_, '_> {
|
||||||
pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core
|
pub const FIXTURE: &'static str = include_str!("helpers/famous_defs_fixture.rs");
|
||||||
pub mod convert {
|
|
||||||
pub trait From<T> {
|
|
||||||
fn from(t: T) -> Self;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod default {
|
|
||||||
pub trait Default {
|
|
||||||
fn default() -> Self;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod iter {
|
|
||||||
pub use self::traits::{collect::IntoIterator, iterator::Iterator};
|
|
||||||
mod traits {
|
|
||||||
pub(crate) mod iterator {
|
|
||||||
use crate::option::Option;
|
|
||||||
pub trait Iterator {
|
|
||||||
type Item;
|
|
||||||
fn next(&mut self) -> Option<Self::Item>;
|
|
||||||
fn by_ref(&mut self) -> &mut Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
fn take(self, n: usize) -> crate::iter::Take<Self> {
|
|
||||||
crate::iter::Take { inner: self }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<I: Iterator> Iterator for &mut I {
|
|
||||||
type Item = I::Item;
|
|
||||||
fn next(&mut self) -> Option<I::Item> {
|
|
||||||
(**self).next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub(crate) mod collect {
|
|
||||||
pub trait IntoIterator {
|
|
||||||
type Item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::sources::*;
|
|
||||||
pub(crate) mod sources {
|
|
||||||
use super::Iterator;
|
|
||||||
use crate::option::Option::{self, *};
|
|
||||||
pub struct Repeat<A> {
|
|
||||||
element: A,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn repeat<T>(elt: T) -> Repeat<T> {
|
|
||||||
Repeat { element: elt }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A> Iterator for Repeat<A> {
|
|
||||||
type Item = A;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<A> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub use self::adapters::*;
|
|
||||||
pub(crate) mod adapters {
|
|
||||||
use super::Iterator;
|
|
||||||
use crate::option::Option::{self, *};
|
|
||||||
pub struct Take<I> { pub(crate) inner: I }
|
|
||||||
impl<I> Iterator for Take<I> where I: Iterator {
|
|
||||||
type Item = <I as Iterator>::Item;
|
|
||||||
fn next(&mut self) -> Option<<I as Iterator>::Item> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod option {
|
|
||||||
pub enum Option<T> { None, Some(T)}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod prelude {
|
|
||||||
pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default};
|
|
||||||
}
|
|
||||||
#[prelude_import]
|
|
||||||
pub use prelude::*;
|
|
||||||
"#;
|
|
||||||
|
|
||||||
pub fn core(&self) -> Option<Crate> {
|
pub fn core(&self) -> Option<Crate> {
|
||||||
self.find_crate("core")
|
self.find_crate("core")
|
||||||
|
120
crates/ide_db/src/helpers/famous_defs_fixture.rs
Normal file
120
crates/ide_db/src/helpers/famous_defs_fixture.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
//- /libcore.rs crate:core
|
||||||
|
//! Signatures of traits, types and functions from the core lib for use in tests.
|
||||||
|
pub mod convert {
|
||||||
|
pub trait From<T> {
|
||||||
|
fn from(t: T) -> Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod default {
|
||||||
|
pub trait Default {
|
||||||
|
fn default() -> Self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod iter {
|
||||||
|
pub use self::traits::{collect::IntoIterator, iterator::Iterator};
|
||||||
|
mod traits {
|
||||||
|
pub(crate) mod iterator {
|
||||||
|
use crate::option::Option;
|
||||||
|
pub trait Iterator {
|
||||||
|
type Item;
|
||||||
|
fn next(&mut self) -> Option<Self::Item>;
|
||||||
|
fn by_ref(&mut self) -> &mut Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn take(self, n: usize) -> crate::iter::Take<Self> {
|
||||||
|
crate::iter::Take { inner: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator> Iterator for &mut I {
|
||||||
|
type Item = I::Item;
|
||||||
|
fn next(&mut self) -> Option<I::Item> {
|
||||||
|
(**self).next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) mod collect {
|
||||||
|
pub trait IntoIterator {
|
||||||
|
type Item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::sources::*;
|
||||||
|
pub(crate) mod sources {
|
||||||
|
use super::Iterator;
|
||||||
|
use crate::option::Option::{self, *};
|
||||||
|
pub struct Repeat<A> {
|
||||||
|
element: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn repeat<T>(elt: T) -> Repeat<T> {
|
||||||
|
Repeat { element: elt }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> Iterator for Repeat<A> {
|
||||||
|
type Item = A;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<A> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::adapters::*;
|
||||||
|
pub(crate) mod adapters {
|
||||||
|
use super::Iterator;
|
||||||
|
use crate::option::Option::{self, *};
|
||||||
|
pub struct Take<I> {
|
||||||
|
pub(crate) inner: I,
|
||||||
|
}
|
||||||
|
impl<I> Iterator for Take<I>
|
||||||
|
where
|
||||||
|
I: Iterator,
|
||||||
|
{
|
||||||
|
type Item = <I as Iterator>::Item;
|
||||||
|
fn next(&mut self) -> Option<<I as Iterator>::Item> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod ops {
|
||||||
|
#[lang = "fn"]
|
||||||
|
pub trait Fn<Args>: FnMut<Args> {
|
||||||
|
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "fn_mut"]
|
||||||
|
pub trait FnMut<Args>: FnOnce<Args> {
|
||||||
|
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
||||||
|
}
|
||||||
|
#[lang = "fn_once"]
|
||||||
|
pub trait FnOnce<Args> {
|
||||||
|
#[lang = "fn_once_output"]
|
||||||
|
type Output;
|
||||||
|
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod option {
|
||||||
|
pub enum Option<T> {
|
||||||
|
None,
|
||||||
|
Some(T),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use crate::{
|
||||||
|
convert::From,
|
||||||
|
default::Default,
|
||||||
|
iter::{IntoIterator, Iterator},
|
||||||
|
ops::{Fn, FnMut, FnOnce},
|
||||||
|
option::Option::{self, *},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#[prelude_import]
|
||||||
|
pub use prelude::*;
|
@ -324,7 +324,7 @@ impl TidyDocs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_exclude_file(d: &Path) -> bool {
|
fn is_exclude_file(d: &Path) -> bool {
|
||||||
let file_names = ["tests.rs"];
|
let file_names = ["tests.rs", "famous_defs_fixture.rs"];
|
||||||
|
|
||||||
d.file_name()
|
d.file_name()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user