Skip to main content

miniextendr_lint/rules/
s4_method_prefix.rs

1//! MXL111: `s4_*` method name on `#[miniextendr(s4)]` impl.
2//!
3//! S4 codegen auto-prepends `s4_` to every instance method name when generating
4//! the R generic. A Rust method named `s4_foo` on an `#[miniextendr(s4)]` impl
5//! produces an R generic `s4_s4_foo`, making it unreachable via the expected
6//! `s4_foo(obj, ...)` call.
7
8use crate::crate_index::{CrateIndex, MethodReceiverKind};
9use crate::diagnostic::Diagnostic;
10use crate::lint_code::LintCode;
11
12pub fn check(index: &CrateIndex, diagnostics: &mut Vec<Diagnostic>) {
13    for (path, data) in &index.file_data {
14        for (impl_type, methods) in &data.impl_methods {
15            for entry in methods {
16                if entry.class_system != "s4" {
17                    continue;
18                }
19                // Only instance methods are auto-prefixed. A receiver-less
20                // method is the class constructor, named after the type, or a
21                // static method, `Class_method()`.
22                if entry.receiver_kind == MethodReceiverKind::None {
23                    continue;
24                }
25                if let Some(rest) = entry.method_name.strip_prefix("s4_") {
26                    diagnostics.push(
27                        Diagnostic::new(
28                            LintCode::MXL111,
29                            path,
30                            entry.line,
31                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("method `{2}::{0}` will produce R generic `s4_{1}` (s4 codegen auto-prepends `s4_`); rename to `{3}` to avoid the double prefix",
                entry.method_name, entry.method_name, impl_type, rest))
    })format!(
32                                "method `{impl_type}::{}` will produce R generic \
33                                 `s4_{}` (s4 codegen auto-prepends `s4_`); \
34                                 rename to `{rest}` to avoid the double prefix",
35                                entry.method_name, entry.method_name,
36                            ),
37                        )
38                        .with_help(
39                            "the macro prepends `s4_` to every S4 method name; \
40                             keep the Rust method name unprefixed",
41                        ),
42                    );
43                }
44            }
45        }
46    }
47}