-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Wip: Add new lint "char_slices" #6529
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,6 +66,34 @@ declare_clippy_lint! { | |
"usage of `Box<Vec<T>>`, vector elements are already on the heap" | ||
} | ||
|
||
declare_clippy_lint! { | ||
/// **What it does:** Checks for use of `&[char]` anywhere in the code. | ||
/// | ||
/// **Why is this bad?** `char` represents a Unicode codepoint, not a | ||
/// character. Usually users of `&[char]` want O(1) indexing on characters, | ||
/// not codepoints. | ||
/// | ||
/// **Known problems:** None. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When dealing with FFI to other high-level languages where strings are represented by sequences of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as far as we understand it, (from what we understand There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found another counter-example (though nightly only): std::str::pattern::Pattern is implemented on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
/// | ||
/// **Example:** | ||
/// ```rust,ignore | ||
/// struct X { | ||
/// chars: &[char] | ||
/// } | ||
/// ``` | ||
/// | ||
/// Better: | ||
/// | ||
/// ```rust,ignore | ||
/// struct X { | ||
/// chars: &[&str] | ||
/// } | ||
/// ``` | ||
pub CHAR_SLICES, | ||
pedantic, | ||
"usage of `&[char]`, usually you want to index characters instead of codepoints" | ||
} | ||
|
||
declare_clippy_lint! { | ||
/// **What it does:** Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code. | ||
/// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. | ||
|
@@ -252,7 +280,7 @@ pub struct Types { | |
vec_box_size_threshold: u64, | ||
} | ||
|
||
impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER]); | ||
impl_lint_pass!(Types => [BOX_VEC, VEC_BOX, CHAR_SLICES, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER]); | ||
|
||
impl<'tcx> LateLintPass<'tcx> for Types { | ||
fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) { | ||
|
@@ -581,6 +609,24 @@ impl Types { | |
"a `VecDeque` might work", | ||
); | ||
return; // don't recurse into the type | ||
} else if let TyKind::Slice(s) = hir_ty.kind { | ||
if let TyKind::Path(ref qpath) = s.kind { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would probably be more readable using an |
||
if !is_local { | ||
let hir_id = hir_ty.hir_id; | ||
let res = qpath_res(cx, qpath, hir_id); | ||
if let Some(def_id) = res.opt_def_id() { | ||
if Some(def_id) == cx.tcx.lang_items().char_impl() { | ||
brightly-salty marked this conversation as resolved.
Show resolved
Hide resolved
|
||
span_lint( | ||
cx, | ||
CHAR_SLICES, | ||
hir_ty.span, | ||
"consider using `&[&str]` instead of `&[char]`", | ||
); | ||
return; // don't recurse into the type | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
match *qpath { | ||
|
@@ -714,6 +760,25 @@ impl Types { | |
}; | ||
self.check_ty(cx, &mut_ty.ty, is_local); | ||
}, | ||
TyKind::Slice(ref s) => { | ||
if let TyKind::Path(ref qpath) = s.kind { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to be the same as L614..629. Perhaps factor out a method? |
||
if !is_local { | ||
let hir_id = hir_ty.hir_id; | ||
let res = qpath_res(cx, qpath, hir_id); | ||
if let Some(def_id) = res.opt_def_id() { | ||
if Some(def_id) == cx.tcx.lang_items().char_impl() { | ||
span_lint( | ||
cx, | ||
CHAR_SLICES, | ||
hir_ty.span, | ||
"consider using `&[&str]` instead of `&[char]`", | ||
); | ||
return; // don't recurse into the type | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
_ => self.check_ty(cx, &mut_ty.ty, is_local), | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#![warn(clippy::char_slices)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is missing the corresponding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is because it currently does not produce any output in stderr. I think something is wrong but I have no idea what it is. If you have any ideas they would be very welcome. (This is only my second PR to clippy, and my first was relatively easy because it was almost exactly the same as three other lints). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmmm... What I usually do in this case is to comment out lint conditions or move the lint out of other checks until output appears. Then I may reorder the checks until I've found the one that precludes linting and then I try to understand why it doesn't match. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @llogiq I think I found the problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO how about just using |
||
|
||
fn main() { | ||
let char_slice: &[char] = &['a', 'b']; | ||
takes_char_slice(char_slice); | ||
let char_slice2 = returns_char_slice(); | ||
} | ||
|
||
fn takes_char_slice(char_slice: &[char]) { | ||
println!("{:?}", char_slice) | ||
} | ||
|
||
fn returns_char_slice() -> &'static [char] { | ||
&['c', 'd'] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docs should also say something about how to index on characters (e.g.
unicode_segmentation
?)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the issue, the correct way to index on characters is to use
&[&str]
. I can try to make that more clear in the documentation if that is correct.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was not talking about the type but the code.