2019-05-14 10:06:21 +02:00
|
|
|
use crate::utils::{match_def_path, paths, span_lint};
|
2019-02-16 21:28:16 -07:00
|
|
|
use if_chain::if_chain;
|
2020-02-21 09:39:38 +01:00
|
|
|
use rustc_hir::{GenericBound, GenericParam, WhereBoundPredicate, WherePredicate};
|
2020-06-25 23:41:36 +03:00
|
|
|
use rustc_lint::{LateContext, LateLintPass};
|
2020-01-11 20:37:08 +09:00
|
|
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
2019-02-16 21:28:16 -07:00
|
|
|
|
|
|
|
declare_clippy_lint! {
|
2019-03-05 11:50:33 -05:00
|
|
|
/// **What it does:** Checks for generics with `std::ops::Drop` as bounds.
|
|
|
|
///
|
|
|
|
/// **Why is this bad?** `Drop` bounds do not really accomplish anything.
|
|
|
|
/// A type may have compiler-generated drop glue without implementing the
|
|
|
|
/// `Drop` trait itself. The `Drop` trait also only has one method,
|
|
|
|
/// `Drop::drop`, and that function is by fiat not callable in user code.
|
|
|
|
/// So there is really no use case for using `Drop` in trait bounds.
|
|
|
|
///
|
|
|
|
/// The most likely use case of a drop bound is to distinguish between types
|
|
|
|
/// that have destructors and types that don't. Combined with specialization,
|
|
|
|
/// a naive coder would write an implementation that assumed a type could be
|
|
|
|
/// trivially dropped, then write a specialization for `T: Drop` that actually
|
|
|
|
/// calls the destructor. Except that doing so is not correct; String, for
|
|
|
|
/// example, doesn't actually implement Drop, but because String contains a
|
|
|
|
/// Vec, assuming it can be trivially dropped will leak memory.
|
|
|
|
///
|
|
|
|
/// **Known problems:** None.
|
|
|
|
///
|
|
|
|
/// **Example:**
|
|
|
|
/// ```rust
|
|
|
|
/// fn foo<T: Drop>() {}
|
|
|
|
/// ```
|
2020-06-09 14:36:01 +00:00
|
|
|
/// Could be written as:
|
|
|
|
/// ```rust
|
|
|
|
/// fn foo<T>() {}
|
|
|
|
/// ```
|
2019-02-16 21:28:16 -07:00
|
|
|
pub DROP_BOUNDS,
|
|
|
|
correctness,
|
2020-07-23 20:05:42 +02:00
|
|
|
"bounds of the form `T: Drop` are useless"
|
2019-02-16 21:28:16 -07:00
|
|
|
}
|
|
|
|
|
2020-07-23 20:05:42 +02:00
|
|
|
const DROP_BOUNDS_SUMMARY: &str = "bounds of the form `T: Drop` are useless, \
|
|
|
|
use `std::mem::needs_drop` to detect if a type has drop glue";
|
2019-02-16 21:28:16 -07:00
|
|
|
|
2019-04-08 13:43:55 -07:00
|
|
|
declare_lint_pass!(DropBounds => [DROP_BOUNDS]);
|
2019-02-16 21:28:16 -07:00
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
impl<'tcx> LateLintPass<'tcx> for DropBounds {
|
|
|
|
fn check_generic_param(&mut self, cx: &LateContext<'tcx>, p: &'tcx GenericParam<'_>) {
|
2019-12-30 13:02:10 +09:00
|
|
|
for bound in p.bounds.iter() {
|
2019-02-16 21:28:16 -07:00
|
|
|
lint_bound(cx, bound);
|
|
|
|
}
|
|
|
|
}
|
2020-06-25 23:41:36 +03:00
|
|
|
fn check_where_predicate(&mut self, cx: &LateContext<'tcx>, p: &'tcx WherePredicate<'_>) {
|
2019-02-16 21:28:16 -07:00
|
|
|
if let WherePredicate::BoundPredicate(WhereBoundPredicate { bounds, .. }) = p {
|
2019-12-30 13:02:10 +09:00
|
|
|
for bound in *bounds {
|
2019-02-16 21:28:16 -07:00
|
|
|
lint_bound(cx, bound);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 23:41:36 +03:00
|
|
|
fn lint_bound<'tcx>(cx: &LateContext<'tcx>, bound: &'tcx GenericBound<'_>) {
|
2019-02-16 21:28:16 -07:00
|
|
|
if_chain! {
|
|
|
|
if let GenericBound::Trait(t, _) = bound;
|
2019-05-04 02:03:12 +02:00
|
|
|
if let Some(def_id) = t.trait_ref.path.res.opt_def_id();
|
2019-05-17 23:53:54 +02:00
|
|
|
if match_def_path(cx, def_id, &paths::DROP_TRAIT);
|
2019-02-16 21:28:16 -07:00
|
|
|
then {
|
|
|
|
span_lint(
|
|
|
|
cx,
|
|
|
|
DROP_BOUNDS,
|
|
|
|
t.span,
|
|
|
|
DROP_BOUNDS_SUMMARY
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|