Move "types to lint" to the item stack

This commit is contained in:
Cameron Steffen 2021-02-09 19:39:38 -06:00 committed by flip1995
parent 7e1c1c1541
commit 7f61ddd5b8
No known key found for this signature in database
GPG key ID: 1CA0DF2AF59D68A5

View file

@ -59,8 +59,6 @@ declare_clippy_lint! {
pub struct UseSelf { pub struct UseSelf {
msrv: Option<RustcVersion>, msrv: Option<RustcVersion>,
stack: Vec<StackItem>, stack: Vec<StackItem>,
types_to_skip: Vec<HirId>,
types_to_lint: Vec<HirId>,
} }
const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0); const USE_SELF_MSRV: RustcVersion = RustcVersion::new(1, 37, 0);
@ -75,11 +73,13 @@ impl UseSelf {
} }
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[derive(Debug)]
enum StackItem { enum StackItem {
Check { Check {
hir_id: HirId, hir_id: HirId,
impl_trait_ref_def_id: Option<LocalDefId>, impl_trait_ref_def_id: Option<LocalDefId>,
types_to_skip: Vec<HirId>,
types_to_lint: Vec<HirId>,
}, },
NoCheck, NoCheck,
} }
@ -116,6 +116,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
self.stack.push(StackItem::Check { self.stack.push(StackItem::Check {
hir_id: hir_self_ty.hir_id, hir_id: hir_self_ty.hir_id,
impl_trait_ref_def_id, impl_trait_ref_def_id,
types_to_lint: Vec::new(),
types_to_skip: Vec::new(),
}); });
} else { } else {
self.stack.push(StackItem::NoCheck); self.stack.push(StackItem::NoCheck);
@ -149,7 +151,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
// declaration. The collection of those types is all this method implementation does. // declaration. The collection of those types is all this method implementation does.
if_chain! { if_chain! {
if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind; if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind;
if let Some(StackItem::Check { impl_trait_ref_def_id: Some(def_id), .. }) = self.stack.last().copied(); if let Some(&mut StackItem::Check {
impl_trait_ref_def_id: Some(def_id),
ref mut types_to_skip,
..
}) = self.stack.last_mut();
if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(def_id); if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(def_id);
then { then {
// `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be // `self_ty` is the semantic self type of `impl <trait> for <type>`. This cannot be
@ -191,17 +197,13 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) { if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
let mut visitor = SkipTyCollector::default(); let mut visitor = SkipTyCollector::default();
visitor.visit_ty(&impl_hir_ty); visitor.visit_ty(&impl_hir_ty);
self.types_to_skip.extend(visitor.types_to_skip); types_to_skip.extend(visitor.types_to_skip);
} }
} }
} }
} }
} }
fn check_impl_item_post(&mut self, _: &LateContext<'_>, _: &hir::ImplItem<'_>) {
self.types_to_skip.clear();
}
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) { fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx hir::Body<'_>) {
// `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies // `hir_ty_to_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies
// we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`. // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`.
@ -211,7 +213,13 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
// which shouldn't, with a visitor. We could directly lint in the visitor, but then we // which shouldn't, with a visitor. We could directly lint in the visitor, but then we
// could only allow this lint on item scope. And we would have to check if those types are // could only allow this lint on item scope. And we would have to check if those types are
// already dealt with in `check_ty` anyway. // already dealt with in `check_ty` anyway.
if let Some(StackItem::Check { hir_id, .. }) = self.stack.last() { if let Some(StackItem::Check {
hir_id,
types_to_lint,
types_to_skip,
..
}) = self.stack.last_mut()
{
let self_ty = ty_from_hir_id(cx, *hir_id); let self_ty = ty_from_hir_id(cx, *hir_id);
let mut visitor = LintTyCollector { let mut visitor = LintTyCollector {
@ -221,25 +229,36 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
types_to_skip: vec![], types_to_skip: vec![],
}; };
visitor.visit_expr(&body.value); visitor.visit_expr(&body.value);
self.types_to_lint.extend(visitor.types_to_lint); types_to_lint.extend(visitor.types_to_lint);
self.types_to_skip.extend(visitor.types_to_skip); types_to_skip.extend(visitor.types_to_skip);
} }
} }
fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) {
self.types_to_lint.clear();
}
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
if in_macro(hir_ty.span) if in_macro(hir_ty.span) | in_impl(cx, hir_ty) | !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV) {
| in_impl(cx, hir_ty)
| self.types_to_skip.contains(&hir_ty.hir_id)
| !meets_msrv(self.msrv.as_ref(), &USE_SELF_MSRV)
{
return; return;
} }
let lint_dependend_on_expr_kind = || { let lint_dependend_on_expr_kind = if let Some(StackItem::Check {
hir_id,
types_to_lint,
types_to_skip,
..
}) = self.stack.last()
{
if types_to_skip.contains(&hir_ty.hir_id) {
false
} else if types_to_lint.contains(&hir_ty.hir_id) {
true
} else {
let self_ty = ty_from_hir_id(cx, *hir_id);
should_lint_ty(hir_ty, hir_ty_to_ty(cx.tcx, hir_ty), self_ty)
}
} else {
false
};
if lint_dependend_on_expr_kind {
// FIXME: this span manipulation should not be necessary // FIXME: this span manipulation should not be necessary
// @flip1995 found an ast lowering issue in // @flip1995 found an ast lowering issue in
// https://github.com/rust-lang/rust/blob/master/src/librustc_ast_lowering/path.rs#l142-l162 // https://github.com/rust-lang/rust/blob/master/src/librustc_ast_lowering/path.rs#l142-l162
@ -250,16 +269,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
})) => span_lint_until_last_segment(cx, hir_ty.span, segment), })) => span_lint_until_last_segment(cx, hir_ty.span, segment),
_ => span_lint(cx, hir_ty.span), _ => span_lint(cx, hir_ty.span),
} }
};
if self.types_to_lint.contains(&hir_ty.hir_id) {
lint_dependend_on_expr_kind();
} else if let Some(StackItem::Check { hir_id, .. }) = self.stack.last() {
let self_ty = ty_from_hir_id(cx, *hir_id);
if should_lint_ty(hir_ty, hir_ty_to_ty(cx.tcx, hir_ty), self_ty) {
lint_dependend_on_expr_kind();
}
} }
} }