about summary refs log tree commit diff
diff options
context:
space:
mode:
authorArthur Lafrance <lafrancearthur@gmail.com>2023-09-25 00:15:00 -0700
committerArthur Lafrance <lafrancearthur@gmail.com>2023-10-16 19:47:33 -0700
commitf77dea89e183b638841d42d4d7bea48058a98e76 (patch)
tree18bc71a5132be3dc008d7b45af46d2664db28dff
parent8769e02d0b17e18e0a52b521a82da4bcae2e6385 (diff)
basic lint v2 implemented
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/internal.rs45
-rw-r--r--compiler/rustc_lint/src/lib.rs4
-rw-r--r--compiler/rustc_lint/src/lints.rs6
-rw-r--r--compiler/rustc_lint/src/span_use_eq_ctxt.rs38
-rw-r--r--compiler/rustc_span/src/span_encoding.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs13
8 files changed, 69 insertions, 43 deletions
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 197fe6552d7..261451e530e 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -494,6 +494,8 @@ lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
 
 lint_requested_level = requested on the command line with `{$level} {$lint_name}`
 
+lint_span_use_eq_ctxt = use `eq_ctxt()` not `ctxt() == ctxt()`
+
 lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
     .label = target type is set here
 
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index fc2d3d0a254..c2aa768e945 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -3,14 +3,14 @@
 
 use crate::lints::{
     BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
-    QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
+    QueryInstability, SpanUseEqCtxtDiag, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
     UntranslatableDiagnosticTrivial,
 };
 use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_ast as ast;
 use rustc_hir::def::Res;
 use rustc_hir::{def_id::DefId, Expr, ExprKind, GenericArg, PatKind, Path, PathSegment, QPath};
-use rustc_hir::{HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
+use rustc_hir::{BinOp, BinOpKind, HirId, Impl, Item, ItemKind, Node, Pat, Ty, TyKind};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -537,3 +537,44 @@ impl LateLintPass<'_> for BadOptAccess {
         }
     }
 }
+
+// some things i'm not sure about:
+//   * is Warn the right level?
+//   * the way i verify that the right method is being called (path + diag item check)
+
+declare_tool_lint! {
+    pub rustc::SPAN_USE_EQ_CTXT,
+    Warn, // is this the right level?
+    "Use of `==` with `Span::ctxt` rather than `Span::eq_ctxt`",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
+
+impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind {
+            if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
+                cx.emit_spanned_lint(
+                    SPAN_USE_EQ_CTXT,
+                    expr.span,
+                    SpanUseEqCtxtDiag { msg: "fail" },
+                );
+            }
+        }
+    }
+}
+
+fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match &expr.kind {
+        ExprKind::MethodCall(path, receiver, _, _) => {
+            path.ident.name.as_str() == "ctxt"
+                && cx
+                    .typeck_results()
+                    .type_dependent_def_id(receiver.hir_id)
+                    .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::Span, did))
+        }
+
+        _ => false,
+    }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index ca1f620b7c7..d61c59af1e0 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -83,7 +83,6 @@ mod passes;
 mod ptr_nulls;
 mod redundant_semicolon;
 mod reference_casting;
-mod span_use_eq_ctxt;
 mod traits;
 mod types;
 mod unused;
@@ -532,6 +531,8 @@ fn register_internals(store: &mut LintStore) {
     store.register_late_mod_pass(|_| Box::new(BadOptAccess));
     store.register_lints(&PassByValue::get_lints());
     store.register_late_mod_pass(|_| Box::new(PassByValue));
+    store.register_lints(&SpanUseEqCtxt::get_lints());
+    store.register_late_mod_pass(|_| Box::new(SpanUseEqCtxt));
     // FIXME(davidtwco): deliberately do not include `UNTRANSLATABLE_DIAGNOSTIC` and
     // `DIAGNOSTIC_OUTSIDE_OF_IMPL` here because `-Wrustc::internal` is provided to every crate and
     // these lints will trigger all of the time - change this once migration to diagnostic structs
@@ -549,6 +550,7 @@ fn register_internals(store: &mut LintStore) {
             LintId::of(USAGE_OF_QUALIFIED_TY),
             LintId::of(EXISTING_DOC_KEYWORD),
             LintId::of(BAD_OPT_ACCESS),
+            LintId::of(SPAN_USE_EQ_CTXT),
         ],
     );
 }
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 594ef97b3ff..a02bee506df 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -901,6 +901,12 @@ pub struct QueryInstability {
 }
 
 #[derive(LintDiagnostic)]
+#[diag(lint_span_use_eq_ctxt)]
+pub struct SpanUseEqCtxtDiag<'a> {
+    pub msg: &'a str,
+}
+
+#[derive(LintDiagnostic)]
 #[diag(lint_tykind_kind)]
 pub struct TykindKind {
     #[suggestion(code = "ty", applicability = "maybe-incorrect")]
diff --git a/compiler/rustc_lint/src/span_use_eq_ctxt.rs b/compiler/rustc_lint/src/span_use_eq_ctxt.rs
deleted file mode 100644
index 19fea01bf4f..00000000000
--- a/compiler/rustc_lint/src/span_use_eq_ctxt.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-use crate::{LateContext, LateLintPass};
-use rustc_hir::{BinOp, BinOpKind, Expr, ExprKind};
-use rustc_span::sym;
-
-declare_lint! {
-    pub SPAN_USE_EQ_CTXT,
-    Warn, // is this the right level?
-    "Use of `==` with `Span::ctxt` rather than `Span::eq_ctxt`"
-}
-
-declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
-
-impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
-        if let ExprKind::Binary(BinOp { node: BinOpKind::Eq, .. }, lhs, rhs) = expr.kind {
-            if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
-                todo!(); // emit lint
-            }
-        }
-    }
-}
-
-fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    match &expr.kind {
-        ExprKind::MethodCall(..) => {
-            // i gave a method a diagnostic item -- FIXME: switch to a diagnostic
-            // item for the Span type and check:
-            //   * method call path == "ctxt"
-            //   * receiver type matches Span diag item
-            // also FIXME(todo) remove old SpanCtxt diagnostic item
-            cx.typeck_results()
-                .type_dependent_def_id(expr.hir_id)
-                .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, did))
-        }
-
-        _ => false,
-    }
-}
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index 69ad11e23f0..7c7f8448c97 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -75,6 +75,7 @@ use rustc_data_structures::fx::FxIndexSet;
 /// the dependency to the parent definition's span. This is performed
 /// using the callback `SPAN_TRACK` to access the query engine.
 ///
+#[cfg_attr(not(test), rustc_diagnostic_item = "Span")]
 #[derive(Clone, Copy, Eq, PartialEq, Hash)]
 #[rustc_pass_by_value]
 pub struct Span {
@@ -212,7 +213,6 @@ impl Span {
 
     /// This function is used as a fast path when decoding the full `SpanData` is not necessary.
     /// It's a cut-down version of `data_untracked`.
-    #[rustc_diagnostic_item = "SpanCtxt"]
     #[inline]
     pub fn ctxt(self) -> SyntaxContext {
         if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index be8c65862dc..9598b2d0310 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -303,7 +303,7 @@ symbols! {
         SliceIndex,
         SliceIter,
         Some,
-        SpanCtxt,
+        Span,
         String,
         StructuralEq,
         StructuralPartialEq,
diff --git a/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs
new file mode 100644
index 00000000000..5b4c59a2e8a
--- /dev/null
+++ b/tests/ui-fulldeps/internal-lints/span_use_eq_ctxt.rs
@@ -0,0 +1,13 @@
+// compile-flags: -Z unstable-options
+
+#![feature(rustc_private)]
+#![deny(rustc::span_use_eq_ctxt)]
+
+extern crate rustc_span;
+use rustc_span::Span;
+
+pub fn f(s: Span, t: Span) -> bool {
+    s.ctxt() == t.ctxt() //~ ERROR use of span ctxt
+}
+
+fn main() {}