1 //==-- llvm/FileCheck/FileCheck.h --------------------------------*- C++ -*-==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 /// \file This file has some utilities to use FileCheck as an API
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_FILECHECK_FILECHECK_H
14 #define LLVM_FILECHECK_FILECHECK_H
15 
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/MemoryBuffer.h"
18 #include "llvm/Support/Regex.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include <bitset>
21 #include <string>
22 #include <vector>
23 
24 namespace llvm {
25 
26 /// Contains info about various FileCheck options.
27 struct FileCheckRequest {
28   std::vector<StringRef> CheckPrefixes;
29   std::vector<StringRef> CommentPrefixes;
30   bool NoCanonicalizeWhiteSpace = false;
31   std::vector<StringRef> ImplicitCheckNot;
32   std::vector<StringRef> GlobalDefines;
33   bool AllowEmptyInput = false;
34   bool AllowUnusedPrefixes = false;
35   bool MatchFullLines = false;
36   bool IgnoreCase = false;
37   bool IsDefaultCheckPrefix = false;
38   bool EnableVarScope = false;
39   bool AllowDeprecatedDagOverlap = false;
40   bool Verbose = false;
41   bool VerboseVerbose = false;
42 };
43 
44 namespace Check {
45 
46 enum FileCheckKind {
47   CheckNone = 0,
48   CheckPlain,
49   CheckNext,
50   CheckSame,
51   CheckNot,
52   CheckDAG,
53   CheckLabel,
54   CheckEmpty,
55   CheckComment,
56 
57   /// Indicates the pattern only matches the end of file. This is used for
58   /// trailing CHECK-NOTs.
59   CheckEOF,
60 
61   /// Marks when parsing found a -NOT check combined with another CHECK suffix.
62   CheckBadNot,
63 
64   /// Marks when parsing found a -COUNT directive with invalid count value.
65   CheckBadCount
66 };
67 
68 enum FileCheckKindModifier {
69   /// Modifies directive to perform literal match.
70   ModifierLiteral = 0,
71 
72   // The number of modifier.
73   Size
74 };
75 
76 class FileCheckType {
77   FileCheckKind Kind;
78   int Count; ///< optional Count for some checks
79   /// Modifers for the check directive.
80   std::bitset<FileCheckKindModifier::Size> Modifiers;
81 
82 public:
83   FileCheckType(FileCheckKind Kind = CheckNone)
84       : Kind(Kind), Count(1), Modifiers() {}
85   FileCheckType(const FileCheckType &) = default;
86   FileCheckType &operator=(const FileCheckType &) = default;
87 
88   operator FileCheckKind() const { return Kind; }
89 
90   int getCount() const { return Count; }
91   FileCheckType &setCount(int C);
92 
93   bool isLiteralMatch() const {
94     return Modifiers[FileCheckKindModifier::ModifierLiteral];
95   }
96   FileCheckType &setLiteralMatch(bool Literal = true) {
97     Modifiers.set(FileCheckKindModifier::ModifierLiteral, Literal);
98     return *this;
99   }
100 
101   // \returns a description of \p Prefix.
102   std::string getDescription(StringRef Prefix) const;
103 
104   // \returns a description of \p Modifiers.
105   std::string getModifiersDescription() const;
106 };
107 } // namespace Check
108 
109 /// Summary of a FileCheck diagnostic.
110 struct FileCheckDiag {
111   /// What is the FileCheck directive for this diagnostic?
112   Check::FileCheckType CheckTy;
113   /// Where is the FileCheck directive for this diagnostic?
114   SMLoc CheckLoc;
115   /// What type of match result does this diagnostic describe?
116   ///
117   /// A directive's supplied pattern is said to be either expected or excluded
118   /// depending on whether the pattern must have or must not have a match in
119   /// order for the directive to succeed.  For example, a CHECK directive's
120   /// pattern is expected, and a CHECK-NOT directive's pattern is excluded.
121   /// All match result types whose names end with "Excluded" are for excluded
122   /// patterns, and all others are for expected patterns.
123   ///
124   /// There might be more than one match result for a single pattern.  For
125   /// example, there might be several discarded matches
126   /// (MatchFoundButDiscarded) before either a good match
127   /// (MatchFoundAndExpected) or a failure to match (MatchNoneButExpected),
128   /// and there might be a fuzzy match (MatchFuzzy) after the latter.
129   enum MatchType {
130     /// Indicates a good match for an expected pattern.
131     MatchFoundAndExpected,
132     /// Indicates a match for an excluded pattern.
133     MatchFoundButExcluded,
134     /// Indicates a match for an expected pattern, but the match is on the
135     /// wrong line.
136     MatchFoundButWrongLine,
137     /// Indicates a discarded match for an expected pattern.
138     MatchFoundButDiscarded,
139     /// Indicates no match for an excluded pattern.
140     MatchNoneAndExcluded,
141     /// Indicates no match for an expected pattern, but this might follow good
142     /// matches when multiple matches are expected for the pattern, or it might
143     /// follow discarded matches for the pattern.
144     MatchNoneButExpected,
145     /// Indicates a fuzzy match that serves as a suggestion for the next
146     /// intended match for an expected pattern with too few or no good matches.
147     MatchFuzzy,
148   } MatchTy;
149   /// The search range if MatchTy is MatchNoneAndExcluded or
150   /// MatchNoneButExpected, or the match range otherwise.
151   unsigned InputStartLine;
152   unsigned InputStartCol;
153   unsigned InputEndLine;
154   unsigned InputEndCol;
155   /// A note to replace the one normally indicated by MatchTy, or the empty
156   /// string if none.
157   std::string Note;
158   FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,
159                 SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange,
160                 StringRef Note = "");
161 };
162 
163 class FileCheckPatternContext;
164 struct FileCheckString;
165 
166 /// FileCheck class takes the request and exposes various methods that
167 /// use information from the request.
168 class FileCheck {
169   FileCheckRequest Req;
170   std::unique_ptr<FileCheckPatternContext> PatternContext;
171   // C++17 TODO: make this a plain std::vector.
172   std::unique_ptr<std::vector<FileCheckString>> CheckStrings;
173 
174 public:
175   explicit FileCheck(FileCheckRequest Req);
176   ~FileCheck();
177 
178   // Combines the check prefixes into a single regex so that we can efficiently
179   // scan for any of the set.
180   //
181   // The semantics are that the longest-match wins which matches our regex
182   // library.
183   Regex buildCheckPrefixRegex();
184 
185   /// Reads the check file from \p Buffer and records the expected strings it
186   /// contains. Errors are reported against \p SM.
187   ///
188   /// Only expected strings whose prefix is one of those listed in \p PrefixRE
189   /// are recorded. \returns true in case of an error, false otherwise.
190   ///
191   /// If \p ImpPatBufferIDRange, then the range (inclusive start, exclusive end)
192   /// of IDs for source buffers added to \p SM for implicit patterns are
193   /// recorded in it.  The range is empty if there are none.
194   bool
195   readCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
196                 std::pair<unsigned, unsigned> *ImpPatBufferIDRange = nullptr);
197 
198   bool ValidateCheckPrefixes();
199 
200   /// Canonicalizes whitespaces in the file. Line endings are replaced with
201   /// UNIX-style '\n'.
202   StringRef CanonicalizeFile(MemoryBuffer &MB,
203                              SmallVectorImpl<char> &OutputBuffer);
204 
205   /// Checks the input to FileCheck provided in the \p Buffer against the
206   /// expected strings read from the check file and record diagnostics emitted
207   /// in \p Diags. Errors are recorded against \p SM.
208   ///
209   /// \returns false if the input fails to satisfy the checks.
210   bool checkInput(SourceMgr &SM, StringRef Buffer,
211                   std::vector<FileCheckDiag> *Diags = nullptr);
212 };
213 
214 } // namespace llvm
215 
216 #endif
217