]> git.lizzy.rs Git - rust.git/commitdiff
Implement internal lints
authorflip1995 <hello@philkrones.com>
Wed, 24 Apr 2019 21:22:54 +0000 (23:22 +0200)
committerflip1995 <hello@philkrones.com>
Sun, 28 Apr 2019 19:19:25 +0000 (21:19 +0200)
- USAGE_OF_QUALIFIED_TY

- TY_PASS_BY_REFERENCE

src/librustc/lint/internal.rs
src/librustc_lint/lib.rs
src/librustc_mir/borrow_check/borrow_set.rs

index 91f1bee26de3275a62c22c6bb0782f55f385d736..126a7cd3349153db422e7449df28c464b6f28c9b 100644 (file)
@@ -1,7 +1,7 @@
 //! Some lints that are only useful in the compiler or crates that use compiler internals, such as
 //! Clippy.
 
-use crate::hir::{HirId, Path, PathSegment, QPath, Ty, TyKind};
+use crate::hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind};
 use crate::lint::{
     EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass,
 };
@@ -57,12 +57,28 @@ fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
 declare_lint! {
     pub USAGE_OF_TY_TYKIND,
     Allow,
-    "Usage of `ty::TyKind` outside of the `ty::sty` module"
+    "usage of `ty::TyKind` outside of the `ty::sty` module"
 }
 
-declare_lint_pass!(TyKindUsage => [USAGE_OF_TY_TYKIND]);
+declare_lint! {
+    pub TY_PASS_BY_REFERENCE,
+    Allow,
+    "passing `Ty` or `TyCtxt` by reference"
+}
+
+declare_lint! {
+    pub USAGE_OF_QUALIFIED_TY,
+    Allow,
+    "using `ty::{Ty,TyCtxt}` instead of importing it"
+}
+
+declare_lint_pass!(TyTyKind => [
+    USAGE_OF_TY_TYKIND,
+    TY_PASS_BY_REFERENCE,
+    USAGE_OF_QUALIFIED_TY,
+]);
 
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyKindUsage {
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyTyKind {
     fn check_path(&mut self, cx: &LateContext<'_, '_>, path: &'tcx Path, _: HirId) {
         let segments = path.segments.iter().rev().skip(1).rev();
 
@@ -82,16 +98,72 @@ fn check_path(&mut self, cx: &LateContext<'_, '_>, path: &'tcx Path, _: HirId) {
     }
 
     fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &'tcx Ty) {
-        if let TyKind::Path(qpath) = &ty.node {
-            if let QPath::Resolved(_, path) = qpath {
-                if let Some(last) = path.segments.iter().last() {
-                    if lint_ty_kind_usage(cx, last) {
-                        cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, "usage of `ty::TyKind`")
-                            .help("try using `ty::Ty` instead")
+        match &ty.node {
+            TyKind::Path(qpath) => {
+                if let QPath::Resolved(_, path) = qpath {
+                    if let Some(last) = path.segments.iter().last() {
+                        if lint_ty_kind_usage(cx, last) {
+                            cx.struct_span_lint(
+                                USAGE_OF_TY_TYKIND,
+                                path.span,
+                                "usage of `ty::TyKind`",
+                            )
+                            .help("try using `Ty` instead")
                             .emit();
+                        } else {
+                            if ty.span.ctxt().outer().expn_info().is_some() {
+                                return;
+                            }
+                            if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
+                                if path.segments.len() > 1 {
+                                    cx.struct_span_lint(
+                                        USAGE_OF_QUALIFIED_TY,
+                                        path.span,
+                                        &format!("usage of qualified `ty::{}`", t),
+                                    )
+                                    .span_suggestion(
+                                        path.span,
+                                        "try using it unqualified",
+                                        t,
+                                        // The import probably needs to be changed
+                                        Applicability::MaybeIncorrect,
+                                    )
+                                    .emit();
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            TyKind::Rptr(
+                _,
+                MutTy {
+                    ty: inner_ty,
+                    mutbl: Mutability::MutImmutable,
+                },
+            ) => {
+                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner_def_id()) {
+                    if cx.tcx.impl_trait_ref(impl_did).is_some() {
+                        return;
                     }
                 }
+                if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) {
+                    cx.struct_span_lint(
+                        TY_PASS_BY_REFERENCE,
+                        ty.span,
+                        &format!("passing `{}` by reference", t),
+                    )
+                    .span_suggestion(
+                        ty.span,
+                        "try passing by value",
+                        t,
+                        // Changing type of function argument
+                        Applicability::MaybeIncorrect,
+                    )
+                    .emit();
+                }
             }
+            _ => {}
         }
     }
 }
@@ -107,3 +179,43 @@ fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment) -> bool {
 
     false
 }
+
+fn is_ty_or_ty_ctxt(cx: &LateContext<'_, '_>, ty: &Ty) -> Option<String> {
+    match &ty.node {
+        TyKind::Path(qpath) => {
+            if let QPath::Resolved(_, path) = qpath {
+                let did = path.def.opt_def_id()?;
+                if cx.match_def_path(did, &["rustc", "ty", "Ty"]) {
+                    return Some(format!("Ty{}", gen_args(path.segments.last().unwrap())));
+                } else if cx.match_def_path(did, &["rustc", "ty", "context", "TyCtxt"]) {
+                    return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap())));
+                }
+            }
+        }
+        _ => {}
+    }
+
+    None
+}
+
+fn gen_args(segment: &PathSegment) -> String {
+    if let Some(args) = &segment.args {
+        let lifetimes = args
+            .args
+            .iter()
+            .filter_map(|arg| {
+                if let GenericArg::Lifetime(lt) = arg {
+                    Some(lt.name.ident().to_string())
+                } else {
+                    None
+                }
+            })
+            .collect::<Vec<_>>();
+
+        if !lifetimes.is_empty() {
+            return format!("<{}>", lifetimes.join(", "));
+        }
+    }
+
+    String::new()
+}
index 7d23da857bbbb35d26f4a4bf3f6860aef0d44c40..0bb9d4389dd0b7eb0e773f1a34077b5ca590b2ab 100644 (file)
@@ -495,7 +495,7 @@ macro_rules! register_passes {
 
 pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) {
     store.register_early_pass(sess, false, false, box DefaultHashTypes::new());
-    store.register_late_pass(sess, false, false, false, box TyKindUsage);
+    store.register_late_pass(sess, false, false, false, box TyTyKind);
     store.register_group(
         sess,
         false,
@@ -504,6 +504,8 @@ pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) {
         vec![
             LintId::of(DEFAULT_HASH_TYPES),
             LintId::of(USAGE_OF_TY_TYKIND),
+            LintId::of(TY_PASS_BY_REFERENCE),
+            LintId::of(USAGE_OF_QUALIFIED_TY),
         ],
     );
 }
index c8d6ee9db6f9e73370c0515bfde18fa04d7312f3..9581b6b52f7ab2fa4b06846c8ddb4ea43d933cdf 100644 (file)
@@ -315,7 +315,7 @@ fn insert_as_pending_if_two_phase(
             start_location, assigned_place, borrow_index,
         );
 
-        if !allow_two_phase_borrow(&self.tcx, kind) {
+        if !allow_two_phase_borrow(self.tcx, kind) {
             debug!("  -> {:?}", start_location);
             return;
         }