clang  14.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 
12 #include "clang/Basic/Diagnostic.h"
14 #include "clang/Basic/LLVM.h"
16 #include "clang/Lex/Preprocessor.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 
26 namespace clang {
27 
28 class FileEntry;
29 class LangOptions;
30 class SourceManager;
31 class 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 {
188 public:
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 
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.
236  struct ExpectedData {
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 
259 private:
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 
297 public:
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
clang::DiagnosticsEngine::Level
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:194
max
__DEVICE__ int max(int __a, int __b)
Definition: __clang_cuda_math.h:196
clang::VerifyDiagnosticConsumer::ExpectedData::Remarks
DirectiveList Remarks
Definition: VerifyDiagnosticConsumer.h:239
clang::VerifyDiagnosticConsumer
VerifyDiagnosticConsumer - Create a diagnostic client which will use markers in the input source to c...
Definition: VerifyDiagnosticConsumer.h:186
clang::VerifyDiagnosticConsumer::ExpectedData
ExpectedData - owns directive objects and deletes on destructor.
Definition: VerifyDiagnosticConsumer.h:236
clang::SourceRange
A trivial tuple used to represent a source range.
Definition: SourceLocation.h:212
clang::VerifyDiagnosticConsumer::Directive::Text
const std::string Text
Definition: VerifyDiagnosticConsumer.h:204
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::VerifyDiagnosticConsumer::BeginSourceFile
void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) override
Callback to inform the diagnostic client that processing of a source file is beginning.
Definition: VerifyDiagnosticConsumer.cpp:679
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::VerifyDiagnosticConsumer::Directive::DirectiveLoc
SourceLocation DirectiveLoc
Definition: VerifyDiagnosticConsumer.h:202
clang::VerifyDiagnosticConsumer::Directive::DiagnosticLoc
SourceLocation DiagnosticLoc
Definition: VerifyDiagnosticConsumer.h:203
clang::VerifyDiagnosticConsumer::IsUnparsedNoDirectives
@ IsUnparsedNoDirectives
File has diagnostics but guaranteed no directives.
Definition: VerifyDiagnosticConsumer.h:317
clang::DiagnosticConsumer
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1722
clang::VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer
~VerifyDiagnosticConsumer() override
Definition: VerifyDiagnosticConsumer.cpp:668
clang::VerifyDiagnosticConsumer::Directive::isValid
virtual bool isValid(std::string &Error)=0
clang::DiagnosticsEngine
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:191
clang::VerifyDiagnosticConsumer::UpdateParsedFileStatus
void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS)
Update lists of parsed and unparsed files.
Definition: VerifyDiagnosticConsumer.cpp:1020
clang::VerifyDiagnosticConsumer::HandleDiagnostic
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.
Definition: VerifyDiagnosticConsumer.cpp:720
clang::VerifyDiagnosticConsumer::Directive::operator=
Directive & operator=(const Directive &)=delete
clang::CommentHandler
Abstract base class that describes a handler that will receive source ranges for each of the comments...
Definition: Preprocessor.h:2490
clang::SourceManager
This class handles loading and caching of source files into memory.
Definition: SourceManager.h:626
Preprocessor.h
clang::Diagnostic
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1547
clang::VerifyDiagnosticConsumer::EndSourceFile
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
Definition: VerifyDiagnosticConsumer.cpp:700
clang::VerifyDiagnosticConsumer::Directive::MaxCount
static const unsigned MaxCount
Constant representing n or more matches.
Definition: VerifyDiagnosticConsumer.h:200
clang::VerifyDiagnosticConsumer::HasOtherExpectedDirectives
@ HasOtherExpectedDirectives
Definition: VerifyDiagnosticConsumer.h:254
Diagnostic.h
clang::VerifyDiagnosticConsumer::Directive::match
virtual bool match(StringRef S)=0
clang::VerifyDiagnosticConsumer::ExpectedData::Warnings
DirectiveList Warnings
Definition: VerifyDiagnosticConsumer.h:238
clang::VerifyDiagnosticConsumer::Directive::Directive
Directive(const Directive &)=delete
clang::VerifyDiagnosticConsumer::Directive::Max
unsigned Max
Definition: VerifyDiagnosticConsumer.h:205
clang::VerifyDiagnosticConsumer::VerifyDiagnosticConsumer
VerifyDiagnosticConsumer(DiagnosticsEngine &Diags)
Create a new verifying diagnostic client, which will issue errors to the currently-attached diagnosti...
Definition: VerifyDiagnosticConsumer.cpp:659
clang::VerifyDiagnosticConsumer::HasNoDirectivesReported
@ HasNoDirectivesReported
Definition: VerifyDiagnosticConsumer.h:252
clang::VerifyDiagnosticConsumer::Directive::MatchAnyLine
bool MatchAnyLine
Definition: VerifyDiagnosticConsumer.h:206
SourceLocation.h
clang::VerifyDiagnosticConsumer::Directive::Min
unsigned Min
Definition: VerifyDiagnosticConsumer.h:205
clang::VerifyDiagnosticConsumer::IsParsed
@ IsParsed
File has been processed via HandleComment.
Definition: VerifyDiagnosticConsumer.h:311
clang::VerifyDiagnosticConsumer::DirectiveStatus
DirectiveStatus
Definition: VerifyDiagnosticConsumer.h:250
LLVM.h
clang::VerifyDiagnosticConsumer::Directive::~Directive
virtual ~Directive()=default
clang::LangOptions
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:58
clang::VerifyDiagnosticConsumer::HasNoDirectives
@ HasNoDirectives
Definition: VerifyDiagnosticConsumer.h:251
clang::VerifyDiagnosticConsumer::Directive::Directive
Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
Definition: VerifyDiagnosticConsumer.h:221
clang::VerifyDiagnosticConsumer::IsUnparsed
@ IsUnparsed
File has diagnostics and may have directives.
Definition: VerifyDiagnosticConsumer.h:314
clang::VerifyDiagnosticConsumer::ExpectedData::Errors
DirectiveList Errors
Definition: VerifyDiagnosticConsumer.h:237
clang::SourceLocation::isInvalid
bool isInvalid() const
Definition: SourceLocation.h:113
clang
Definition: CalledOnceCheck.h:17
clang::FileID
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Definition: SourceLocation.h:40
clang::VerifyDiagnosticConsumer::DirectiveList
std::vector< std::unique_ptr< Directive > > DirectiveList
Definition: VerifyDiagnosticConsumer.h:233
clang::VerifyDiagnosticConsumer::Directive
Directive - Abstract class representing a parsed verify directive.
Definition: VerifyDiagnosticConsumer.h:191
clang::VerifyDiagnosticConsumer::HasExpectedNoDiagnostics
@ HasExpectedNoDiagnostics
Definition: VerifyDiagnosticConsumer.h:253
FileManager.h
clang::VerifyDiagnosticConsumer::ExpectedData::Reset
void Reset()
Definition: VerifyDiagnosticConsumer.h:242
clang::VerifyDiagnosticConsumer::ParsedStatus
ParsedStatus
Definition: VerifyDiagnosticConsumer.h:309
clang::Preprocessor
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:130
SM
#define SM(sm)
Definition: Cuda.cpp:78
clang::VerifyDiagnosticConsumer::HandleComment
bool HandleComment(Preprocessor &PP, SourceRange Comment) override
HandleComment - Hook into the preprocessor and extract comments containing expected errors and warnin...
Definition: VerifyDiagnosticConsumer.cpp:762
clang::VerifyDiagnosticConsumer::Directive::create
static std::unique_ptr< Directive > create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
Definition: VerifyDiagnosticConsumer.cpp:1130
ExpectedData
VerifyDiagnosticConsumer::ExpectedData ExpectedData
Definition: VerifyDiagnosticConsumer.cpp:51
clang::VerifyDiagnosticConsumer::Directive::MatchAnyFileAndLine
bool MatchAnyFileAndLine
Definition: VerifyDiagnosticConsumer.h:207
clang::VerifyDiagnosticConsumer::ExpectedData::Notes
DirectiveList Notes
Definition: VerifyDiagnosticConsumer.h:240