Skip to content

Commit 763acde

Browse files
committed
Rework directive checks and add tests
# Conflicts: # src/tools/compiletest/src/header/tests.rs
1 parent f1e7acb commit 763acde

File tree

7 files changed

+105
-76
lines changed

7 files changed

+105
-76
lines changed

src/tools/compiletest/src/header.rs

+50-76
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
1414
use crate::header::cfg::parse_cfg_name_directive;
1515
use crate::header::cfg::MatchOutcome;
1616
use crate::header::needs::CachedNeedsConditions;
17-
use crate::util::find_best_match_for_name;
17+
use crate::util::edit_distance::find_best_match_for_name;
1818
use crate::{extract_cdb_version, extract_gdb_version};
1919

2020
mod cfg;
@@ -681,8 +681,8 @@ pub fn line_directive<'line>(
681681
/// This is generated by collecting directives from ui tests and then extracting their directive
682682
/// names. This is **not** an exhaustive list of all possible directives. Instead, this is a
683683
/// best-effort approximation for diagnostics.
684-
// tidy-alphabetical-start
685684
const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
685+
// tidy-alphabetical-start
686686
"assembly-output",
687687
"aux-build",
688688
"aux-crate",
@@ -880,8 +880,8 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
880880
"unit-test",
881881
"unset-exec-env",
882882
"unset-rustc-env",
883+
// tidy-alphabetical-end
883884
];
884-
// tidy-alphabetical-end
885885

886886
/// The broken-down contents of a line containing a test header directive,
887887
/// which [`iter_header`] passes to its callback function.
@@ -911,6 +911,22 @@ struct HeaderLine<'ln> {
911911
directive: &'ln str,
912912
}
913913

914+
pub(crate) struct CheckDirectiveResult<'ln> {
915+
is_known_directive: bool,
916+
directive_name: &'ln str,
917+
}
918+
919+
// Returns `(is_known_directive, directive_name)`.
920+
pub(crate) fn check_directive(directive_ln: &str) -> CheckDirectiveResult<'_> {
921+
let directive_name =
922+
directive_ln.split_once([':', ' ']).map(|(pre, _)| pre).unwrap_or(directive_ln);
923+
924+
CheckDirectiveResult {
925+
is_known_directive: KNOWN_DIRECTIVE_NAMES.contains(&directive_name),
926+
directive_name: directive_ln,
927+
}
928+
}
929+
914930
fn iter_header(
915931
mode: Mode,
916932
_suite: &str,
@@ -950,6 +966,7 @@ fn iter_header(
950966
let mut ln = String::new();
951967
let mut line_number = 0;
952968

969+
// Match on error annotations like `//~ERROR`.
953970
static REVISION_MAGIC_COMMENT_RE: Lazy<Regex> =
954971
Lazy::new(|| Regex::new("//(\\[.*\\])?~.*").unwrap());
955972

@@ -968,33 +985,19 @@ fn iter_header(
968985
if ln.starts_with("fn") || ln.starts_with("mod") {
969986
return;
970987

971-
// First try to accept `ui_test` style comments
972-
} else if let Some((header_revision, original_directive_line)) = line_directive(comment, ln)
988+
// First try to accept `ui_test` style comments (`//@`)
989+
} else if let Some((header_revision, non_revisioned_directive_line)) =
990+
line_directive(comment, ln)
973991
{
974-
// Let Makefiles and non-rs files just get handled in the regular way.
975-
if testfile.extension().map(|e| e != "rs").unwrap_or(true) {
976-
it(HeaderLine {
977-
line_number,
978-
original_line,
979-
header_revision,
980-
directive: original_directive_line,
981-
});
982-
continue;
983-
}
992+
// Perform unknown directive check on Rust files.
993+
if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
994+
let directive_ln = non_revisioned_directive_line.trim();
984995

985-
let directive_ln = original_directive_line.trim();
996+
let CheckDirectiveResult { is_known_directive, directive_name } = check_directive(directive_ln);
986997

987-
if let Some((directive_name, _)) = directive_ln.split_once([':', ' ']) {
988-
if KNOWN_DIRECTIVE_NAMES.contains(&directive_name) {
989-
it(HeaderLine {
990-
line_number,
991-
original_line,
992-
header_revision,
993-
directive: original_directive_line,
994-
});
995-
continue;
996-
} else {
998+
if !is_known_directive {
997999
*poisoned = true;
1000+
9981001
eprintln!(
9991002
"error: detected unknown compiletest test directive `{}` in {}:{}",
10001003
directive_ln,
@@ -1007,32 +1010,19 @@ fn iter_header(
10071010
{
10081011
eprintln!("help: did you mean `{}` instead?", suggestion);
10091012
}
1010-
return;
1011-
}
1012-
} else if KNOWN_DIRECTIVE_NAMES.contains(&directive_ln) {
1013-
it(HeaderLine {
1014-
line_number,
1015-
original_line,
1016-
header_revision,
1017-
directive: original_directive_line,
1018-
});
1019-
continue;
1020-
} else {
1021-
*poisoned = true;
1022-
eprintln!(
1023-
"error: detected unknown compiletest test directive `{}` in {}:{}",
1024-
directive_ln,
1025-
testfile.display(),
1026-
line_number,
1027-
);
10281013

1029-
if let Some(suggestion) =
1030-
find_best_match_for_name(KNOWN_DIRECTIVE_NAMES, directive_ln, None)
1031-
{
1032-
eprintln!("help: did you mean `{}` instead?", suggestion);
1014+
return;
10331015
}
1034-
return;
10351016
}
1017+
1018+
it(HeaderLine {
1019+
line_number,
1020+
original_line,
1021+
header_revision,
1022+
directive: non_revisioned_directive_line,
1023+
});
1024+
// Then we try to check for legacy-style candidates, which are not the magic ~ERROR family
1025+
// error annotations.
10361026
} else if !REVISION_MAGIC_COMMENT_RE.is_match(ln) {
10371027
let Some((_, rest)) = line_directive("//", ln) else {
10381028
continue;
@@ -1046,34 +1036,18 @@ fn iter_header(
10461036

10471037
let rest = rest.trim_start();
10481038

1049-
for candidate in KNOWN_DIRECTIVE_NAMES.iter() {
1050-
if rest.starts_with(candidate) {
1051-
let Some(prefix_removed) = rest.strip_prefix(candidate) else {
1052-
// We have a comment that's *successfully* parsed as an legacy-style
1053-
// directive. We emit an error here to warn the user.
1054-
*poisoned = true;
1055-
eprintln!(
1056-
"error: detected legacy-style directives in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead:{:#?}",
1057-
testfile.display(),
1058-
line_number,
1059-
line_directive("//", ln),
1060-
);
1061-
return;
1062-
};
1039+
let CheckDirectiveResult { is_known_directive, directive_name } = check_directive(rest);
10631040

1064-
if prefix_removed.starts_with([' ', ':']) {
1065-
// We have a comment that's *successfully* parsed as an legacy-style
1066-
// directive. We emit an error here to warn the user.
1067-
*poisoned = true;
1068-
eprintln!(
1069-
"error: detected legacy-style directives in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead:{:#?}",
1070-
testfile.display(),
1071-
line_number,
1072-
line_directive("//", ln),
1073-
);
1074-
return;
1075-
}
1076-
}
1041+
if is_known_directive {
1042+
*poisoned = true;
1043+
eprintln!(
1044+
"error: detected legacy-style directive {} in compiletest test: {}:{}, please use `ui_test`-style directives `//@` instead: {:#?}",
1045+
directive_name,
1046+
testfile.display(),
1047+
line_number,
1048+
line_directive("//", ln),
1049+
);
1050+
return;
10771051
}
10781052
}
10791053
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//@ check-pass
2+
3+
//~ HELP
4+
fn main() { } //~ERROR
5+
//~^ ERROR
6+
//~| ERROR
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! ignore-wasm
2+
//@ ignore-wasm
3+
//@ check-pass
4+
// regular comment
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// ignore-wasm
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# ignore-owo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//@ needs-headpat

src/tools/compiletest/src/header/tests.rs

+42
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use std::str::FromStr;
55
use crate::common::{Config, Debugger, Mode};
66
use crate::header::{parse_normalization_string, EarlyProps, HeadersCache};
77

8+
use super::iter_header;
9+
810
fn make_test_description<R: Read>(
911
config: &Config,
1012
name: test::TestName,
@@ -612,3 +614,43 @@ fn threads_support() {
612614
assert_eq!(check_ignore(&config, "//@ needs-threads"), !has_threads)
613615
}
614616
}
617+
618+
fn run_path(poisoned: &mut bool, path: &Path, buf: &[u8]) {
619+
let rdr = std::io::Cursor::new(&buf);
620+
iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
621+
}
622+
623+
#[test]
624+
fn test_unknown_directive_check() {
625+
let mut poisoned = false;
626+
run_path(&mut poisoned, Path::new("a.rs"), include_bytes!("./directive_checks/unknown_directive.rs"));
627+
assert!(poisoned);
628+
}
629+
630+
#[test]
631+
fn test_known_legacy_directive_check() {
632+
let mut poisoned = false;
633+
run_path(&mut poisoned, Path::new("a.rs"), include_bytes!("./directive_checks/known_legacy_directive.rs"));
634+
assert!(poisoned);
635+
}
636+
637+
#[test]
638+
fn test_known_directive_check_no_error() {
639+
let mut poisoned = false;
640+
run_path(&mut poisoned, Path::new("a.rs"), include_bytes!("./directive_checks/known_directive.rs"));
641+
assert!(!poisoned);
642+
}
643+
644+
#[test]
645+
fn test_error_annotation_no_error() {
646+
let mut poisoned = false;
647+
run_path(&mut poisoned, Path::new("a.rs"), include_bytes!("./directive_checks/error_annotation.rs"));
648+
assert!(!poisoned);
649+
}
650+
651+
#[test]
652+
fn test_non_rs_unknown_directive_not_checked() {
653+
let mut poisoned = false;
654+
run_path(&mut poisoned, Path::new("a.Makefile"), include_bytes!("./directive_checks/not_rs.Makefile"));
655+
assert!(!poisoned);
656+
}

0 commit comments

Comments
 (0)