Auto merge of #10813 - y21:issue10755, r=xFrednet
[`default_constructed_unit_structs`]: do not lint on type alias paths
Fixes #10755.
Type aliases cannot be used as a constructor, so this lint should not trigger in those cases.
I also changed `clippy_utils::is_ty_alias` to also consider associated types since [they kinda are type aliases too](48ec50ae39/compiler/rustc_resolve/src/late/diagnostics.rs (L1520)
).
changelog: [`default_constructed_unit_structs`]: do not lint on type alias paths
This commit is contained in:
commit
f1fd4673bc
5 changed files with 62 additions and 7 deletions
|
@ -1,4 +1,4 @@
|
||||||
use clippy_utils::{diagnostics::span_lint_and_sugg, match_def_path, paths};
|
use clippy_utils::{diagnostics::span_lint_and_sugg, is_ty_alias, match_def_path, paths};
|
||||||
use hir::{def::Res, ExprKind};
|
use hir::{def::Res, ExprKind};
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -43,12 +43,23 @@ declare_clippy_lint! {
|
||||||
}
|
}
|
||||||
declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
|
declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]);
|
||||||
|
|
||||||
|
fn is_alias(ty: hir::Ty<'_>) -> bool {
|
||||||
|
if let hir::TyKind::Path(ref qpath) = ty.kind {
|
||||||
|
is_ty_alias(qpath)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl LateLintPass<'_> for DefaultConstructedUnitStructs {
|
impl LateLintPass<'_> for DefaultConstructedUnitStructs {
|
||||||
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
|
||||||
if_chain!(
|
if_chain!(
|
||||||
// make sure we have a call to `Default::default`
|
// make sure we have a call to `Default::default`
|
||||||
if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
|
if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind;
|
||||||
if let ExprKind::Path(ref qpath@ hir::QPath::TypeRelative(_,_)) = fn_expr.kind;
|
if let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind;
|
||||||
|
// make sure this isn't a type alias:
|
||||||
|
// `<Foo as Bar>::Assoc` cannot be used as a constructor
|
||||||
|
if !is_alias(*base);
|
||||||
if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
|
if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
|
||||||
if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
|
if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
|
||||||
// make sure we have a struct with no fields (unit struct)
|
// make sure we have a struct with no fields (unit struct)
|
||||||
|
|
|
@ -287,7 +287,7 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
|
||||||
/// Checks if the given `QPath` belongs to a type alias.
|
/// Checks if the given `QPath` belongs to a type alias.
|
||||||
pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
|
pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
|
||||||
match *qpath {
|
match *qpath {
|
||||||
QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias, ..)),
|
QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)),
|
||||||
QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) },
|
QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) },
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,28 @@ struct EmptyStruct {}
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
struct NonExhaustiveStruct;
|
struct NonExhaustiveStruct;
|
||||||
|
|
||||||
|
mod issue_10755 {
|
||||||
|
struct Sqlite {}
|
||||||
|
|
||||||
|
trait HasArguments<'q> {
|
||||||
|
type Arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'q> HasArguments<'q> for Sqlite {
|
||||||
|
type Arguments = std::marker::PhantomData<&'q ()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type SqliteArguments<'q> = <Sqlite as HasArguments<'q>>::Arguments;
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
// should not lint
|
||||||
|
// type alias cannot be used as a constructor
|
||||||
|
let _ = <Sqlite as HasArguments>::Arguments::default();
|
||||||
|
|
||||||
|
let _ = SqliteArguments::default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// should lint
|
// should lint
|
||||||
let _ = PhantomData::<usize>;
|
let _ = PhantomData::<usize>;
|
||||||
|
|
|
@ -101,6 +101,28 @@ struct EmptyStruct {}
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
struct NonExhaustiveStruct;
|
struct NonExhaustiveStruct;
|
||||||
|
|
||||||
|
mod issue_10755 {
|
||||||
|
struct Sqlite {}
|
||||||
|
|
||||||
|
trait HasArguments<'q> {
|
||||||
|
type Arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'q> HasArguments<'q> for Sqlite {
|
||||||
|
type Arguments = std::marker::PhantomData<&'q ()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type SqliteArguments<'q> = <Sqlite as HasArguments<'q>>::Arguments;
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
// should not lint
|
||||||
|
// type alias cannot be used as a constructor
|
||||||
|
let _ = <Sqlite as HasArguments>::Arguments::default();
|
||||||
|
|
||||||
|
let _ = SqliteArguments::default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// should lint
|
// should lint
|
||||||
let _ = PhantomData::<usize>::default();
|
let _ = PhantomData::<usize>::default();
|
||||||
|
|
|
@ -13,25 +13,25 @@ LL | inner: PhantomData::default(),
|
||||||
| ^^^^^^^^^^^ help: remove this call to `default`
|
| ^^^^^^^^^^^ help: remove this call to `default`
|
||||||
|
|
||||||
error: use of `default` to create a unit struct
|
error: use of `default` to create a unit struct
|
||||||
--> $DIR/default_constructed_unit_structs.rs:106:33
|
--> $DIR/default_constructed_unit_structs.rs:128:33
|
||||||
|
|
|
|
||||||
LL | let _ = PhantomData::<usize>::default();
|
LL | let _ = PhantomData::<usize>::default();
|
||||||
| ^^^^^^^^^^^ help: remove this call to `default`
|
| ^^^^^^^^^^^ help: remove this call to `default`
|
||||||
|
|
||||||
error: use of `default` to create a unit struct
|
error: use of `default` to create a unit struct
|
||||||
--> $DIR/default_constructed_unit_structs.rs:107:42
|
--> $DIR/default_constructed_unit_structs.rs:129:42
|
||||||
|
|
|
|
||||||
LL | let _: PhantomData<i32> = PhantomData::default();
|
LL | let _: PhantomData<i32> = PhantomData::default();
|
||||||
| ^^^^^^^^^^^ help: remove this call to `default`
|
| ^^^^^^^^^^^ help: remove this call to `default`
|
||||||
|
|
||||||
error: use of `default` to create a unit struct
|
error: use of `default` to create a unit struct
|
||||||
--> $DIR/default_constructed_unit_structs.rs:108:55
|
--> $DIR/default_constructed_unit_structs.rs:130:55
|
||||||
|
|
|
|
||||||
LL | let _: PhantomData<i32> = std::marker::PhantomData::default();
|
LL | let _: PhantomData<i32> = std::marker::PhantomData::default();
|
||||||
| ^^^^^^^^^^^ help: remove this call to `default`
|
| ^^^^^^^^^^^ help: remove this call to `default`
|
||||||
|
|
||||||
error: use of `default` to create a unit struct
|
error: use of `default` to create a unit struct
|
||||||
--> $DIR/default_constructed_unit_structs.rs:109:23
|
--> $DIR/default_constructed_unit_structs.rs:131:23
|
||||||
|
|
|
|
||||||
LL | let _ = UnitStruct::default();
|
LL | let _ = UnitStruct::default();
|
||||||
| ^^^^^^^^^^^ help: remove this call to `default`
|
| ^^^^^^^^^^^ help: remove this call to `default`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue