|
11 | 11 | use crate::rustc::hir::def_id::DefId;
|
12 | 12 | use crate::rustc::hir;
|
13 | 13 | use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass, in_external_macro, LintContext};
|
| 14 | +use crate::rustc::util::nodemap::NodeSet; |
14 | 15 | use crate::rustc::{declare_tool_lint, lint_array};
|
15 | 16 | use if_chain::if_chain;
|
16 | 17 | use crate::rustc::ty::{self, Ty};
|
@@ -91,8 +92,10 @@ declare_clippy_lint! {
|
91 | 92 | "`fn new() -> Self` without `#[derive]`able `Default` implementation"
|
92 | 93 | }
|
93 | 94 |
|
94 |
| -#[derive(Copy, Clone)] |
95 |
| -pub struct NewWithoutDefault; |
| 95 | +#[derive(Clone, Default)] |
| 96 | +pub struct NewWithoutDefault { |
| 97 | + impling_types: Option<NodeSet>, |
| 98 | +} |
96 | 99 |
|
97 | 100 | impl LintPass for NewWithoutDefault {
|
98 | 101 | fn get_lints(&self) -> LintArray {
|
@@ -130,13 +133,39 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
|
130 | 133 | return;
|
131 | 134 | }
|
132 | 135 | if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
|
| 136 | + let self_did = cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id)); |
133 | 137 | let self_ty = cx.tcx
|
134 |
| - .type_of(cx.tcx.hir.local_def_id(cx.tcx.hir.get_parent(id))); |
| 138 | + .type_of(self_did); |
135 | 139 | if_chain! {
|
136 | 140 | if same_tys(cx, self_ty, return_ty(cx, id));
|
137 | 141 | if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
|
138 |
| - if !implements_trait(cx, self_ty, default_trait_id, &[]); |
139 | 142 | then {
|
| 143 | + if self.impling_types.is_none() { |
| 144 | + let mut impls = NodeSet(); |
| 145 | + cx.tcx.for_each_impl(default_trait_id, |d| { |
| 146 | + if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() { |
| 147 | + if let Some(node_id) = cx.tcx.hir.as_local_node_id(ty_def.did) { |
| 148 | + impls.insert(node_id); |
| 149 | + } |
| 150 | + } |
| 151 | + }); |
| 152 | + self.impling_types = Some(impls); |
| 153 | + } |
| 154 | + |
| 155 | + // Check if a Default implementation exists for the Self type, regardless of |
| 156 | + // generics |
| 157 | + if_chain! { |
| 158 | + if let Some(ref impling_types) = self.impling_types; |
| 159 | + if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def(); |
| 160 | + if self_def.did.is_local(); |
| 161 | + then { |
| 162 | + let self_id = cx.tcx.hir.local_def_id_to_node_id(self_def.did.to_local()); |
| 163 | + if impling_types.contains(&self_id) { |
| 164 | + return; |
| 165 | + } |
| 166 | + } |
| 167 | + } |
| 168 | + |
140 | 169 | if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
|
141 | 170 | span_lint_and_then(
|
142 | 171 | cx,
|
|
0 commit comments