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