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 } ;
66use rustc_errors:: Applicability ;
77use rustc_hir:: def_id:: DefId ;
88use rustc_hir:: { Expr , ExprKind , QPath } ;
99use 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;
1112use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1213use rustc_span:: { sym, Symbol } ;
14+ use std:: borrow:: Cow ;
1315
1416declare_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.
154164fn 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
0 commit comments