-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Suggest Cstr::count_bytes in strlen_on_c_strings
#16323
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
base: master
Are you sure you want to change the base?
Conversation
|
@Tigls CI is failing on fmt check |
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.
Could you please add tests below/at the considered MSRV, and inside/outside const contexts?
| && let ExprKind::MethodCall(path, self_arg, [], _) = recv.kind | ||
| && !recv.span.from_expansion() | ||
| && path.ident.name == sym::as_ptr | ||
| && self.msrv.meets(cx, msrvs::CONST_BLOCKS) |
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.
What is the link between .count_bytes() and CONST_BLOCKS?
Also:
- If the MSRV isn't met, the previous suggestion should still apply.
- Different MSRV apply in and outside a
constcontext.
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.
yeah, I didn't know I can add new names to MSRV enum, thought they are kind of fixed code names for versions.
But makes sense, all fixed now.
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.
Don't forget to add tests for all combinations of MSRV/const contexts. You can look at how it's done in other tests by looking for the #[clippy::msrv] attribute.
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.
Looks like I can't call the libc::strlen in the const context. Since it is an FFI function, which is linked at runtime, it just won't compile. Does it mean I can safely remove the msrv branch for const context and keep only the branch for non-const contex, since the user won't be able to compile it anyway?
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.
@samueltardieu let me know if you had time to have a look and close this
|
Reminder, once the PR becomes ready for a review, use |
|
@rustbot ready |
|
|
||
| declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]); | ||
| pub struct StrlenOnCStrings<'a> { | ||
| msrv: &'a Msrv, |
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.
Msrv is Copy, so it should be fine to store it by value
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.
fixed
| let ty = cx.typeck_results().expr_ty(self_arg).peel_refs(); | ||
| let method_name = if ty.is_diag_item(cx, sym::cstring_type) { | ||
| "as_bytes" | ||
| } else if ty.is_lang_item(cx, LangItem::CStr) { | ||
| "to_bytes" | ||
| } else { | ||
| return; | ||
| }; | ||
| span_lint_and_sugg( | ||
| cx, | ||
| STRLEN_ON_C_STRINGS, | ||
| span, | ||
| "using `libc::strlen` on a `CString` or `CStr` value", | ||
| "try", | ||
| format!("{val_name}.{method_name}().len()"), | ||
| app, | ||
| ); | ||
| } |
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 code in the two branches is very similar. Imo it would be better to use span_lint_and_then and put the MSRV-dependent logic inside its closure.
This comment has been minimized.
This comment has been minimized.
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
This comment has been minimized.
This comment has been minimized.
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.
That's looking good. Could you please squash all the commits together?
|
@rustbot ready |
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.
@samueltardieu should we include this last change in this PR? If so, @Tigls, feel free to amend it into your last commit
| let suggestion = if self.msrv.meets(cx, msrvs::CSTR_COUNT_BYTES) { | ||
| format!("{val_name}.count_bytes()") | ||
| } else if ty.is_diag_item(cx, sym::cstring_type) { | ||
| format!("{val_name}.as_bytes().len()") | ||
| } else if ty.is_lang_item(cx, LangItem::CStr) { | ||
| format!("{val_name}.to_bytes().len()") | ||
| } else { | ||
| return; | ||
| }; |
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.
In #16391, it was decided that we should lint types that dereference to CStr as well, and just recommend to_bytes() to avoid complications with CString in particular (see #16391 (comment) for more context). Therefore it should be safe to simplify this to:
| let suggestion = if self.msrv.meets(cx, msrvs::CSTR_COUNT_BYTES) { | |
| format!("{val_name}.count_bytes()") | |
| } else if ty.is_diag_item(cx, sym::cstring_type) { | |
| format!("{val_name}.as_bytes().len()") | |
| } else if ty.is_lang_item(cx, LangItem::CStr) { | |
| format!("{val_name}.to_bytes().len()") | |
| } else { | |
| return; | |
| }; | |
| let suggestion = if self.msrv.meets(cx, msrvs::CSTR_COUNT_BYTES) { | |
| format!("{val_name}.count_bytes()") | |
| } else { | |
| format!("{val_name}.to_bytes().len()") | |
| }; |
| /// ### What it does | ||
| /// Checks for usage of `libc::strlen` on a `CString` or `CStr` value, | ||
| /// and suggest calling `as_bytes().len()` or `to_bytes().len()` respectively instead. | ||
| /// and suggest calling `count_bytes()`instead. |
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.
small typo:
| /// and suggest calling `count_bytes()`instead. | |
| /// and suggest calling `count_bytes()` instead. |
Yes, that would be better indeed. |
Closes #16308
changelog: [
strlen_on_c_strings]: changes suggestion to use CStr::count_bytes()