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