|
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