Skip to main content

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.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                // 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: 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}