basic lint v2 implemented

This commit is contained in:
Arthur Lafrance 2023-09-25 00:15:00 -07:00
parent 8769e02d0b
commit f77dea89e1
8 changed files with 69 additions and 43 deletions

View File

@ -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

View File

@ -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 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
}
}
}
// 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,
}
}

View File

@ -83,7 +83,6 @@
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),
],
);
}

View File

@ -900,6 +900,12 @@ pub struct QueryInstability {
pub query: Symbol,
}
#[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 {

View File

@ -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,
}
}

View File

@ -75,6 +75,7 @@
/// 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 @@ pub fn is_dummy(self) -> bool {
/// 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 {

View File

@ -303,7 +303,7 @@
SliceIndex,
SliceIter,
Some,
SpanCtxt,
Span,
String,
StructuralEq,
StructuralPartialEq,

View File

@ -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() {}