clang 17.0.0git
VerifyDiagnosticConsumer.h
Go to the documentation of this file.
1//===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- 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#ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
10#define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
11
14#include "clang/Basic/LLVM.h"
17#include "llvm/ADT/DenseMap.h"
18#include "llvm/ADT/PointerIntPair.h"
19#include "llvm/ADT/StringRef.h"
20#include <cassert>
21#include <limits>
22#include <memory>
23#include <string>
24#include <vector>
25
26namespace clang {
27
28class FileEntry;
29class LangOptions;
30class SourceManager;
31class TextDiagnosticBuffer;
32
33/// VerifyDiagnosticConsumer - Create a diagnostic client which will use
34/// markers in the input source to check that all the emitted diagnostics match
35/// those expected.
36///
37/// INVOKING THE DIAGNOSTIC CHECKER:
38///
39/// VerifyDiagnosticConsumer is typically invoked via the "-verify" option to
40/// "clang -cc1". "-verify" is equivalent to "-verify=expected", so all
41/// diagnostics are typically specified with the prefix "expected". For
42/// example:
43///
44/// \code
45/// int A = B; // expected-error {{use of undeclared identifier 'B'}}
46/// \endcode
47///
48/// Custom prefixes can be specified as a comma-separated sequence. Each
49/// prefix must start with a letter and contain only alphanumeric characters,
50/// hyphens, and underscores. For example, given just "-verify=foo,bar",
51/// the above diagnostic would be ignored, but the following diagnostics would
52/// be recognized:
53///
54/// \code
55/// int A = B; // foo-error {{use of undeclared identifier 'B'}}
56/// int C = D; // bar-error {{use of undeclared identifier 'D'}}
57/// \endcode
58///
59/// Multiple occurrences accumulate prefixes. For example,
60/// "-verify -verify=foo,bar -verify=baz" is equivalent to
61/// "-verify=expected,foo,bar,baz".
62///
63/// SPECIFYING DIAGNOSTICS:
64///
65/// Indicating that a line expects an error or a warning is simple. Put a
66/// comment on the line that has the diagnostic, use:
67///
68/// \code
69/// expected-{error,warning,remark,note}
70/// \endcode
71///
72/// to tag if it's an expected error, remark or warning, and place the expected
73/// text between {{ and }} markers. The full text doesn't have to be included,
74/// only enough to ensure that the correct diagnostic was emitted.
75///
76/// Here's an example:
77///
78/// \code
79/// int A = B; // expected-error {{use of undeclared identifier 'B'}}
80/// \endcode
81///
82/// You can place as many diagnostics on one line as you wish. To make the code
83/// more readable, you can use slash-newline to separate out the diagnostics.
84///
85/// Alternatively, it is possible to specify the line on which the diagnostic
86/// should appear by appending "@<line>" to "expected-<type>", for example:
87///
88/// \code
89/// #warning some text
90/// // expected-warning@10 {{some text}}
91/// \endcode
92///
93/// The line number may be absolute (as above), or relative to the current
94/// line by prefixing the number with either '+' or '-'.
95///
96/// If the diagnostic is generated in a separate file, for example in a shared
97/// header file, it may be beneficial to be able to declare the file in which
98/// the diagnostic will appear, rather than placing the expected-* directive in
99/// the actual file itself. This can be done using the following syntax:
100///
101/// \code
102/// // expected-error@path/include.h:15 {{error message}}
103/// \endcode
104///
105/// The path can be absolute or relative and the same search paths will be used
106/// as for #include directives. The line number in an external file may be
107/// substituted with '*' meaning that any line number will match (useful where
108/// the included file is, for example, a system header where the actual line
109/// number may change and is not critical).
110///
111/// As an alternative to specifying a fixed line number, the location of a
112/// diagnostic can instead be indicated by a marker of the form "#<marker>".
113/// Markers are specified by including them in a comment, and then referenced
114/// by appending the marker to the diagnostic with "@#<marker>":
115///
116/// \code
117/// #warning some text // #1
118/// // expected-warning@#1 {{some text}}
119/// \endcode
120///
121/// The name of a marker used in a directive must be unique within the
122/// compilation.
123///
124/// The simple syntax above allows each specification to match exactly one
125/// error. You can use the extended syntax to customize this. The extended
126/// syntax is "expected-<type> <n> {{diag text}}", where <type> is one of
127/// "error", "warning" or "note", and <n> is a positive integer. This allows
128/// the diagnostic to appear as many times as specified. Example:
129///
130/// \code
131/// void f(); // expected-note 2 {{previous declaration is here}}
132/// \endcode
133///
134/// Where the diagnostic is expected to occur a minimum number of times, this
135/// can be specified by appending a '+' to the number. Example:
136///
137/// \code
138/// void f(); // expected-note 0+ {{previous declaration is here}}
139/// void g(); // expected-note 1+ {{previous declaration is here}}
140/// \endcode
141///
142/// In the first example, the diagnostic becomes optional, i.e. it will be
143/// swallowed if it occurs, but will not generate an error if it does not
144/// occur. In the second example, the diagnostic must occur at least once.
145/// As a short-hand, "one or more" can be specified simply by '+'. Example:
146///
147/// \code
148/// void g(); // expected-note + {{previous declaration is here}}
149/// \endcode
150///
151/// A range can also be specified by "<n>-<m>". Example:
152///
153/// \code
154/// void f(); // expected-note 0-1 {{previous declaration is here}}
155/// \endcode
156///
157/// In this example, the diagnostic may appear only once, if at all.
158///
159/// Regex matching mode may be selected by appending '-re' to type and
160/// including regexes wrapped in double curly braces in the directive, such as:
161///
162/// \code
163/// expected-error-re {{format specifies type 'wchar_t **' (aka '{{.+}}')}}
164/// \endcode
165///
166/// Examples matching error: "variable has incomplete type 'struct s'"
167///
168/// \code
169/// // expected-error {{variable has incomplete type 'struct s'}}
170/// // expected-error {{variable has incomplete type}}
171///
172/// // expected-error-re {{variable has type 'struct {{.}}'}}
173/// // expected-error-re {{variable has type 'struct {{.*}}'}}
174/// // expected-error-re {{variable has type 'struct {{(.*)}}'}}
175/// // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}}
176/// \endcode
177///
178/// VerifyDiagnosticConsumer expects at least one expected-* directive to
179/// be found inside the source code. If no diagnostics are expected the
180/// following directive can be used to indicate this:
181///
182/// \code
183/// // expected-no-diagnostics
184/// \endcode
185///
187 public CommentHandler {
188public:
189 /// Directive - Abstract class representing a parsed verify directive.
190 ///
191 class Directive {
192 public:
193 static std::unique_ptr<Directive>
194 create(bool RegexKind, SourceLocation DirectiveLoc,
196 bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max);
197
198 public:
199 /// Constant representing n or more matches.
200 static const unsigned MaxCount = std::numeric_limits<unsigned>::max();
201
204 const std::string Text;
205 unsigned Min, Max;
207 bool MatchAnyFileAndLine; // `MatchAnyFileAndLine` implies `MatchAnyLine`.
208
209 Directive(const Directive &) = delete;
210 Directive &operator=(const Directive &) = delete;
211 virtual ~Directive() = default;
212
213 // Returns true if directive text is valid.
214 // Otherwise returns false and populates E.
215 virtual bool isValid(std::string &Error) = 0;
216
217 // Returns true on match.
218 virtual bool match(StringRef S) = 0;
219
220 protected:
222 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
223 unsigned Min, unsigned Max)
227 assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
228 assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) &&
229 "DiagnosticLoc is invalid!");
230 }
231 };
232
233 using DirectiveList = std::vector<std::unique_ptr<Directive>>;
234
235 /// ExpectedData - owns directive objects and deletes on destructor.
241
242 void Reset() {
243 Errors.clear();
244 Warnings.clear();
245 Remarks.clear();
246 Notes.clear();
247 }
248 };
249
255 };
256
257 class MarkerTracker;
258
259private:
260 DiagnosticsEngine &Diags;
261 DiagnosticConsumer *PrimaryClient;
262 std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner;
263 std::unique_ptr<TextDiagnosticBuffer> Buffer;
264 std::unique_ptr<MarkerTracker> Markers;
265 const Preprocessor *CurrentPreprocessor = nullptr;
266 const LangOptions *LangOpts = nullptr;
267 SourceManager *SrcManager = nullptr;
268 unsigned ActiveSourceFiles = 0;
269 DirectiveStatus Status;
270 ExpectedData ED;
271
272 void CheckDiagnostics();
273
274 void setSourceManager(SourceManager &SM) {
275 assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!");
276 SrcManager = &SM;
277 }
278
279 // These facilities are used for validation in debug builds.
280 class UnparsedFileStatus {
281 llvm::PointerIntPair<const FileEntry *, 1, bool> Data;
282
283 public:
284 UnparsedFileStatus(const FileEntry *File, bool FoundDirectives)
285 : Data(File, FoundDirectives) {}
286
287 const FileEntry *getFile() const { return Data.getPointer(); }
288 bool foundDirectives() const { return Data.getInt(); }
289 };
290
291 using ParsedFilesMap = llvm::DenseMap<FileID, const FileEntry *>;
292 using UnparsedFilesMap = llvm::DenseMap<FileID, UnparsedFileStatus>;
293
294 ParsedFilesMap ParsedFiles;
295 UnparsedFilesMap UnparsedFiles;
296
297public:
298 /// Create a new verifying diagnostic client, which will issue errors to
299 /// the currently-attached diagnostic client when a diagnostic does not match
300 /// what is expected (as indicated in the source file).
301 VerifyDiagnosticConsumer(DiagnosticsEngine &Diags);
302 ~VerifyDiagnosticConsumer() override;
303
304 void BeginSourceFile(const LangOptions &LangOpts,
305 const Preprocessor *PP) override;
306
307 void EndSourceFile() override;
308
310 /// File has been processed via HandleComment.
312
313 /// File has diagnostics and may have directives.
315
316 /// File has diagnostics but guaranteed no directives.
318 };
319
320 /// Update lists of parsed and unparsed files.
322
323 bool HandleComment(Preprocessor &PP, SourceRange Comment) override;
324
326 const Diagnostic &Info) override;
327};
328
329} // namespace clang
330
331#endif // LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
#define SM(sm)
Definition: Cuda.cpp:80
Defines the Diagnostic-related interfaces.
Defines the clang::FileManager interface and associated types.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
Defines the clang::Preprocessor interface.
Defines the clang::SourceLocation class and associated facilities.
const char * Data
VerifyDiagnosticConsumer::ExpectedData ExpectedData
Abstract base class that describes a handler that will receive source ranges for each of the comments...
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1740
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1566
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:195
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:82
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
Encodes a location in the source.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
Directive - Abstract class representing a parsed verify directive.
virtual bool isValid(std::string &Error)=0
static std::unique_ptr< Directive > create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
static const unsigned MaxCount
Constant representing n or more matches.
virtual bool match(StringRef S)=0
Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
Directive & operator=(const Directive &)=delete
VerifyDiagnosticConsumer - Create a diagnostic client which will use markers in the input source to c...
void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS)
Update lists of parsed and unparsed files.
VerifyDiagnosticConsumer(DiagnosticsEngine &Diags)
Create a new verifying diagnostic client, which will issue errors to the currently-attached diagnosti...
@ IsUnparsed
File has diagnostics and may have directives.
@ IsUnparsedNoDirectives
File has diagnostics but guaranteed no directives.
@ IsParsed
File has been processed via HandleComment.
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) override
Callback to inform the diagnostic client that processing of a source file is beginning.
std::vector< std::unique_ptr< Directive > > DirectiveList
bool HandleComment(Preprocessor &PP, SourceRange Comment) override
HandleComment - Hook into the preprocessor and extract comments containing expected errors and warnin...
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
ExpectedData - owns directive objects and deletes on destructor.