about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/tidy/src/features.rs45
1 files changed, 39 insertions, 6 deletions
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index 9ec9974e1ad..9b6037c6a4b 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -258,7 +258,7 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features
     let mut next_feature_omits_tracking_issue = false;
 
     let mut in_feature_group = false;
-    let mut prev_name = None;
+    let mut prev_names = vec![];
 
     contents
         .lines()
@@ -291,11 +291,11 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features
                 }
 
                 in_feature_group = true;
-                prev_name = None;
+                prev_names = vec![];
                 return None;
             } else if line.starts_with(FEATURE_GROUP_END_PREFIX) {
                 in_feature_group = false;
-                prev_name = None;
+                prev_names = vec![];
                 return None;
             }
 
@@ -325,16 +325,49 @@ fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features
                 }
             };
             if in_feature_group {
-                if prev_name > Some(name) {
+                if prev_names.last() > Some(&name) {
+                    // This assumes the user adds the feature name at the end of the list, as we're
+                    // not looking ahead.
+                    let correct_index = match prev_names.binary_search(&name) {
+                        Ok(_) => {
+                            // This only occurs when the feature name has already been declared.
+                            tidy_error!(
+                                bad,
+                                "{}:{}: duplicate feature {}",
+                                path.display(),
+                                line_number,
+                                name,
+                            );
+                            // skip any additional checks for this line
+                            return None;
+                        }
+                        Err(index) => index,
+                    };
+
+                    let correct_placement = if correct_index == 0 {
+                        "at the beginning of the feature group".to_owned()
+                    } else if correct_index == prev_names.len() {
+                        // I don't believe this is reachable given the above assumption, but it
+                        // doesn't hurt to be safe.
+                        "at the end of the feature group".to_owned()
+                    } else {
+                        format!(
+                            "between {} and {}",
+                            prev_names[correct_index - 1],
+                            prev_names[correct_index],
+                        )
+                    };
+
                     tidy_error!(
                         bad,
-                        "{}:{}: feature {} is not sorted by feature name",
+                        "{}:{}: feature {} is not sorted by feature name (should be {})",
                         path.display(),
                         line_number,
                         name,
+                        correct_placement,
                     );
                 }
-                prev_name = Some(name);
+                prev_names.push(name);
             }
 
             let issue_str = parts.next().unwrap().trim();