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