-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into redundant_local
- Loading branch information
Showing
31 changed files
with
1,832 additions
and
51 deletions.
There are no files selected for viewing
This file contains 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 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 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 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 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 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 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 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 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,216 @@ | ||
use crate::Lint; | ||
use clippy_utils::{diagnostics::span_lint_and_then, is_lint_allowed}; | ||
use rustc_hir::{Expr, ExprKind}; | ||
use rustc_lint::{LateContext, LateLintPass, LintContext}; | ||
use rustc_middle::{lint::in_external_macro, ty::Ty}; | ||
use rustc_session::{declare_lint_pass, declare_tool_lint}; | ||
use rustc_span::Symbol; | ||
use std::borrow::Cow; | ||
|
||
declare_clippy_lint! { | ||
/// ### What it does | ||
/// Checks for the usage of the `to_ne_bytes` method and/or the function `from_ne_bytes`. | ||
/// | ||
/// ### Why is this bad? | ||
/// It's not, but some may prefer to specify the target endianness explicitly. | ||
/// | ||
/// ### Example | ||
/// ```rust,ignore | ||
/// let _x = 2i32.to_ne_bytes(); | ||
/// let _y = 2i64.to_ne_bytes(); | ||
/// ``` | ||
#[clippy::version = "1.71.0"] | ||
pub HOST_ENDIAN_BYTES, | ||
restriction, | ||
"disallows usage of the `to_ne_bytes` method" | ||
} | ||
|
||
declare_clippy_lint! { | ||
/// ### What it does | ||
/// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`. | ||
/// | ||
/// ### Why is this bad? | ||
/// It's not, but some may wish to lint usage of this method, either to suggest using the host | ||
/// endianness or big endian. | ||
/// | ||
/// ### Example | ||
/// ```rust,ignore | ||
/// let _x = 2i32.to_le_bytes(); | ||
/// let _y = 2i64.to_le_bytes(); | ||
/// ``` | ||
#[clippy::version = "1.71.0"] | ||
pub LITTLE_ENDIAN_BYTES, | ||
restriction, | ||
"disallows usage of the `to_le_bytes` method" | ||
} | ||
|
||
declare_clippy_lint! { | ||
/// ### What it does | ||
/// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`. | ||
/// | ||
/// ### Why is this bad? | ||
/// It's not, but some may wish to lint usage of this method, either to suggest using the host | ||
/// endianness or little endian. | ||
/// | ||
/// ### Example | ||
/// ```rust,ignore | ||
/// let _x = 2i32.to_be_bytes(); | ||
/// let _y = 2i64.to_be_bytes(); | ||
/// ``` | ||
#[clippy::version = "1.71.0"] | ||
pub BIG_ENDIAN_BYTES, | ||
restriction, | ||
"disallows usage of the `to_be_bytes` method" | ||
} | ||
|
||
declare_lint_pass!(EndianBytes => [HOST_ENDIAN_BYTES, LITTLE_ENDIAN_BYTES, BIG_ENDIAN_BYTES]); | ||
|
||
const HOST_NAMES: [&str; 2] = ["from_ne_bytes", "to_ne_bytes"]; | ||
const LITTLE_NAMES: [&str; 2] = ["from_le_bytes", "to_le_bytes"]; | ||
const BIG_NAMES: [&str; 2] = ["from_be_bytes", "to_be_bytes"]; | ||
|
||
#[derive(Clone, Debug)] | ||
enum LintKind { | ||
Host, | ||
Little, | ||
Big, | ||
} | ||
|
||
#[derive(Clone, Copy, PartialEq)] | ||
enum Prefix { | ||
From, | ||
To, | ||
} | ||
|
||
impl LintKind { | ||
fn allowed(&self, cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { | ||
is_lint_allowed(cx, self.as_lint(), expr.hir_id) | ||
} | ||
|
||
fn as_lint(&self) -> &'static Lint { | ||
match self { | ||
LintKind::Host => HOST_ENDIAN_BYTES, | ||
LintKind::Little => LITTLE_ENDIAN_BYTES, | ||
LintKind::Big => BIG_ENDIAN_BYTES, | ||
} | ||
} | ||
|
||
fn as_name(&self, prefix: Prefix) -> &str { | ||
let index = usize::from(prefix == Prefix::To); | ||
|
||
match self { | ||
LintKind::Host => HOST_NAMES[index], | ||
LintKind::Little => LITTLE_NAMES[index], | ||
LintKind::Big => BIG_NAMES[index], | ||
} | ||
} | ||
} | ||
|
||
impl LateLintPass<'_> for EndianBytes { | ||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { | ||
if in_external_macro(cx.sess(), expr.span) { | ||
return; | ||
} | ||
|
||
if_chain! { | ||
if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind; | ||
if args.is_empty(); | ||
let ty = cx.typeck_results().expr_ty(receiver); | ||
if ty.is_primitive_ty(); | ||
if maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty); | ||
then { | ||
return; | ||
} | ||
} | ||
|
||
if_chain! { | ||
if let ExprKind::Call(function, ..) = expr.kind; | ||
if let ExprKind::Path(qpath) = function.kind; | ||
if let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id(); | ||
if let Some(function_name) = cx.get_def_path(def_id).last(); | ||
let ty = cx.typeck_results().expr_ty(expr); | ||
if ty.is_primitive_ty(); | ||
then { | ||
maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty); | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) -> bool { | ||
let ne = LintKind::Host.as_name(prefix); | ||
let le = LintKind::Little.as_name(prefix); | ||
let be = LintKind::Big.as_name(prefix); | ||
|
||
let (lint, other_lints) = match name.as_str() { | ||
name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]), | ||
name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]), | ||
name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]), | ||
_ => return false, | ||
}; | ||
|
||
let mut help = None; | ||
|
||
'build_help: { | ||
// all lints disallowed, don't give help here | ||
if [&[lint], other_lints.as_slice()] | ||
.concat() | ||
.iter() | ||
.all(|lint| !lint.allowed(cx, expr)) | ||
{ | ||
break 'build_help; | ||
} | ||
|
||
// ne_bytes and all other lints allowed | ||
if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) { | ||
help = Some(Cow::Borrowed("specify the desired endianness explicitly")); | ||
break 'build_help; | ||
} | ||
|
||
// le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but | ||
// le_bytes is not | ||
if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) { | ||
help = Some(Cow::Borrowed("use the native endianness instead")); | ||
break 'build_help; | ||
} | ||
|
||
let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr)); | ||
let len = allowed_lints.clone().count(); | ||
|
||
let mut help_str = "use ".to_owned(); | ||
|
||
for (i, lint) in allowed_lints.enumerate() { | ||
let only_one = len == 1; | ||
if !only_one { | ||
help_str.push_str("either of "); | ||
} | ||
|
||
help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix))); | ||
|
||
if i != len && !only_one { | ||
help_str.push_str("or "); | ||
} | ||
} | ||
|
||
help = Some(Cow::Owned(help_str + "instead")); | ||
} | ||
|
||
span_lint_and_then( | ||
cx, | ||
lint.as_lint(), | ||
expr.span, | ||
&format!( | ||
"usage of the {}`{ty}::{}`{}", | ||
if prefix == Prefix::From { "function " } else { "" }, | ||
lint.as_name(prefix), | ||
if prefix == Prefix::To { " method" } else { "" }, | ||
), | ||
move |diag| { | ||
if let Some(help) = help { | ||
diag.help(help); | ||
} | ||
}, | ||
); | ||
|
||
true | ||
} |
Oops, something went wrong.