Skip to content
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

Lint "&PathBuf instead of &Path" in PTR_ARG #6506

Merged
merged 1 commit into from
Dec 27, 2020
Merged
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: 2 additions & 2 deletions clippy_dev/src/ra_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
use std::path::{Path, PathBuf};

// This module takes an absolute path to a rustc repo and alters the dependencies to point towards
// the respective rustc subcrates instead of using extern crate xyz.
Expand Down Expand Up @@ -44,7 +44,7 @@ pub fn run(rustc_path: Option<&str>) {
}

fn inject_deps_into_manifest(
rustc_source_dir: &PathBuf,
rustc_source_dir: &Path,
manifest_path: &str,
cargo_toml: &str,
lib_rs: &str,
Expand Down
60 changes: 45 additions & 15 deletions clippy_lints/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,20 +182,6 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:

if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
if is_type_diagnostic_item(cx, ty, sym::vec_type) {
let mut ty_snippet = None;
if_chain! {
if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last();
then {
let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
}).collect();
if types.len() == 1 {
ty_snippet = snippet_opt(cx, types[0].span);
}
}
};
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
span_lint_and_then(
cx,
Expand All @@ -204,7 +190,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
"writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
with non-Vec-based slices.",
|diag| {
if let Some(ref snippet) = ty_snippet {
if let Some(ref snippet) = get_only_generic_arg_snippet(cx, arg) {
diag.span_suggestion(
arg.span,
"change this to",
Expand Down Expand Up @@ -247,6 +233,33 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
},
);
}
} else if match_type(cx, ty, &paths::PATH_BUF) {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
span_lint_and_then(
cx,
PTR_ARG,
arg.span,
"writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.",
|diag| {
diag.span_suggestion(
arg.span,
"change this to",
"&Path".into(),
Applicability::Unspecified,
);
for (clonespan, suggestion) in spans {
diag.span_suggestion_short(
clonespan,
&snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
Cow::Owned(format!("change `{}` to", x))
}),
suggestion.into(),
Applicability::Unspecified,
);
}
},
);
}
} else if match_type(cx, ty, &paths::COW) {
if_chain! {
if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind;
Expand Down Expand Up @@ -309,6 +322,23 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id:
}
}

fn get_only_generic_arg_snippet(cx: &LateContext<'_>, arg: &Ty<'_>) -> Option<String> {
if_chain! {
if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last();
let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
}).collect();
if types.len() == 1;
then {
snippet_opt(cx, types[0].span)
} else {
None
}
}
}

fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
if let TyKind::Rptr(ref lt, ref m) = ty.kind {
Some((lt, m.mutbl, ty.span))
Expand Down
22 changes: 22 additions & 0 deletions tests/ui/ptr_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![warn(clippy::ptr_arg)]

use std::borrow::Cow;
use std::path::PathBuf;

fn do_vec(x: &Vec<i64>) {
//Nothing here
Expand All @@ -21,6 +22,15 @@ fn do_str_mut(x: &mut String) {
//Nothing here either
}

fn do_path(x: &PathBuf) {
//Nothing here either
}

fn do_path_mut(x: &mut PathBuf) {
// no error here
//Nothing here either
}

fn main() {}

trait Foo {
Expand Down Expand Up @@ -55,6 +65,14 @@ fn str_cloned(x: &String) -> String {
x.clone()
}

fn path_cloned(x: &PathBuf) -> PathBuf {
let a = x.clone();
let b = x.clone();
let c = b.clone();
let d = a.clone().clone().clone();
x.clone()
}

fn false_positive_capacity(x: &Vec<u8>, y: &String) {
let a = x.capacity();
let b = y.clone();
Expand Down Expand Up @@ -87,10 +105,12 @@ impl Foo2 for String {
// Check that the allow attribute on parameters is honored
mod issue_5644 {
use std::borrow::Cow;
use std::path::PathBuf;

fn allowed(
#[allow(clippy::ptr_arg)] _v: &Vec<u32>,
#[allow(clippy::ptr_arg)] _s: &String,
#[allow(clippy::ptr_arg)] _p: &PathBuf,
#[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
) {
}
Expand All @@ -100,6 +120,7 @@ mod issue_5644 {
fn allowed(
#[allow(clippy::ptr_arg)] _v: &Vec<u32>,
#[allow(clippy::ptr_arg)] _s: &String,
#[allow(clippy::ptr_arg)] _p: &PathBuf,
#[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
) {
}
Expand All @@ -109,6 +130,7 @@ mod issue_5644 {
fn allowed(
#[allow(clippy::ptr_arg)] _v: &Vec<u32>,
#[allow(clippy::ptr_arg)] _s: &String,
#[allow(clippy::ptr_arg)] _p: &PathBuf,
#[allow(clippy::ptr_arg)] _c: &Cow<[i32]>,
) {
}
Expand Down
45 changes: 37 additions & 8 deletions tests/ui/ptr_arg.stderr
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
--> $DIR/ptr_arg.rs:6:14
--> $DIR/ptr_arg.rs:7:14
|
LL | fn do_vec(x: &Vec<i64>) {
| ^^^^^^^^^ help: change this to: `&[i64]`
|
= note: `-D clippy::ptr-arg` implied by `-D warnings`

error: writing `&String` instead of `&str` involves a new object where a slice will do.
--> $DIR/ptr_arg.rs:15:14
--> $DIR/ptr_arg.rs:16:14
|
LL | fn do_str(x: &String) {
| ^^^^^^^ help: change this to: `&str`

error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.
--> $DIR/ptr_arg.rs:25:15
|
LL | fn do_path(x: &PathBuf) {
| ^^^^^^^^ help: change this to: `&Path`

error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
--> $DIR/ptr_arg.rs:28:18
--> $DIR/ptr_arg.rs:38:18
|
LL | fn do_vec(x: &Vec<i64>);
| ^^^^^^^^^ help: change this to: `&[i64]`

error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices.
--> $DIR/ptr_arg.rs:41:14
--> $DIR/ptr_arg.rs:51:14
|
LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
| ^^^^^^^^
Expand All @@ -38,7 +44,7 @@ LL | x.to_owned()
|

error: writing `&String` instead of `&str` involves a new object where a slice will do.
--> $DIR/ptr_arg.rs:50:18
--> $DIR/ptr_arg.rs:60:18
|
LL | fn str_cloned(x: &String) -> String {
| ^^^^^^^
Expand All @@ -60,8 +66,31 @@ help: change `x.clone()` to
LL | x.to_string()
|

error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do.
--> $DIR/ptr_arg.rs:68:19
|
LL | fn path_cloned(x: &PathBuf) -> PathBuf {
| ^^^^^^^^
|
help: change this to
|
LL | fn path_cloned(x: &Path) -> PathBuf {
| ^^^^^
help: change `x.clone()` to
|
LL | let a = x.to_path_buf();
| ^^^^^^^^^^^^^^^
help: change `x.clone()` to
|
LL | let b = x.to_path_buf();
| ^^^^^^^^^^^^^^^
help: change `x.clone()` to
|
LL | x.to_path_buf()
|

error: writing `&String` instead of `&str` involves a new object where a slice will do.
--> $DIR/ptr_arg.rs:58:44
--> $DIR/ptr_arg.rs:76:44
|
LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
| ^^^^^^^
Expand All @@ -80,10 +109,10 @@ LL | let c = y;
| ^

error: using a reference to `Cow` is not recommended.
--> $DIR/ptr_arg.rs:72:25
--> $DIR/ptr_arg.rs:90:25
|
LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
| ^^^^^^^^^^^ help: change this to: `&[i32]`

error: aborting due to 7 previous errors
error: aborting due to 9 previous errors