llvm.org GIT mirror llvm / c58b079
Add FileCheck -implicit-check-not option to allow stricter tests without adding too many CHECK-NOTs manually. Summary: Add FileCheck -implicit-check-not option which allows specifying a pattern that should only occur in the input when explicitly matched by a positive check. This feature allows checking tool diagnostics in a way clang -verify does it for compiler diagnostics. The option has been tested on a number of clang-tidy checks, I'll post a link to the clang-tidy patch to this thread. Once there's an agreement on the general direction, I can add tests and documentation. Reviewers: djasper, bkramer Reviewed By: bkramer Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D4462 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@212810 91177308-0d34-0410-b5e6-96231b3b80d8 Alexander Kornienko 5 years ago
3 changed file(s) with 83 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
4747 tabs) which causes it to ignore these differences (a space will match a tab).
4848 The :option:`--strict-whitespace` argument disables this behavior. End-of-line
4949 sequences are canonicalized to UNIX-style ``\n`` in all modes.
50
51 .. option:: --implicit-check-not check-pattern
52
53 Adds implicit negative checks for the specified patterns between positive
54 checks. The option allows writing stricter tests without stuffing them with
55 ``CHECK-NOT``s.
56
57 For example, "``--implicit-check-not warning:``" can be useful when testing
58 diagnostic messages from tools that don't have an option similar to ``clang
59 -verify``. With this option FileCheck will verify that input does not contain
60 warnings not covered by any ``CHECK:`` patterns.
5061
5162 .. option:: -version
5263
0 ; RUN: sed 's#^;.*##' %s | FileCheck -check-prefix=CHECK-PASS -implicit-check-not=warning: %s
1 ; RUN: sed 's#^;.*##' %s | not FileCheck -check-prefix=CHECK-FAIL1 -implicit-check-not=warning: %s 2>&1 | FileCheck %s -check-prefix CHECK-ERROR1
2 ; RUN: sed 's#^;.*##' %s | not FileCheck -check-prefix=CHECK-FAIL2 -implicit-check-not=warning: %s 2>&1 | FileCheck %s -check-prefix CHECK-ERROR2
3 ; RUN: sed 's#^;.*##' %s | not FileCheck -check-prefix=CHECK-FAIL3 -implicit-check-not=warning: %s 2>&1 | FileCheck %s -check-prefix CHECK-ERROR3
4 ; RUN: sed 's#^;.*##' %s | not FileCheck -check-prefix=CHECK-FAIL1 -implicit-check-not='{{aaa|bbb|ccc}}' %s 2>&1 | FileCheck %s -check-prefix CHECK-ERROR4
5 ; RUN: sed 's#^;.*##' %s | not FileCheck -check-prefix=CHECK-FAIL1 -implicit-check-not=aaa -implicit-check-not=bbb -implicit-check-not=ccc %s 2>&1 | FileCheck %s -check-prefix CHECK-ERROR5
6 ; RUN: sed 's#^;.*##' %s | not FileCheck -check-prefix=CHECK-FAIL2 -implicit-check-not=aaa -implicit-check-not=bbb -implicit-check-not=ccc %s 2>&1 | FileCheck %s -check-prefix CHECK-ERROR6
7 ; RUN: sed 's#^;.*##' %s | not FileCheck -check-prefix=CHECK-FAIL3 -implicit-check-not=aaa -implicit-check-not=bbb -implicit-check-not=ccc %s 2>&1 | FileCheck %s -check-prefix CHECK-ERROR7
8
9 warning: aaa
10 ; CHECK-PASS: warning: aaa
11 ; CHECK-ERROR1: error: CHECK-FAIL1-NOT: string occurred!
12 ; CHECK-ERROR1: command line:1:22: note: CHECK-FAIL1-NOT: pattern specified here
13 ; CHECK-ERROR1-NEXT: -implicit-check-not='warning:'
14 ; CHECK-FAIL2: warning: aaa
15 ; CHECK-FAIL3: warning: aaa
16 ; CHECK-ERROR4: error: CHECK-FAIL1-NOT: string occurred!
17 ; CHECK-ERROR4: command line:1:22: note: CHECK-FAIL1-NOT: pattern specified here
18 ; CHECK-ERROR4-NEXT: {{-implicit-check-not='\{\{aaa\|bbb\|ccc\}\}'}}
19 ; CHECK-ERROR5: error: CHECK-FAIL1-NOT: string occurred!
20 ; CHECK-ERROR5: command line:1:22: note: CHECK-FAIL1-NOT: pattern specified here
21 ; CHECK-ERROR5-NEXT: -implicit-check-not='aaa'
22
23 warning: bbb
24 ; CHECK-PASS: warning: bbb
25 ; CHECK-FAIL1: warning: bbb
26 ; CHECK-ERROR2: error: CHECK-FAIL2-NOT: string occurred!
27 ; CHECK-ERROR2: command line:1:22: note: CHECK-FAIL2-NOT: pattern specified here
28 ; CHECK-ERROR2-NEXT: -implicit-check-not='warning:'
29 ; CHECK-FAIL3: warning: bbb
30 ; CHECK-ERROR6: error: CHECK-FAIL2-NOT: string occurred!
31 ; CHECK-ERROR6: command line:1:22: note: CHECK-FAIL2-NOT: pattern specified here
32 ; CHECK-ERROR6-NEXT: -implicit-check-not='bbb'
33
34 warning: ccc
35 ; CHECK-PASS: warning: ccc
36 ; CHECK-FAIL1: warning: ccc
37 ; CHECK-FAIL2: warning: ccc
38 ; CHECK-ERROR3: error: CHECK-FAIL3-NOT: string occurred!
39 ; CHECK-ERROR3: command line:1:22: note: CHECK-FAIL3-NOT: pattern specified here
40 ; CHECK-ERROR3-NEXT: -implicit-check-not='warning:'
41 ; CHECK-ERROR7: error: CHECK-FAIL3-NOT: string occurred!
42 ; CHECK-ERROR7: command line:1:22: note: CHECK-FAIL3-NOT: pattern specified here
43 ; CHECK-ERROR7-NEXT: -implicit-check-not='ccc'
4848 static cl::opt
4949 NoCanonicalizeWhiteSpace("strict-whitespace",
5050 cl::desc("Do not treat all horizontal whitespace as equivalent"));
51
52 static cl::list ImplicitCheckNot(
53 "implicit-check-not",
54 cl::desc("Add an implicit negative check with this pattern to every\n"
55 "positive check. This can be used to ensure that no instances of\n"
56 "this pattern occur which are not matched by a positive pattern"),
57 cl::value_desc("pattern"));
5158
5259 typedef cl::list::const_iterator prefix_iterator;
5360
836843
837844 // Find all instances of CheckPrefix followed by : in the file.
838845 StringRef Buffer = F->getBuffer();
839 std::vector DagNotMatches;
846
847 std::vector ImplicitNegativeChecks;
848 for (const auto &PatternString : ImplicitCheckNot) {
849 // Create a buffer with fake command line content in order to display the
850 // command line option responsible for the specific implicit CHECK-NOT.
851 std::string Prefix = std::string("-") + ImplicitCheckNot.ArgStr + "='";
852 std::string Suffix = "'";
853 MemoryBuffer *CmdLine = MemoryBuffer::getMemBufferCopy(
854 Prefix + PatternString + Suffix, "command line");
855 StringRef PatternInBuffer =
856 CmdLine->getBuffer().substr(Prefix.size(), PatternString.size());
857 SM.AddNewSourceBuffer(CmdLine, SMLoc());
858
859 ImplicitNegativeChecks.push_back(Pattern(Check::CheckNot));
860 ImplicitNegativeChecks.back().ParsePattern(PatternInBuffer,
861 "IMPLICIT-CHECK", SM, 0);
862 }
863
864
865 std::vector DagNotMatches = ImplicitNegativeChecks;
840866
841867 // LineNumber keeps track of the line on which CheckPrefix instances are
842868 // found.
909935 PatternLoc,
910936 CheckTy));
911937 std::swap(DagNotMatches, CheckStrings.back().DagNotStrings);
938 DagNotMatches = ImplicitNegativeChecks;
912939 }
913940
914941 // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first