clang  11.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 
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:
221  Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
222  bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
223  unsigned Min, unsigned Max)
224  : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc), Text(Text),
225  Min(Min), Max(Max), MatchAnyLine(MatchAnyLine || MatchAnyFileAndLine),
226  MatchAnyFileAndLine(MatchAnyFileAndLine) {
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).
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
std::vector< std::unique_ptr< Directive > > DirectiveList
VerifyDiagnosticConsumer - Create a diagnostic client which will use markers in the input source to c...
Defines the clang::FileManager interface and associated types.
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...
File has been processed via HandleComment.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1526
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
ExpectedData - owns directive objects and deletes on destructor.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:54
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:153
Defines the Diagnostic-related interfaces.
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.
File has diagnostics but guaranteed no directives.
Defines the clang::Preprocessor interface.
#define SM(sm)
Definition: Cuda.cpp:62
bool HandleComment(Preprocessor &PP, SourceRange Comment) override
HandleComment - Hook into the preprocessor and extract comments containing expected errors and warnin...
Directive & operator=(const Directive &)=delete
Encodes a location in the source.
Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
Cached information about one file (either on disk or in the virtual file system). ...
Definition: FileManager.h:79
virtual bool match(StringRef S)=0
File has diagnostics and may have directives.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
virtual bool isValid(std::string &Error)=0
Dataflow Directional Tag Classes.
static std::unique_ptr< Directive > create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
__DEVICE__ int max(int __a, int __b)
Defines the clang::SourceLocation class and associated facilities.
static const unsigned MaxCount
Constant representing n or more matches.
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:156
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1354
Abstract base class that describes a handler that will receive source ranges for each of the comments...
A trivial tuple used to represent a source range.
Directive - Abstract class representing a parsed verify directive.
This class handles loading and caching of source files into memory.
void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) override
Callback to inform the diagnostic client that processing of a source file is beginning.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128