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

Update str utils to prevent ICEs and FNs #7873

Merged
merged 3 commits into from
Oct 25, 2021
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
58 changes: 20 additions & 38 deletions clippy_lints/src/enum_variants.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! lint on enum variants that are prefixed or suffixed by the same characters

use clippy_utils::camel_case;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::is_present_in_source;
use clippy_utils::str_utils::{self, count_match_end, count_match_start};
use rustc_hir::{EnumDef, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
Expand Down Expand Up @@ -117,26 +117,6 @@ impl_lint_pass!(EnumVariantNames => [
MODULE_INCEPTION
]);

/// Returns the number of chars that match from the start
#[must_use]
fn partial_match(pre: &str, name: &str) -> usize {
let mut name_iter = name.chars();
let _ = name_iter.next_back(); // make sure the name is never fully matched
pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
}

/// Returns the number of chars that match from the end
#[must_use]
fn partial_rmatch(post: &str, name: &str) -> usize {
let mut name_iter = name.chars();
let _ = name_iter.next(); // make sure the name is never fully matched
post.chars()
.rev()
.zip(name_iter.rev())
.take_while(|&(l, r)| l == r)
.count()
}

fn check_variant(
cx: &LateContext<'_>,
threshold: u64,
Expand All @@ -150,7 +130,7 @@ fn check_variant(
}
for var in def.variants {
let name = var.ident.name.as_str();
if partial_match(item_name, &name) == item_name_chars
if count_match_start(item_name, &name).char_count == item_name_chars
&& name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
&& name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
{
Expand All @@ -161,7 +141,7 @@ fn check_variant(
"variant name starts with the enum's name",
);
}
if partial_rmatch(item_name, &name) == item_name_chars {
if count_match_end(item_name, &name).char_count == item_name_chars {
span_lint(
cx,
ENUM_VARIANT_NAMES,
Expand All @@ -171,33 +151,33 @@ fn check_variant(
}
}
let first = &def.variants[0].ident.name.as_str();
let mut pre = &first[..camel_case::until(&*first)];
let mut post = &first[camel_case::from(&*first)..];
let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
for var in def.variants {
let name = var.ident.name.as_str();

let pre_match = partial_match(pre, &name);
let pre_match = count_match_start(pre, &name).byte_count;
pre = &pre[..pre_match];
let pre_camel = camel_case::until(pre);
let pre_camel = str_utils::camel_case_until(pre).byte_index;
pre = &pre[..pre_camel];
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
if next.is_numeric() {
return;
}
if next.is_lowercase() {
let last = pre.len() - last.len_utf8();
let last_camel = camel_case::until(&pre[..last]);
pre = &pre[..last_camel];
let last_camel = str_utils::camel_case_until(&pre[..last]);
pre = &pre[..last_camel.byte_index];
} else {
break;
}
}

let post_match = partial_rmatch(post, &name);
let post_end = post.len() - post_match;
let post_match = count_match_end(post, &name);
let post_end = post.len() - post_match.byte_count;
post = &post[post_end..];
let post_camel = camel_case::from(post);
post = &post[post_camel..];
let post_camel = str_utils::camel_case_start(post);
post = &post[post_camel.byte_index..];
}
let (what, value) = match (pre.is_empty(), post.is_empty()) {
(true, true) => return,
Expand Down Expand Up @@ -266,14 +246,16 @@ impl LateLintPass<'_> for EnumVariantNames {
);
}
}
if item.vis.node.is_pub() {
let matching = partial_match(mod_camel, &item_camel);
let rmatching = partial_rmatch(mod_camel, &item_camel);
// The `module_name_repetitions` lint should only trigger if the item has the module in its
// name. Having the same name is accepted.
if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
let matching = count_match_start(mod_camel, &item_camel);
let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();

let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();

if matching == nchars {
if matching.char_count == nchars {
match item_camel.chars().nth(nchars) {
Some(c) if is_word_beginning(c) => span_lint(
cx,
Expand All @@ -284,7 +266,7 @@ impl LateLintPass<'_> for EnumVariantNames {
_ => (),
}
}
if rmatching == nchars {
if rmatching.char_count == nchars {
span_lint(
cx,
MODULE_NAME_REPETITIONS,
Expand Down
117 changes: 0 additions & 117 deletions clippy_utils/src/camel_case.rs

This file was deleted.

2 changes: 1 addition & 1 deletion clippy_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ pub mod sym_helper;
#[allow(clippy::module_name_repetitions)]
pub mod ast_utils;
pub mod attrs;
pub mod camel_case;
pub mod comparisons;
pub mod consts;
pub mod diagnostics;
Expand All @@ -50,6 +49,7 @@ pub mod paths;
pub mod ptr;
pub mod qualify_min_const_fn;
pub mod source;
pub mod str_utils;
pub mod sugg;
pub mod ty;
pub mod usage;
Expand Down
Loading