]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
MFV: r333378
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / include / clang / Frontend / VerifyDiagnosticConsumer.h
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 ///
141 class VerifyDiagnosticConsumer: public DiagnosticConsumer,
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,
149                                              SourceLocation DirectiveLoc,
150                                              SourceLocation DiagnosticLoc,
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
158     SourceLocation DirectiveLoc;
159     SourceLocation DiagnosticLoc;
160     const std::string Text;
161     unsigned Min, Max;
162     bool MatchAnyLine;
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
206   enum DirectiveStatus {
207     HasNoDirectives,
208     HasNoDirectivesReported,
209     HasExpectedNoDiagnostics,
210     HasOtherExpectedDirectives
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).
249   VerifyDiagnosticConsumer(DiagnosticsEngine &Diags);
250   ~VerifyDiagnosticConsumer() override;
251
252   void BeginSourceFile(const LangOptions &LangOpts,
253                        const Preprocessor *PP) override;
254
255   void EndSourceFile() override;
256
257   enum ParsedStatus {
258     /// File has been processed via HandleComment.
259     IsParsed,
260
261     /// File has diagnostics and may have directives.
262     IsUnparsed,
263
264     /// File has diagnostics but guaranteed no directives.
265     IsUnparsedNoDirectives
266   };
267
268   /// \brief Update lists of parsed and unparsed files.
269   void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS);
270
271   bool HandleComment(Preprocessor &PP, SourceRange Comment) override;
272
273   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
274                         const Diagnostic &Info) override;
275 };
276
277 } // end namspace clang
278
279 #endif