litcheck_filecheck/rules/
same.rs1use crate::common::*;
2
3#[derive(Debug)]
4pub struct CheckSame<M> {
5 pattern: M,
6}
7impl<M> CheckSame<M>
8where
9 M: MatcherMut,
10{
11 pub fn new(pattern: M) -> Self {
12 Self { pattern }
13 }
14}
15impl<M> Spanned for CheckSame<M>
16where
17 M: MatcherMut,
18{
19 fn span(&self) -> SourceSpan {
20 self.pattern.span()
21 }
22}
23impl<M> Rule for CheckSame<M>
24where
25 M: MatcherMut,
26{
27 fn kind(&self) -> Check {
28 Check::Same
29 }
30
31 fn apply<'input, 'context, C>(&self, context: &mut C) -> DiagResult<Matches<'input>>
32 where
33 C: Context<'input, 'context> + ?Sized,
34 {
35 let input = context.search_line();
36 let result = self.pattern.try_match_mut(input, context)?;
37 match result {
38 MatchResult {
39 ty,
40 info: Some(info),
41 } if ty.is_ok() => {
42 let cursor = context.cursor_mut();
43 assert!(info.span.start().to_usize() < cursor.end_of_line());
44 cursor.set_start(info.span.end().to_usize());
45 Ok(MatchResult::new(ty, Some(info)).into())
46 }
47 result @ MatchResult { info: Some(_), .. } => Ok(result.into()),
48 result => {
49 let extended_result = self
52 .pattern
53 .try_match_mut(context.search_block(), context)?;
54 if let Some(info) = extended_result.info {
55 Ok(Matches::from(MatchResult {
56 ty: MatchType::Failed(CheckFailedError::MatchFoundButWrongLine {
57 span: info.span,
58 input_file: context.input_file(),
59 pattern: context.source_file(self.pattern.span().source_id()).map(
60 |match_file| RelatedCheckError {
61 span: self.pattern.span(),
62 match_file,
63 },
64 ),
65 }),
66 info: Some(info),
67 }))
68 } else {
69 Ok(result.into())
70 }
71 }
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::{pattern::matcher::*, rules::CheckPlain, source_file};
80
81 #[test]
82 fn check_same_test() -> DiagResult<()> {
83 let mut context = TestContext::new();
84 let match_file = source_file!(
85 context.config,
86 "
87CHECK: tail call
88CHECK-SAME: @llvm.atomic.load.add.i64
89"
90 );
91 let input_file = source_file!(
92 context.config,
93 "
94define void @inc4(i64* %p) {
95entry:
96 %0 = tail call i64 @llvm.atomic.load.add.i64.p0i64(i64* %p, i64 1)
97 ret void
98}
99"
100 );
101 context
102 .with_checks(match_file.clone())
103 .with_input(input_file);
104 let mut mctx = context.match_context();
105 let pattern = SubstringMatcher::new(
106 Span::new(
107 SourceSpan::from_range_unchecked(match_file.id(), 6..14),
108 Cow::Borrowed("tail call"),
109 ),
110 mctx.config,
111 )
112 .expect("expected pattern to be valid");
113 let rule = CheckPlain::new(pattern);
114 let matches = rule
115 .apply(&mut mctx)
116 .expect("expected non-fatal application of rule");
117 TestResult::from_matches(matches, &mctx).into_result()?;
118
119 let pattern = SubstringMatcher::new(
120 Span::new(
121 SourceSpan::from_range_unchecked(match_file.id(), 26..50),
122 Cow::Borrowed("@llvm.atomic.load.add.i64"),
123 ),
124 mctx.config,
125 )
126 .expect("expected pattern to be valid");
127 let rule = CheckSame::new(pattern);
128 let matches = rule
129 .apply(&mut mctx)
130 .expect("expected non-fatal application of rule");
131 let matched = TestResult::from_matches(matches, &mctx).into_result()?;
132 assert_eq!(matched[0].span.start().to_u32(), 64);
133 assert_eq!(matched[0].span.len(), 25);
134 let input = mctx.search();
135 assert_eq!(
136 input.as_str(matched[0].matched_range()),
137 "@llvm.atomic.load.add.i64"
138 );
139 assert_eq!(input.buffer()[mctx.cursor().start()], b'.');
140
141 Ok(())
142 }
143}