Writing custom lints inspect generic type

I'm wanting to write some custom lints and am following the following guides linked below. I got stuck trying to implement my idea. Maybe someone more familiar with clippy/rustc internals might be able to shed some light on the method I need to call to get the type information I need.

I want to create a lint which forbids implementing from and try_from from tuples. Such as

struct Foo;
impl From<(u32,u32)> for Foo {...}

Here's where I'm at:

#![feature(rustc_private)]
#![feature(let_chains)]

extern crate rustc_ast;
extern crate rustc_hir;
extern crate rustc_lint;
extern crate rustc_session;
extern crate rustc_span;

mod disallowed_from_tuple {

    use rustc_hir::{self as hir};
    use rustc_lint::{LateContext, LateLintPass, LintContext};
    use rustc_session::{declare_lint_pass, declare_tool_lint};
    use rustc_span::sym;

    declare_tool_lint! {
        pub lint::IMPL_FROM_TUPLE,
        Warn,
        "Warn if implemeting From or TryFrom from a tuple",
        report_in_external_macro: false
    }
    declare_lint_pass!(ImplFromTuple => [IMPL_FROM_TUPLE]);

    impl<'tcx> LateLintPass<'tcx> for ImplFromTuple {
        fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
            let tcx = cx.tcx;

            if let hir::ItemKind::Impl(impl_) = item.kind
                // the trait is a `From` or `TryFrom` implementation
                && let Some(trait_) = &impl_.of_trait
                && let Some(did) = trait_.trait_def_id()
                && (tcx.is_diagnostic_item(sym::From, did) ||
                    tcx.is_diagnostic_item(sym::TryFrom, did) )
                // for From<T>, TryFrom<T> T is a tuple
                // stuck here unsure how to see if T is a tuple
                
                && let generic = tcx.generics_of(did)
                // && let x = tcx.impl_subject(did)
            {

                eprintln!("{generic:?}");
                let warning_msg = if tcx.is_diagnostic_item(sym::From, did) {
                    "implementing From using a tuple"
                } else {
                    "implementing TryFrom using a tuple"
                };

                cx.span_lint(IMPL_FROM_TUPLE, trait_.path.span, |diag| { diag.primary_message(warning_msg); });
            }
        }
    }
}

use rustc_lint::LintStore;

use crate::disallowed_from_tuple::ImplFromTuple;

fn main() -> Result<(), ()> {
    let args: Vec<String> = std::env::args().collect();
    if args.is_empty() {
        eprintln!("Missing file operand");
        return Err(());
    }
    println!("Running lint example with arguments `{:?}`", args);

    rustc_tools::with_lints(&args, vec![], |store: &mut LintStore| {
        store.register_late_pass(|_| Box::new(ImplFromTuple));
    })
    .map_err(|_| ())
}

I've been testing on this foo.rs

pub fn foo() {}
fn bar() {}

pub fn generics<A: Sized>(_: A) {
    println!("hello");

}

struct Bar;
impl From<i32> for Bar {
    fn from(value: i32) -> Self {
        Bar
    }
}
impl From<(i32, i32)> for Bar {
    fn from(value: (i32,i32)) -> Self {
        Bar
    }
}

fn main() {
    foo();
    bar();
    generics(0i8);
}

playground is not runnable because it requires some rust components which aren't included by default

[package]
name = "custom-lints"
version = "0.1.0"
edition = "2021"

rustc-workspace-hack = "1.0.0"

[dependencies]
rustc-tools = "0.80"

I'm using the rust docs from the second link

https://blog.guillaume-gomez.fr/articles/2024-01-18+Writing+your+own+Rust+linter
https://guillaumegomez.github.io/rustc-tools/compiler/0.80/doc/rustc_middle/ty/context/struct.TyCtxt.html

Any help is appreciated.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.