clang  7.0.0svn
VerifyDiagnosticConsumer.h
Go to the documentation of this file.
1 //===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
11 #define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICCONSUMER_H
12 
13 #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 /// USING THE DIAGNOSTIC CHECKER:
38 ///
39 /// Indicating that a line expects an error or a warning is simple. Put a
40 /// comment on the line that has the diagnostic, use:
41 ///
42 /// \code
43 /// expected-{error,warning,remark,note}
44 /// \endcode
45 ///
46 /// to tag if it's an expected error, remark or warning, and place the expected
47 /// text between {{ and }} markers. The full text doesn't have to be included,
48 /// only enough to ensure that the correct diagnostic was emitted.
49 ///
50 /// Here's an example:
51 ///
52 /// \code
53 /// int A = B; // expected-error {{use of undeclared identifier 'B'}}
54 /// \endcode
55 ///
56 /// You can place as many diagnostics on one line as you wish. To make the code
57 /// more readable, you can use slash-newline to separate out the diagnostics.
58 ///
59 /// Alternatively, it is possible to specify the line on which the diagnostic
60 /// should appear by appending "@<line>" to "expected-<type>", for example:
61 ///
62 /// \code
63 /// #warning some text
64 /// // expected-warning@10 {{some text}}
65 /// \endcode
66 ///
67 /// The line number may be absolute (as above), or relative to the current
68 /// line by prefixing the number with either '+' or '-'.
69 ///
70 /// If the diagnostic is generated in a separate file, for example in a shared
71 /// header file, it may be beneficial to be able to declare the file in which
72 /// the diagnostic will appear, rather than placing the expected-* directive in
73 /// the actual file itself. This can be done using the following syntax:
74 ///
75 /// \code
76 /// // expected-error@path/include.h:15 {{error message}}
77 /// \endcode
78 ///
79 /// The path can be absolute or relative and the same search paths will be used
80 /// as for #include directives. The line number in an external file may be
81 /// substituted with '*' meaning that any line number will match (useful where
82 /// the included file is, for example, a system header where the actual line
83 /// number may change and is not critical).
84 ///
85 /// The simple syntax above allows each specification to match exactly one
86 /// error. You can use the extended syntax to customize this. The extended
87 /// syntax is "expected-<type> <n> {{diag text}}", where <type> is one of
88 /// "error", "warning" or "note", and <n> is a positive integer. This allows
89 /// the diagnostic to appear as many times as specified. Example:
90 ///
91 /// \code
92 /// void f(); // expected-note 2 {{previous declaration is here}}
93 /// \endcode
94 ///
95 /// Where the diagnostic is expected to occur a minimum number of times, this
96 /// can be specified by appending a '+' to the number. Example:
97 ///
98 /// \code
99 /// void f(); // expected-note 0+ {{previous declaration is here}}
100 /// void g(); // expected-note 1+ {{previous declaration is here}}
101 /// \endcode
102 ///
103 /// In the first example, the diagnostic becomes optional, i.e. it will be
104 /// swallowed if it occurs, but will not generate an error if it does not
105 /// occur. In the second example, the diagnostic must occur at least once.
106 /// As a short-hand, "one or more" can be specified simply by '+'. Example:
107 ///
108 /// \code
109 /// void g(); // expected-note + {{previous declaration is here}}
110 /// \endcode
111 ///
112 /// A range can also be specified by "<n>-<m>". Example:
113 ///
114 /// \code
115 /// void f(); // expected-note 0-1 {{previous declaration is here}}
116 /// \endcode
117 ///
118 /// In this example, the diagnostic may appear only once, if at all.
119 ///
120 /// Regex matching mode may be selected by appending '-re' to type and
121 /// including regexes wrapped in double curly braces in the directive, such as:
122 ///
123 /// \code
124 /// expected-error-re {{format specifies type 'wchar_t **' (aka '{{.+}}')}}
125 /// \endcode
126 ///
127 /// Examples matching error: "variable has incomplete type 'struct s'"
128 ///
129 /// \code
130 /// // expected-error {{variable has incomplete type 'struct s'}}
131 /// // expected-error {{variable has incomplete type}}
132 ///
133 /// // expected-error-re {{variable has type 'struct {{.}}'}}
134 /// // expected-error-re {{variable has type 'struct {{.*}}'}}
135 /// // expected-error-re {{variable has type 'struct {{(.*)}}'}}
136 /// // expected-error-re {{variable has type 'struct{{[[:space:]](.*)}}'}}
137 /// \endcode
138 ///
139 /// VerifyDiagnosticConsumer expects at least one expected-* directive to
140 /// be found inside the source code. If no diagnostics are expected the
141 /// following directive can be used to indicate this:
142 ///
143 /// \code
144 /// // expected-no-diagnostics
145 /// \endcode
146 ///
148  public CommentHandler {
149 public:
150  /// Directive - Abstract class representing a parsed verify directive.
151  ///
152  class Directive {
153  public:
154  static std::unique_ptr<Directive> create(bool RegexKind,
157  bool MatchAnyLine, StringRef Text,
158  unsigned Min, unsigned Max);
159 
160  public:
161  /// Constant representing n or more matches.
162  static const unsigned MaxCount = std::numeric_limits<unsigned>::max();
163 
166  const std::string Text;
167  unsigned Min, Max;
169 
170  Directive(const Directive &) = delete;
171  Directive &operator=(const Directive &) = delete;
172  virtual ~Directive() = default;
173 
174  // Returns true if directive text is valid.
175  // Otherwise returns false and populates E.
176  virtual bool isValid(std::string &Error) = 0;
177 
178  // Returns true on match.
179  virtual bool match(StringRef S) = 0;
180 
181  protected:
182  Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
183  bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
184  : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
185  Text(Text), Min(Min), Max(Max), MatchAnyLine(MatchAnyLine) {
186  assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
187  assert((!DiagnosticLoc.isInvalid() || MatchAnyLine) &&
188  "DiagnosticLoc is invalid!");
189  }
190  };
191 
192  using DirectiveList = std::vector<std::unique_ptr<Directive>>;
193 
194  /// ExpectedData - owns directive objects and deletes on destructor.
195  struct ExpectedData {
200 
201  void Reset() {
202  Errors.clear();
203  Warnings.clear();
204  Remarks.clear();
205  Notes.clear();
206  }
207  };
208 
214  };
215 
216 private:
217  DiagnosticsEngine &Diags;
218  DiagnosticConsumer *PrimaryClient;
219  std::unique_ptr<DiagnosticConsumer> PrimaryClientOwner;
220  std::unique_ptr<TextDiagnosticBuffer> Buffer;
221  const Preprocessor *CurrentPreprocessor = nullptr;
222  const LangOptions *LangOpts = nullptr;
223  SourceManager *SrcManager = nullptr;
224  unsigned ActiveSourceFiles = 0;
225  DirectiveStatus Status;
226  ExpectedData ED;
227 
228  void CheckDiagnostics();
229 
230  void setSourceManager(SourceManager &SM) {
231  assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!");
232  SrcManager = &SM;
233  }
234 
235  // These facilities are used for validation in debug builds.
236  class UnparsedFileStatus {
237  llvm::PointerIntPair<const FileEntry *, 1, bool> Data;
238 
239  public:
240  UnparsedFileStatus(const FileEntry *File, bool FoundDirectives)
241  : Data(File, FoundDirectives) {}
242 
243  const FileEntry *getFile() const { return Data.getPointer(); }
244  bool foundDirectives() const { return Data.getInt(); }
245  };
246 
247  using ParsedFilesMap = llvm::DenseMap<FileID, const FileEntry *>;
248  using UnparsedFilesMap = llvm::DenseMap<FileID, UnparsedFileStatus>;
249 
250  ParsedFilesMap ParsedFiles;
251  UnparsedFilesMap UnparsedFiles;
252 
253 public:
254  /// Create a new verifying diagnostic client, which will issue errors to
255  /// the currently-attached diagnostic client when a diagnostic does not match
256  /// what is expected (as indicated in the source file).
258  ~VerifyDiagnosticConsumer() override;
259 
260  void BeginSourceFile(const LangOptions &LangOpts,
261  const Preprocessor *PP) override;
262 
263  void EndSourceFile() override;
264 
266  /// File has been processed via HandleComment.
268 
269  /// File has diagnostics and may have directives.
271 
272  /// File has diagnostics but guaranteed no directives.
274  };
275 
276  /// Update lists of parsed and unparsed files.
278 
279  bool HandleComment(Preprocessor &PP, SourceRange Comment) override;
280 
282  const Diagnostic &Info) override;
283 };
284 
285 } // namespace clang
286 
287 #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:1487
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:50
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:1468
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:59
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:1315
__DEVICE__ int max(int __a, int __b)
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:127