-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add lint to replace const
s with const fn
s
#2344
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
use rustc::lint::*; | ||
use rustc::hir; | ||
use rustc::hir::def::Def; | ||
use utils::{match_def_path, span_lint_and_sugg}; | ||
|
||
/// **What it does:** Checks for usage of `ATOMIC_X_INIT`, `ONCE_INIT`, and | ||
/// `uX/iX::MIN/MAX`. | ||
/// | ||
/// **Why is this bad?** `const fn`s exist | ||
/// | ||
/// **Known problems:** None. | ||
/// | ||
/// **Example:** | ||
/// ```rust | ||
/// static FOO: AtomicIsize = ATOMIC_ISIZE_INIT; | ||
/// ``` | ||
/// | ||
/// Could be written: | ||
/// | ||
/// ```rust | ||
/// static FOO: AtomicIsize = AtomicIsize::new(0); | ||
/// ``` | ||
declare_lint! { | ||
pub REPLACE_CONSTS, | ||
Allow, | ||
"Lint usages of standard library `const`s that could be replaced by `const fn`s" | ||
} | ||
|
||
pub struct ReplaceConsts; | ||
|
||
impl LintPass for ReplaceConsts { | ||
fn get_lints(&self) -> LintArray { | ||
lint_array!(REPLACE_CONSTS) | ||
} | ||
} | ||
|
||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ReplaceConsts { | ||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { | ||
if_chain! { | ||
if let hir::ExprPath(ref qp) = expr.node; | ||
if let Def::Const(def_id) = cx.tables.qpath_def(qp, expr.hir_id); | ||
then { | ||
for &(const_path, repl_snip) in REPLACEMENTS { | ||
if match_def_path(cx.tcx, def_id, const_path) { | ||
span_lint_and_sugg( | ||
cx, | ||
REPLACE_CONSTS, | ||
expr.span, | ||
&format!("using `{}`", const_path.last().expect("empty path")), | ||
"try this", | ||
repl_snip.to_string(), | ||
); | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
const REPLACEMENTS: &[(&[&str], &str)] = &[ | ||
// Once | ||
(&["core", "sync", "ONCE_INIT"], "Once::new()"), | ||
// Atomic | ||
(&["core", "sync", "atomic", "ATOMIC_BOOL_INIT"], "AtomicBool::new(false)"), | ||
(&["core", "sync", "atomic", "ATOMIC_ISIZE_INIT"], "AtomicIsize::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_I8_INIT"], "AtomicI8::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_I16_INIT"], "AtomicI16::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_I32_INIT"], "AtomicI32::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_I64_INIT"], "AtomicI64::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_USIZE_INIT"], "AtomicUsize::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_U8_INIT"], "AtomicU8::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_U16_INIT"], "AtomicU16::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_U32_INIT"], "AtomicU32::new(0)"), | ||
(&["core", "sync", "atomic", "ATOMIC_U64_INIT"], "AtomicU64::new(0)"), | ||
// Min | ||
(&["core", "isize", "MIN"], "isize::min_value()"), | ||
(&["core", "i8", "MIN"], "i8::min_value()"), | ||
(&["core", "i16", "MIN"], "i16::min_value()"), | ||
(&["core", "i32", "MIN"], "i32::min_value()"), | ||
(&["core", "i64", "MIN"], "i64::min_value()"), | ||
(&["core", "i128", "MIN"], "i128::min_value()"), | ||
(&["core", "usize", "MIN"], "usize::min_value()"), | ||
(&["core", "u8", "MIN"], "u8::min_value()"), | ||
(&["core", "u16", "MIN"], "u16::min_value()"), | ||
(&["core", "u32", "MIN"], "u32::min_value()"), | ||
(&["core", "u64", "MIN"], "u64::min_value()"), | ||
(&["core", "u128", "MIN"], "u128::min_value()"), | ||
// Max | ||
(&["core", "isize", "MAX"], "isize::max_value()"), | ||
(&["core", "i8", "MAX"], "i8::max_value()"), | ||
(&["core", "i16", "MAX"], "i16::max_value()"), | ||
(&["core", "i32", "MAX"], "i32::max_value()"), | ||
(&["core", "i64", "MAX"], "i64::max_value()"), | ||
(&["core", "i128", "MAX"], "i128::max_value()"), | ||
(&["core", "usize", "MAX"], "usize::max_value()"), | ||
(&["core", "u8", "MAX"], "u8::max_value()"), | ||
(&["core", "u16", "MAX"], "u16::max_value()"), | ||
(&["core", "u32", "MAX"], "u32::max_value()"), | ||
(&["core", "u64", "MAX"], "u64::max_value()"), | ||
(&["core", "u128", "MAX"], "u128::max_value()"), | ||
]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#![feature(integer_atomics, i128, i128_type)] | ||
#![allow(blacklisted_name)] | ||
#![deny(replace_consts)] | ||
use std::sync::atomic::*; | ||
use std::sync::{ONCE_INIT, Once}; | ||
|
||
fn bad() { | ||
// Once | ||
{ let foo = ONCE_INIT; }; | ||
// Atomic | ||
{ let foo = ATOMIC_BOOL_INIT; }; | ||
{ let foo = ATOMIC_ISIZE_INIT; }; | ||
{ let foo = ATOMIC_I8_INIT; }; | ||
{ let foo = ATOMIC_I16_INIT; }; | ||
{ let foo = ATOMIC_I32_INIT; }; | ||
{ let foo = ATOMIC_I64_INIT; }; | ||
{ let foo = ATOMIC_USIZE_INIT; }; | ||
{ let foo = ATOMIC_U8_INIT; }; | ||
{ let foo = ATOMIC_U16_INIT; }; | ||
{ let foo = ATOMIC_U32_INIT; }; | ||
{ let foo = ATOMIC_U64_INIT; }; | ||
// Min | ||
{ let foo = std::isize::MIN; }; | ||
{ let foo = std::i8::MIN; }; | ||
{ let foo = std::i16::MIN; }; | ||
{ let foo = std::i32::MIN; }; | ||
{ let foo = std::i64::MIN; }; | ||
{ let foo = std::i128::MIN; }; | ||
{ let foo = std::usize::MIN; }; | ||
{ let foo = std::u8::MIN; }; | ||
{ let foo = std::u16::MIN; }; | ||
{ let foo = std::u32::MIN; }; | ||
{ let foo = std::u64::MIN; }; | ||
{ let foo = std::u128::MIN; }; | ||
// Max | ||
{ let foo = std::isize::MAX; }; | ||
{ let foo = std::i8::MAX; }; | ||
{ let foo = std::i16::MAX; }; | ||
{ let foo = std::i32::MAX; }; | ||
{ let foo = std::i64::MAX; }; | ||
{ let foo = std::i128::MAX; }; | ||
{ let foo = std::usize::MAX; }; | ||
{ let foo = std::u8::MAX; }; | ||
{ let foo = std::u16::MAX; }; | ||
{ let foo = std::u32::MAX; }; | ||
{ let foo = std::u64::MAX; }; | ||
{ let foo = std::u128::MAX; }; | ||
} | ||
|
||
fn good() { | ||
// Once | ||
{ let foo = Once::new(); }; | ||
// Atomic | ||
{ let foo = AtomicBool::new(false); }; | ||
{ let foo = AtomicIsize::new(0); }; | ||
{ let foo = AtomicI8::new(0); }; | ||
{ let foo = AtomicI16::new(0); }; | ||
{ let foo = AtomicI32::new(0); }; | ||
{ let foo = AtomicI64::new(0); }; | ||
{ let foo = AtomicUsize::new(0); }; | ||
{ let foo = AtomicU8::new(0); }; | ||
{ let foo = AtomicU16::new(0); }; | ||
{ let foo = AtomicU32::new(0); }; | ||
{ let foo = AtomicU64::new(0); }; | ||
// Min | ||
{ let foo = isize::min_value(); }; | ||
{ let foo = i8::min_value(); }; | ||
{ let foo = i16::min_value(); }; | ||
{ let foo = i32::min_value(); }; | ||
{ let foo = i64::min_value(); }; | ||
{ let foo = i128::min_value(); }; | ||
{ let foo = usize::min_value(); }; | ||
{ let foo = u8::min_value(); }; | ||
{ let foo = u16::min_value(); }; | ||
{ let foo = u32::min_value(); }; | ||
{ let foo = u64::min_value(); }; | ||
{ let foo = u128::min_value(); }; | ||
// Max | ||
{ let foo = isize::max_value(); }; | ||
{ let foo = i8::max_value(); }; | ||
{ let foo = i16::max_value(); }; | ||
{ let foo = i32::max_value(); }; | ||
{ let foo = i64::max_value(); }; | ||
{ let foo = i128::max_value(); }; | ||
{ let foo = usize::max_value(); }; | ||
{ let foo = u8::max_value(); }; | ||
{ let foo = u16::max_value(); }; | ||
{ let foo = u32::max_value(); }; | ||
{ let foo = u64::max_value(); }; | ||
{ let foo = u128::max_value(); }; | ||
} | ||
|
||
fn main() { | ||
bad(); | ||
good(); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MIN
/MAX
are not bad at all, I'd rather recommend the opposite replacement.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add a config option for enabling
MIN
/MAX
on this lint. The opposite replacement might be better suited for a different lint though.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@petrochenkov why? the
MIN
is instd::isize::MIN
and thus requires the full path or an import.min_value
exists on the typeThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's actually the main reason I recommend these; fewer paths to import.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I sort of assumed that it'd make sense to long-term push people toward the
const fn
versions over the constants. For theINIT
structs, they simply aren't at clear as usingnew
, and for theMIN/MAX
structs, the types themselves are already in scope.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. I thought they are associated constants already.
Someone should resurrect that PR.
Why? Constants exist in the language to represent... constants.
MIN
/MAX
are constants, why would you avoid a feature specifically designed to represent them (except for the full path issue which is a fixable library deficiency).min_value()
is longer and has that extraneous call.(I agree about
INIT
atomics though.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^^ This was a concern about constants and const functions in general.
All the listed constants have specific reasons to avoid them (until rust-lang/rust#28656 is redone), so this PR is okay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I totally agree with you @petrochenkov in terms of making them associated constants. When you do end up redoing that PR, you should include the float constants too, as those don't have associated const fns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, no config option for
MIN
/MAX
then?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah, leave it out, we'll adjust the lint when it makes sense to behave differently on stable