litcheck_filecheck/rules/
same.rs

1use 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.offset() < cursor.end_of_line());
44                cursor.set_start(info.span.end());
45                Ok(MatchResult::new(ty, Some(info)).into())
46            }
47            result @ MatchResult { info: Some(_), .. } => Ok(result.into()),
48            result => {
49                // For better diagnostics, extend our search to the end
50                // of the block, just in case there is a match, just in the wrong place
51                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: Some(RelatedCheckError {
60                                span: self.pattern.span(),
61                                match_file: context.match_file(),
62                            }),
63                        }),
64                        info: Some(info),
65                    }))
66                } else {
67                    Ok(result.into())
68                }
69            }
70        }
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use crate::pattern::matcher::*;
78    use crate::rules::CheckPlain;
79
80    #[test]
81    fn check_same_test() -> DiagResult<()> {
82        let mut context = TestContext::new();
83        context
84            .with_checks(
85                "
86CHECK: tail call
87CHECK-SAME: @llvm.atomic.load.add.i64
88",
89            )
90            .with_input(
91                "
92define void @inc4(i64* %p) {
93entry:
94        %0 = tail call i64 @llvm.atomic.load.add.i64.p0i64(i64* %p, i64 1)
95        ret void
96}
97",
98            );
99        let mut mctx = context.match_context();
100        let pattern = SubstringMatcher::new(
101            Span::new(SourceSpan::from(6..14), Cow::Borrowed("tail call")),
102            &mctx.config,
103        )
104        .expect("expected pattern to be valid");
105        let rule = CheckPlain::new(pattern);
106        let matches = rule
107            .apply(&mut mctx)
108            .expect("expected non-fatal application of rule");
109        TestResult::from_matches(matches, &mctx).into_result()?;
110
111        let pattern = SubstringMatcher::new(
112            Span::new(
113                SourceSpan::from(26..50),
114                Cow::Borrowed("@llvm.atomic.load.add.i64"),
115            ),
116            &mctx.config,
117        )
118        .expect("expected pattern to be valid");
119        let rule = CheckSame::new(pattern);
120        let matches = rule
121            .apply(&mut mctx)
122            .expect("expected non-fatal application of rule");
123        let matched = TestResult::from_matches(matches, &mctx).into_result()?;
124        assert_eq!(matched[0].span.offset(), 64);
125        assert_eq!(matched[0].span.len(), 25);
126        let input = mctx.search();
127        assert_eq!(
128            input.as_str(matched[0].matched_range()),
129            "@llvm.atomic.load.add.i64"
130        );
131        assert_eq!(input.buffer()[mctx.cursor().start()], b'.');
132
133        Ok(())
134    }
135}