]> git.proxmox.com Git - rustc.git/blobdiff - src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
New upstream version 1.52.1+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / methods / wrong_self_convention.rs
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
new file mode 100644 (file)
index 0000000..90fab57
--- /dev/null
@@ -0,0 +1,76 @@
+use crate::methods::SelfKind;
+use crate::utils::span_lint;
+use rustc_lint::LateContext;
+use rustc_middle::ty::TyS;
+use rustc_span::source_map::Span;
+use std::fmt;
+
+use super::WRONG_PUB_SELF_CONVENTION;
+use super::WRONG_SELF_CONVENTION;
+
+#[rustfmt::skip]
+const CONVENTIONS: [(Convention, &[SelfKind]); 7] = [
+    (Convention::Eq("new"), &[SelfKind::No]),
+    (Convention::StartsWith("as_"), &[SelfKind::Ref, SelfKind::RefMut]),
+    (Convention::StartsWith("from_"), &[SelfKind::No]),
+    (Convention::StartsWith("into_"), &[SelfKind::Value]),
+    (Convention::StartsWith("is_"), &[SelfKind::Ref, SelfKind::No]),
+    (Convention::Eq("to_mut"), &[SelfKind::RefMut]),
+    (Convention::StartsWith("to_"), &[SelfKind::Ref]),
+];
+enum Convention {
+    Eq(&'static str),
+    StartsWith(&'static str),
+}
+
+impl Convention {
+    #[must_use]
+    fn check(&self, other: &str) -> bool {
+        match *self {
+            Self::Eq(this) => this == other,
+            Self::StartsWith(this) => other.starts_with(this) && this != other,
+        }
+    }
+}
+
+impl fmt::Display for Convention {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+        match *self {
+            Self::Eq(this) => this.fmt(f),
+            Self::StartsWith(this) => this.fmt(f).and_then(|_| '*'.fmt(f)),
+        }
+    }
+}
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    item_name: &str,
+    is_pub: bool,
+    self_ty: &'tcx TyS<'tcx>,
+    first_arg_ty: &'tcx TyS<'tcx>,
+    first_arg_span: Span,
+) {
+    let lint = if is_pub {
+        WRONG_PUB_SELF_CONVENTION
+    } else {
+        WRONG_SELF_CONVENTION
+    };
+    if let Some((ref conv, self_kinds)) = &CONVENTIONS.iter().find(|(ref conv, _)| conv.check(item_name)) {
+        if !self_kinds.iter().any(|k| k.matches(cx, self_ty, first_arg_ty)) {
+            span_lint(
+                cx,
+                lint,
+                first_arg_span,
+                &format!(
+                    "methods called `{}` usually take {}; consider choosing a less ambiguous name",
+                    conv,
+                    &self_kinds
+                        .iter()
+                        .map(|k| k.description())
+                        .collect::<Vec<_>>()
+                        .join(" or ")
+                ),
+            );
+        }
+    }
+}