Skip to content

Commit 9ea640d

Browse files
committed
Remove FIXME and make it retain old raw string hashes
1 parent 2bdb645 commit 9ea640d

File tree

3 files changed

+75
-53
lines changed

3 files changed

+75
-53
lines changed

clippy_lints/src/bare_dos_device_names.rs

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
use clippy_utils::{
2-
diagnostics::span_lint_and_then, get_parent_expr, is_from_proc_macro, match_def_path, path_res, paths::PATH_NEW,
3-
ty::is_type_diagnostic_item,
4-
};
5-
use rustc_ast::LitKind;
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::paths::PATH_NEW;
3+
use clippy_utils::ty::is_type_diagnostic_item;
4+
use clippy_utils::{get_parent_expr, is_from_proc_macro, match_def_path, path_res};
5+
use rustc_ast::{LitKind, StrStyle};
66
use rustc_errors::Applicability;
77
use rustc_hir::def_id::DefId;
88
use rustc_hir::{Expr, ExprKind, QPath};
99
use rustc_lint::{LateContext, LateLintPass, LintContext};
10-
use rustc_middle::{lint::in_external_macro, ty};
10+
use rustc_middle::lint::in_external_macro;
11+
use rustc_middle::ty;
1112
use rustc_session::{declare_lint_pass, declare_tool_lint};
1213
use rustc_span::{sym, Symbol};
14+
use std::borrow::Cow;
1315

1416
declare_clippy_lint! {
1517
/// ### What it does
@@ -41,7 +43,7 @@ impl<'tcx> LateLintPass<'tcx> for BareDosDeviceNames {
4143
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
4244
if !in_external_macro(cx.sess(), expr.span)
4345
&& let ExprKind::Lit(arg) = expr.kind
44-
&& let LitKind::Str(str_sym, _) = arg.node
46+
&& let LitKind::Str(str_sym, str_style) = arg.node
4547
&& matches!(
4648
&*str_sym.as_str().to_ascii_lowercase(),
4749
"aux"
@@ -77,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for BareDosDeviceNames {
7779
| "prn"
7880
)
7981
&& let Some(parent) = get_parent_expr(cx, expr)
80-
&& (is_path_constructor(cx, parent) || is_path_ty(cx, expr, parent))
82+
&& (is_path_like_constructor(cx, parent) || is_path_like_ty(cx, expr, parent))
8183
&& !is_from_proc_macro(cx, expr)
8284
{
8385
span_lint_and_then(
@@ -86,20 +88,26 @@ impl<'tcx> LateLintPass<'tcx> for BareDosDeviceNames {
8688
expr.span,
8789
"this path refers to a DOS device",
8890
|diag| {
91+
// Keep `r###` and `###`
92+
let (prefix, hashes) = if let StrStyle::Raw(num) = str_style {
93+
(Cow::Borrowed("r"), "#".repeat(num as usize).into())
94+
} else {
95+
(Cow::Borrowed(""), Cow::Borrowed(""))
96+
};
97+
8998
// Suggest making current behavior explicit
9099
diag.span_suggestion_verbose(
91100
expr.span,
92-
"if this is intended, try",
93-
// FIXME: I have zero clue why it normalizes this. `\` -> `/`
94-
format!(r#"r"\\.\{str_sym}"\"#),
101+
"if this is intended, use",
102+
format!(r#"r{hashes}"\\.\{str_sym}"{hashes}"#),
95103
Applicability::MaybeIncorrect,
96104
);
97105

98106
// Suggest making the code refer to a file or folder in the current directory
99107
diag.span_suggestion_verbose(
100108
expr.span,
101-
"if this was intended to point to a file or folder, try",
102-
format!("\"./{str_sym}\""),
109+
"if this was intended to point to a file or folder, use",
110+
format!(r#"{prefix}{hashes}"./{str_sym}"{hashes}"#),
103111
Applicability::MaybeIncorrect,
104112
);
105113
}
@@ -112,9 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for BareDosDeviceNames {
112120
/// parent `Expr`, for performance's sake.
113121
///
114122
/// We can't use `is_path_ty` as these take `AsRef<OsStr>` or similar.
115-
///
116-
/// TODO: Should we lint `OsStr` too, in `is_path_ty`? I personally don't think so.
117-
fn is_path_constructor(cx: &LateContext<'_>, parent: &Expr<'_>) -> bool {
123+
fn is_path_like_constructor(cx: &LateContext<'_>, parent: &Expr<'_>) -> bool {
118124
enum DefPathOrTyAndName {
119125
/// Something from `clippy_utils::paths`.
120126
DefPath(&'static [&'static str]),
@@ -136,21 +142,25 @@ fn is_path_constructor(cx: &LateContext<'_>, parent: &Expr<'_>) -> bool {
136142
&& let QPath::TypeRelative(ty, last_segment) = qpath
137143
&& let Some(call_def_id) = path_res(cx, path).opt_def_id()
138144
&& let Some(ty_def_id) = path_res(cx, ty).opt_def_id()
145+
&& LINTED_METHODS.iter().any(|method| match method {
146+
DefPath(path) => match_def_path(cx, call_def_id, path),
147+
TyAndName((ty_name, method_name)) => {
148+
cx.tcx.is_diagnostic_item(*ty_name, ty_def_id) && last_segment.ident.name == *method_name
149+
},
150+
})
139151
{
140-
return LINTED_METHODS.iter().any(|method| {
141-
match method {
142-
DefPath(path) => match_def_path(cx, call_def_id, path),
143-
TyAndName((ty_name, method_name)) => {
144-
cx.tcx.is_diagnostic_item(*ty_name, ty_def_id) && last_segment.ident.name == *method_name
145-
},
146-
}
147-
});
152+
return true;
148153
}
149154

150155
false
151156
}
152157

153158
/// Gets the `DefId` and arguments of `expr`, if it's a `Call` or `MethodCall`
159+
///
160+
/// TODO: Move this to clippy_utils and extend it to give more info (not just `DefId` and
161+
/// arguments). There are many lints that often need this sorta functionality. Most recently
162+
/// `incorrect_partial_ord_impl_on_ord_type`, but basically all `methods` lints can use this to lint
163+
/// `Self::method(self)` as well.
154164
fn get_def_id_and_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<(DefId, &'tcx [Expr<'tcx>])> {
155165
match expr.kind {
156166
ExprKind::Call(path, args) => Some((path_res(cx, path).opt_def_id()?, args)),
@@ -161,16 +171,14 @@ fn get_def_id_and_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) ->
161171

162172
/// Given a `Ty`, returns whether it is likely a path type, like `Path` or `PathBuf`. Also returns
163173
/// true if it's `impl AsRef<Path>`, `T: AsRef<Path>`, etc. You get the idea.
164-
fn is_path_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, parent: &'tcx Expr<'tcx>) -> bool {
174+
fn is_path_like_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, parent: &'tcx Expr<'tcx>) -> bool {
165175
const LINTED_TRAITS: &[(Symbol, Symbol)] = &[
166176
(sym::AsRef, sym::Path),
167177
(sym::AsMut, sym::Path),
168-
// Basically useless, but let's lint these anyway
169178
(sym::AsRef, sym::PathBuf),
170179
(sym::AsMut, sym::PathBuf),
171180
(sym::Into, sym::Path),
172181
(sym::Into, sym::PathBuf),
173-
// Never seen `From` used in a generic context before, but let's lint these anyway
174182
(sym::From, sym::Path),
175183
(sym::From, sym::PathBuf),
176184
// TODO: Let's add more traits here.
@@ -204,14 +212,11 @@ fn is_path_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, parent: &'tc
204212
// I believe `0` is always `Self`, i.e., `T` or `impl <trait>` so get `1` instead
205213
&& let [_, subst] = trit.trait_ref.substs.as_slice()
206214
&& let Some(as_ref_ty) = subst.as_type()
207-
{
208-
for (trait_sym, ty_sym) in LINTED_TRAITS {
209-
if cx.tcx.is_diagnostic_item(*trait_sym, trit.trait_ref.def_id)
215+
&& LINTED_TRAITS.iter().any(|(trait_sym, ty_sym)| {
216+
cx.tcx.is_diagnostic_item(*trait_sym, trit.trait_ref.def_id)
210217
&& is_type_diagnostic_item(cx, as_ref_ty, *ty_sym)
211-
{
212-
return true;
213-
}
214-
}
218+
}) {
219+
return true;
215220
}
216221
}
217222

tests/ui/bare_dos_device_names.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
//@aux-build:proc_macros.rs:proc-macro
2-
#![allow(clippy::no_effect, unused)]
2+
#![allow(clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
33
#![warn(clippy::bare_dos_device_names)]
44

55
#[macro_use]
66
extern crate proc_macros;
77

88
use std::fs::File;
9-
use std::path::Path;
10-
use std::path::PathBuf;
9+
use std::path::{Path, PathBuf};
1110

1211
fn a<T: AsRef<Path>>(t: T) {}
1312

@@ -20,6 +19,9 @@ fn main() {
2019
b("conin$");
2120
File::open("conin$");
2221
std::path::PathBuf::from("a");
22+
// Keep raw string
23+
Path::new(r##"aux"##);
24+
// Don't lint
2325
PathBuf::from("a");
2426
Path::new("a");
2527
external! {

tests/ui/bare_dos_device_names.stderr

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,63 @@
11
error: this path refers to a DOS device
2-
--> $DIR/bare_dos_device_names.rs:19:7
2+
--> $DIR/bare_dos_device_names.rs:18:7
33
|
44
LL | a("con");
55
| ^^^^^
66
|
77
= note: `-D clippy::bare-dos-device-names` implied by `-D warnings`
8-
help: if this is intended, try
8+
help: if this is intended, use
99
|
10-
LL | a(r"//./con"/);
11-
| ~~~~~~~~~~~
12-
help: if this was intended to point to a file or folder, try
10+
LL | a(r"//./con");
11+
| ~~~~~~~~~~
12+
help: if this was intended to point to a file or folder, use
1313
|
1414
LL | a("./con");
1515
| ~~~~~~~
1616

1717
error: this path refers to a DOS device
18-
--> $DIR/bare_dos_device_names.rs:20:7
18+
--> $DIR/bare_dos_device_names.rs:19:7
1919
|
2020
LL | b("conin$");
2121
| ^^^^^^^^
2222
|
23-
help: if this is intended, try
23+
help: if this is intended, use
2424
|
25-
LL | b(r"//./conin$"/);
26-
| ~~~~~~~~~~~~~~
27-
help: if this was intended to point to a file or folder, try
25+
LL | b(r"//./conin$");
26+
| ~~~~~~~~~~~~~
27+
help: if this was intended to point to a file or folder, use
2828
|
2929
LL | b("./conin$");
3030
| ~~~~~~~~~~
3131

3232
error: this path refers to a DOS device
33-
--> $DIR/bare_dos_device_names.rs:21:16
33+
--> $DIR/bare_dos_device_names.rs:20:16
3434
|
3535
LL | File::open("conin$");
3636
| ^^^^^^^^
3737
|
38-
help: if this is intended, try
38+
help: if this is intended, use
3939
|
40-
LL | File::open(r"//./conin$"/);
41-
| ~~~~~~~~~~~~~~
42-
help: if this was intended to point to a file or folder, try
40+
LL | File::open(r"//./conin$");
41+
| ~~~~~~~~~~~~~
42+
help: if this was intended to point to a file or folder, use
4343
|
4444
LL | File::open("./conin$");
4545
| ~~~~~~~~~~
4646

47-
error: aborting due to 3 previous errors
47+
error: this path refers to a DOS device
48+
--> $DIR/bare_dos_device_names.rs:23:15
49+
|
50+
LL | Path::new(r##"aux"##);
51+
| ^^^^^^^^^^
52+
|
53+
help: if this is intended, use
54+
|
55+
LL | Path::new(r##"//./aux"##);
56+
| ~~~~~~~~~~~~~~
57+
help: if this was intended to point to a file or folder, use
58+
|
59+
LL | Path::new(r##"./aux"##);
60+
| ~~~~~~~~~~~~
61+
62+
error: aborting due to 4 previous errors
4863

0 commit comments

Comments
 (0)