New lint: relative_path_in_macro_definition
· Issue #14472 · rust-lang/rust-clippy (original) (raw)
What it does
Check for relative paths (such as core::ops::BitOr
) being used in macros.
When writing declarative macros, one should always refer to items using their absolute path (paths starting with ::
or using $crate
or be keywords such as Self
). That is because users might declare a module with the same name as the first component of the path and thus change the meaning of the macro.
Advantage
This change prevents macros from changing their meaning depending on the context:
macro_rules! derive_bit_or { ($t:ident) => { impl core::ops::BitOr for $t { type Output = Self; fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) } } } }
mod bar { struct Bar(u32); derive_bit_or!(Bar); mod core {} }
This code fails to compile, because the path core::ops::BitOr
is relative and thus the custom core
module defined in mod bar
is used instead of the core
crate.
Drawbacks
Increase verbosity and thus decrease readability of declarative macros.
Example
macro_rules! derive_bit_or { ($t:ident) => { impl core::ops::BitOr for $t { type Output = Self; fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) } } } }
Could be written as:
macro_rules! derive_bit_or { ($t:ident) => { impl ::core::ops::BitOr for $t { type Output = Self; fn bitor(self, rhs: Self) -> Self { Self(self.0 | rhs.0) } } } }