Skip to content

Commit cb307bb

Browse files
committed
Address review comments
1 parent 8687205 commit cb307bb

File tree

6 files changed

+102
-41
lines changed

6 files changed

+102
-41
lines changed

clippy_lints/src/crate_in_macro_def.rs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use rustc_ast::ast::MacroDef;
3-
use rustc_ast::node_id::NodeId;
2+
use rustc_ast::ast::{AttrKind, Attribute, Item, ItemKind};
43
use rustc_ast::token::{Token, TokenKind};
54
use rustc_ast::tokenstream::{TokenStream, TokenTree};
65
use rustc_errors::Applicability;
76
use rustc_lint::{EarlyContext, EarlyLintPass};
87
use rustc_session::{declare_lint_pass, declare_tool_lint};
9-
use rustc_span::Span;
8+
use rustc_span::{symbol::sym, Span};
109

1110
declare_clippy_lint! {
1211
/// ### What it does
1312
/// Checks for use of `crate` as opposed to `$crate` in a macro definition.
1413
///
1514
/// ### Why is this bad?
16-
/// `crate` refers to the macro call's crate, whereas `$crate` refers to the macro
17-
/// definition's crate. Rarely is the former intended. See:
15+
/// `crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's
16+
/// crate. Rarely is the former intended. See:
1817
/// https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
1918
///
2019
/// ### Example
2120
/// ```rust
21+
/// #[macro_export]
2222
/// macro_rules! print_message {
2323
/// () => {
2424
/// println!("{}", crate::MESSAGE);
@@ -28,13 +28,21 @@ declare_clippy_lint! {
2828
/// ```
2929
/// Use instead:
3030
/// ```rust
31+
/// #[macro_export]
3132
/// macro_rules! print_message {
3233
/// () => {
3334
/// println!("{}", $crate::MESSAGE);
3435
/// };
3536
/// }
3637
/// pub const MESSAGE: &str = "Hello!";
3738
/// ```
39+
///
40+
/// Note that if the use of `crate` is intentional, an `allow` attribute can be applied to the
41+
/// macro definition, e.g.:
42+
/// ```rust,ignore
43+
/// #[allow(clippy::crate_in_macro_def)]
44+
/// macro_rules! ok { ... crate::foo ... }
45+
/// ```
3846
#[clippy::version = "1.61.0"]
3947
pub CRATE_IN_MACRO_DEF,
4048
correctness,
@@ -43,18 +51,36 @@ declare_clippy_lint! {
4351
declare_lint_pass!(CrateInMacroDef => [CRATE_IN_MACRO_DEF]);
4452

4553
impl EarlyLintPass for CrateInMacroDef {
46-
fn check_mac_def(&mut self, cx: &EarlyContext<'_>, macro_def: &MacroDef, _: NodeId) {
47-
let tts = macro_def.body.inner_tokens();
48-
if let Some(span) = contains_unhygienic_crate_reference(&tts) {
49-
span_lint_and_sugg(
50-
cx,
51-
CRATE_IN_MACRO_DEF,
52-
span,
53-
"reference to the macro call's crate, which is rarely intended",
54-
"if reference to the macro definition's crate is intended, use",
55-
String::from("$crate"),
56-
Applicability::MachineApplicable,
57-
);
54+
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
55+
if_chain! {
56+
if item.attrs.iter().any(is_macro_export);
57+
if let ItemKind::MacroDef(macro_def) = &item.kind;
58+
let tts = macro_def.body.inner_tokens();
59+
if let Some(span) = contains_unhygienic_crate_reference(&tts);
60+
then {
61+
span_lint_and_sugg(
62+
cx,
63+
CRATE_IN_MACRO_DEF,
64+
span,
65+
"reference to the macro call's crate, which is rarely intended",
66+
"if reference to the macro definition's crate is intended, use",
67+
String::from("$crate"),
68+
Applicability::MachineApplicable,
69+
);
70+
}
71+
}
72+
}
73+
}
74+
75+
fn is_macro_export(attr: &Attribute) -> bool {
76+
if_chain! {
77+
if let AttrKind::Normal(attr_item, _) = &attr.kind;
78+
if let [segment] = attr_item.path.segments.as_slice();
79+
if segment.ident.name == sym::macro_export;
80+
then {
81+
true
82+
} else {
83+
false
5884
}
5985
}
6086
}

clippy_lints/src/utils/conf.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ macro_rules! define_Conf {
123123

124124
#[cfg(feature = "internal")]
125125
pub mod metadata {
126-
use $crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
126+
use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
127127

128128
macro_rules! wrap_option {
129129
() => (None);

tests/ui/crate_in_macro_def.fixed

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// run-rustfix
22
#![warn(clippy::crate_in_macro_def)]
33

4-
#[macro_use]
54
mod hygienic {
5+
#[macro_export]
66
macro_rules! print_message_hygienic {
77
() => {
88
println!("{}", $crate::hygienic::MESSAGE);
@@ -12,8 +12,8 @@ mod hygienic {
1212
pub const MESSAGE: &str = "Hello!";
1313
}
1414

15-
#[macro_use]
1615
mod unhygienic {
16+
#[macro_export]
1717
macro_rules! print_message_unhygienic {
1818
() => {
1919
println!("{}", $crate::unhygienic::MESSAGE);
@@ -23,7 +23,34 @@ mod unhygienic {
2323
pub const MESSAGE: &str = "Hello!";
2424
}
2525

26+
mod unhygienic_intentionally {
27+
// For cases where the use of `crate` is intentional, applying `allow` to the macro definition
28+
// should suppress the lint.
29+
#[allow(clippy::crate_in_macro_def)]
30+
#[macro_export]
31+
macro_rules! print_message_unhygienic_intentionally {
32+
() => {
33+
println!("{}", crate::CALLER_PROVIDED_MESSAGE);
34+
};
35+
}
36+
}
37+
38+
#[macro_use]
39+
mod not_exported {
40+
macro_rules! print_message_not_exported {
41+
() => {
42+
println!("{}", crate::not_exported::MESSAGE);
43+
};
44+
}
45+
46+
pub const MESSAGE: &str = "Hello!";
47+
}
48+
2649
fn main() {
2750
print_message_hygienic!();
2851
print_message_unhygienic!();
52+
print_message_unhygienic_intentionally!();
53+
print_message_not_exported!();
2954
}
55+
56+
pub const CALLER_PROVIDED_MESSAGE: &str = "Hello!";

tests/ui/crate_in_macro_def.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// run-rustfix
22
#![warn(clippy::crate_in_macro_def)]
33

4-
#[macro_use]
54
mod hygienic {
5+
#[macro_export]
66
macro_rules! print_message_hygienic {
77
() => {
88
println!("{}", $crate::hygienic::MESSAGE);
@@ -12,8 +12,8 @@ mod hygienic {
1212
pub const MESSAGE: &str = "Hello!";
1313
}
1414

15-
#[macro_use]
1615
mod unhygienic {
16+
#[macro_export]
1717
macro_rules! print_message_unhygienic {
1818
() => {
1919
println!("{}", crate::unhygienic::MESSAGE);
@@ -23,7 +23,34 @@ mod unhygienic {
2323
pub const MESSAGE: &str = "Hello!";
2424
}
2525

26+
mod unhygienic_intentionally {
27+
// For cases where the use of `crate` is intentional, applying `allow` to the macro definition
28+
// should suppress the lint.
29+
#[allow(clippy::crate_in_macro_def)]
30+
#[macro_export]
31+
macro_rules! print_message_unhygienic_intentionally {
32+
() => {
33+
println!("{}", crate::CALLER_PROVIDED_MESSAGE);
34+
};
35+
}
36+
}
37+
38+
#[macro_use]
39+
mod not_exported {
40+
macro_rules! print_message_not_exported {
41+
() => {
42+
println!("{}", crate::not_exported::MESSAGE);
43+
};
44+
}
45+
46+
pub const MESSAGE: &str = "Hello!";
47+
}
48+
2649
fn main() {
2750
print_message_hygienic!();
2851
print_message_unhygienic!();
52+
print_message_unhygienic_intentionally!();
53+
print_message_not_exported!();
2954
}
55+
56+
pub const CALLER_PROVIDED_MESSAGE: &str = "Hello!";

tests/ui/crate_in_macro_def_allow.rs

Lines changed: 0 additions & 19 deletions
This file was deleted.

tests/ui/crate_in_macro_def_allow.stderr

Whitespace-only changes.

0 commit comments

Comments
 (0)