Skip to content

Add relative_path_in_macro_definition lint (#14472) #14645 #14648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ See [Changelog Update](book/src/development/infrastructure/changelog_update.md)
document.

## Unreleased / Beta / In Rust Nightly
### New Lints
- **`relative_path_in_macro_definition`**:
Warns about relative paths to `core` or `kernel` in macro definitions, recommending absolute paths to avoid ambiguity.

[1e5237f4...master](https://github.com/rust-lang/rust-clippy/compare/1e5237f4...master)

Expand Down Expand Up @@ -6226,6 +6229,7 @@ Released 2018-09-13
[`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns
[`regex_creation_in_loops`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_creation_in_loops
[`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
[`relative_path_in_macro_definition`]: https://rust-lang.github.io/rust-clippy/master/index.html#relative_path_in_macro_definition
[`renamed_function_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params
[`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
[`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity
Expand Down
2 changes: 2 additions & 0 deletions clippy_config/src/conf.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::relative_path_in_macro_definition)]

use crate::ClippyConfiguration;
use crate::types::{
DisallowedPath, DisallowedPathWithoutReplacement, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour,
Expand Down
2 changes: 2 additions & 0 deletions clippy_config/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::relative_path_in_macro_definition)]

use clippy_utils::paths::{PathNS, find_crates, lookup_path};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diag};
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/declare_clippy_lint.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(clippy::relative_path_in_macro_definition)]
#[macro_export]
#[allow(clippy::crate_in_macro_def)]
macro_rules! declare_clippy_lint {
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
crate::regex::INVALID_REGEX_INFO,
crate::regex::REGEX_CREATION_IN_LOOPS_INFO,
crate::regex::TRIVIAL_REGEX_INFO,
crate::relative_path_in_macro_definition::RELATIVE_PATH_IN_MACRO_DEFINITION_INFO,
crate::repeat_vec_with_capacity::REPEAT_VEC_WITH_CAPACITY_INFO,
crate::reserve_after_initialization::RESERVE_AFTER_INITIALIZATION_INFO,
crate::return_self_not_must_use::RETURN_SELF_NOT_MUST_USE_INFO,
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/deprecated_lints.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// This file is managed by `cargo dev rename_lint` and `cargo dev deprecate_lint`.
// Prefer to use those when possible.
#![allow(clippy::relative_path_in_macro_definition)]

macro_rules! declare_with_version {
($name:ident($name_version:ident) = [$(
Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ mod ref_option_ref;
mod ref_patterns;
mod reference;
mod regex;
mod relative_path_in_macro_definition;
mod repeat_vec_with_capacity;
mod reserve_after_initialization;
mod return_self_not_must_use;
Expand Down Expand Up @@ -946,5 +947,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
store.register_early_pass(|| Box::new(relative_path_in_macro_definition::RelativePathInMacroDefinition));
// add lints here, do not remove this comment, it's used in `new_lint`
}
2 changes: 2 additions & 0 deletions clippy_lints/src/missing_asserts_for_indexing.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::relative_path_in_macro_definition)]

use std::mem;
use std::ops::ControlFlow;

Expand Down
2 changes: 2 additions & 0 deletions clippy_lints/src/operators/double_comparison.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::relative_path_in_macro_definition)]

use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::eq_expr_value;
use clippy_utils::source::snippet_with_applicability;
Expand Down
97 changes: 97 additions & 0 deletions clippy_lints/src/relative_path_in_macro_definition.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Item, ItemKind};
use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::declare_lint_pass;

declare_clippy_lint! {
/// ### What it does
/// Checks that references to crates in macro definitions use absolute paths.
///
/// ### Why is this bad?
/// Using relative paths (e.g., `crate_name::...`) in macros can lead to ambiguity if the macro is used in a context
/// where a user defines a module with the same name. Absolute paths (e.g., `::crate_name::...`) ensure the macro always refers to the intended crate.
///
/// ### Example
/// ```rust
/// // Bad
/// macro_rules! my_macro {
/// () => {
/// std::mem::drop(0);
/// };
/// }
///
/// // Good
/// macro_rules! my_macro {
/// () => {
/// ::std::mem::drop(0);
/// };
/// }
/// ```
#[clippy::version = "1.88.0"]
pub RELATIVE_PATH_IN_MACRO_DEFINITION,
correctness,
"using relative paths in declarative macros can lead to context-dependent behavior"
}

declare_lint_pass!(RelativePathInMacroDefinition => [RELATIVE_PATH_IN_MACRO_DEFINITION]);

impl EarlyLintPass for RelativePathInMacroDefinition {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if let ItemKind::MacroDef(_, macro_def) = &item.kind {
check_token_stream(cx, &macro_def.body.tokens);
}
}
}

fn check_token_stream(cx: &EarlyContext<'_>, tokens: &TokenStream) {
let mut iter = tokens.iter().peekable();
let mut prev_token: Option<&TokenTree> = None;

while let Some(tree) = iter.next() {
match tree {
TokenTree::Token(token, _) => {
if let TokenKind::Ident(ident, _) = token.kind {
let first_segment = ident;

let is_path_start = iter.peek().is_some_and(|next_tree| {
if let TokenTree::Token(next_token, _) = next_tree {
next_token.kind == TokenKind::PathSep
} else {
false
}
});

if is_path_start {
let is_absolute = prev_token.is_some_and(|prev| {
matches!(
prev,
TokenTree::Token(
Token {
kind: TokenKind::PathSep,
..
},
_
)
)
});

if !is_absolute {
span_lint(
cx,
RELATIVE_PATH_IN_MACRO_DEFINITION,
token.span,
format!("avoid relative path to `{first_segment}` in macro definitions"),
);
}
}
}
},
TokenTree::Delimited(_open_span, _close_span, _delim, token_stream) => {
check_token_stream(cx, token_stream);
},
}
prev_token = Some(tree);
}
}
2 changes: 2 additions & 0 deletions clippy_lints/src/utils/author.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::relative_path_in_macro_definition)]

use clippy_utils::{MaybePath, get_attr, higher, path_def_id, sym};
use itertools::Itertools;
use rustc_ast::LitIntType;
Expand Down
1 change: 1 addition & 0 deletions clippy_utils/src/check_proc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//! must exist at both the start and the end of an item (e.g. an expression or a path) assuming the
//! code was written, and check if the span contains that text. Note this will only work correctly
//! if the span is not from a `macro_rules` based macro.
#![allow(clippy::relative_path_in_macro_definition)]

use rustc_abi::ExternAbi;
use rustc_ast::AttrStyle;
Expand Down
1 change: 1 addition & 0 deletions clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#![feature(array_windows)]
#![recursion_limit = "512"]
#![allow(
clippy::relative_path_in_macro_definition,
clippy::missing_errors_doc,
clippy::missing_panics_doc,
clippy::must_use_candidate,
Expand Down
1 change: 1 addition & 0 deletions clippy_utils/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(clippy::similar_names)] // `expr` and `expn`
#![allow(clippy::relative_path_in_macro_definition)]

use std::sync::{Arc, OnceLock};

Expand Down
1 change: 1 addition & 0 deletions clippy_utils/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//!
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
#![allow(clippy::relative_path_in_macro_definition)]

use crate::{MaybePath, path_def_id, sym};
use rustc_ast::Mutability;
Expand Down
1 change: 1 addition & 0 deletions clippy_utils/src/sugg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Contains utility functions to generate suggestions.
#![deny(clippy::missing_docs_in_private_items)]
#![allow(clippy::relative_path_in_macro_definition)]

use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_with_context};
use crate::ty::expr_sig;
Expand Down
1 change: 1 addition & 0 deletions clippy_utils/src/sym.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(non_upper_case_globals)]
#![allow(clippy::relative_path_in_macro_definition)]

use rustc_span::symbol::PREDEFINED_SYMBOLS_COUNT;

Expand Down
2 changes: 2 additions & 0 deletions clippy_utils/src/visitors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::relative_path_in_macro_definition)]

use crate::ty::needs_ordered_drop;
use crate::{get_enclosing_block, path_to_local_id};
use core::ops::ControlFlow;
Expand Down
2 changes: 2 additions & 0 deletions rustc_tools_util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::relative_path_in_macro_definition)]

use std::path::PathBuf;
use std::process::Command;
use std::str;
Expand Down
12 changes: 6 additions & 6 deletions tests/ui-toml/absolute_paths/absolute_paths.allow_crates.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:14:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:15:13
|
LL | let _ = std::path::is_separator(' ');
| ^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -11,31 +11,31 @@ LL | #![deny(clippy::absolute_paths)]
| ^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:20:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:21:13
|
LL | let _ = ::std::path::MAIN_SEPARATOR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:26:13
|
LL | let _ = std::collections::hash_map::HashMap::<i32, i32>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:28:31
--> tests/ui-toml/absolute_paths/absolute_paths.rs:29:31
|
LL | let _: &std::path::Path = std::path::Path::new("");
| ^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:28:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:29:13
|
LL | let _: &std::path::Path = std::path::Path::new("");
| ^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:43:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:44:13
|
LL | let _ = std::option::Option::None::<i32>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:26:13
|
LL | let _ = std::collections::hash_map::HashMap::<i32, i32>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
24 changes: 12 additions & 12 deletions tests/ui-toml/absolute_paths/absolute_paths.default.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:14:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:15:13
|
LL | let _ = std::path::is_separator(' ');
| ^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -11,67 +11,67 @@ LL | #![deny(clippy::absolute_paths)]
| ^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:20:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:21:13
|
LL | let _ = ::std::path::MAIN_SEPARATOR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:25:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:26:13
|
LL | let _ = std::collections::hash_map::HashMap::<i32, i32>::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:28:31
--> tests/ui-toml/absolute_paths/absolute_paths.rs:29:31
|
LL | let _: &std::path::Path = std::path::Path::new("");
| ^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:28:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:29:13
|
LL | let _: &std::path::Path = std::path::Path::new("");
| ^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:37:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:38:13
|
LL | let _ = ::core::clone::Clone::clone(&0i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:40:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:41:13
|
LL | let _ = <i32 as core::clone::Clone>::clone(&0i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:43:13
--> tests/ui-toml/absolute_paths/absolute_paths.rs:44:13
|
LL | let _ = std::option::Option::None::<i32>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:65:17
--> tests/ui-toml/absolute_paths/absolute_paths.rs:66:17
|
LL | impl<T: core::cmp::Eq> core::fmt::Display for X<T>
| ^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:70:18
--> tests/ui-toml/absolute_paths/absolute_paths.rs:71:18
|
LL | where T: core::clone::Clone
| ^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:65:32
--> tests/ui-toml/absolute_paths/absolute_paths.rs:66:32
|
LL | impl<T: core::cmp::Eq> core::fmt::Display for X<T>
| ^^^^^^^^^^^^^^^^^^

error: consider bringing this path into scope with the `use` keyword
--> tests/ui-toml/absolute_paths/absolute_paths.rs:116:5
--> tests/ui-toml/absolute_paths/absolute_paths.rs:117:5
|
LL | crate::m1::S
| ^^^^^^^^^^^^
Expand Down
Loading