Add suspicious_command_arg_space lint.

This commit is contained in:
Mara Bos 2023-02-10 16:59:04 +01:00
parent 0f7558148c
commit 145e6a94d6
3 changed files with 70 additions and 0 deletions

View File

@ -80,6 +80,7 @@
mod stable_sort_primitive;
mod str_splitn;
mod string_extend_chars;
mod suspicious_command_arg_space;
mod suspicious_map;
mod suspicious_splitn;
mod suspicious_to_owned;
@ -3162,6 +3163,32 @@
"collecting an iterator when collect is not needed"
}
declare_clippy_lint! {
/// ### What it does
///
/// Checks for `Command::arg()` invocations that look like they
/// should be multiple arguments instead, such as `arg("-t ext2")`.
///
/// ### Why is this bad?
///
/// Arguments are not split by space. An argument like `arg("-t ext2")`
/// will be passed as a single argument to the command,
/// which is likely not what was intended.
///
/// ### Example
/// ```rust
/// std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
/// ```
/// Use instead:
/// ```rust
/// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
/// ```
#[clippy::version = "1.67.0"]
pub SUSPICIOUS_COMMAND_ARG_SPACE,
suspicious,
"single command line argument that looks like it should be multiple arguments"
}
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Msrv,
@ -3496,6 +3523,9 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
}
},
("arg", [arg]) => {
suspicious_command_arg_space::check(cx, recv, arg, span);
}
("as_deref" | "as_deref_mut", []) => {
needless_option_as_deref::check(cx, expr, recv, name);
},

View File

@ -0,0 +1,39 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::paths;
use clippy_utils::ty::match_type;
use rustc_ast as ast;
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::Span;
use super::SUSPICIOUS_COMMAND_ARG_SPACE;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
if match_type(cx, ty, &paths::STD_PROCESS_COMMAND)
&& let hir::ExprKind::Lit(lit) = &arg.kind
&& let ast::LitKind::Str(s, _) = &lit.node
&& let Some((arg1, arg2)) = s.as_str().split_once(' ')
&& arg1.starts_with('-')
&& arg1.chars().all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '-')
{
span_lint_and_then(
cx,
SUSPICIOUS_COMMAND_ARG_SPACE,
arg.span,
"single argument that looks like it should be multiple arguments",
|diag: &mut Diagnostic| {
diag.multipart_suggestion_verbose(
"consider splitting the argument",
vec![
(span, "args".to_string()),
(arg.span, format!("[{arg1:?}, {arg2:?}]")),
],
Applicability::MaybeIncorrect,
);
}
);
}
}

View File

@ -115,6 +115,7 @@
pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"];
pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];