]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h
MFC r244628:
[FreeBSD/stable/9.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_VERIFYDIAGNOSTICSCLIENT_H
11 #define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICSCLIENT_H
12
13 #include "clang/Basic/Diagnostic.h"
14 #include "clang/Lex/Preprocessor.h"
15 #include "llvm/ADT/DenseMap.h"
16 #include "llvm/ADT/OwningPtr.h"
17 #include "llvm/ADT/PointerIntPair.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include <climits>
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,note}
38 /// \endcode
39 ///
40 /// to tag if it's an expected error or warning, and place the expected text
41 /// between {{ and }} markers. The full text doesn't have to be included, only
42 /// 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 /// The simple syntax above allows each specification to match exactly one
65 /// error.  You can use the extended syntax to customize this. The extended
66 /// syntax is "expected-<type> <n> {{diag text}}", where \<type> is one of
67 /// "error", "warning" or "note", and \<n> is a positive integer. This allows
68 /// the diagnostic to appear as many times as specified. Example:
69 ///
70 /// \code
71 ///   void f(); // expected-note 2 {{previous declaration is here}}
72 /// \endcode
73 ///
74 /// Where the diagnostic is expected to occur a minimum number of times, this
75 /// can be specified by appending a '+' to the number. Example:
76 ///
77 /// \code
78 ///   void f(); // expected-note 0+ {{previous declaration is here}}
79 ///   void g(); // expected-note 1+ {{previous declaration is here}}
80 /// \endcode
81 ///
82 /// In the first example, the diagnostic becomes optional, i.e. it will be
83 /// swallowed if it occurs, but will not generate an error if it does not
84 /// occur.  In the second example, the diagnostic must occur at least once.
85 /// As a short-hand, "one or more" can be specified simply by '+'. Example:
86 ///
87 /// \code
88 ///   void g(); // expected-note + {{previous declaration is here}}
89 /// \endcode
90 ///
91 /// A range can also be specified by "<n>-<m>".  Example:
92 ///
93 /// \code
94 ///   void f(); // expected-note 0-1 {{previous declaration is here}}
95 /// \endcode
96 ///
97 /// In this example, the diagnostic may appear only once, if at all.
98 ///
99 /// Regex matching mode may be selected by appending '-re' to type, such as:
100 ///
101 /// \code
102 ///   expected-error-re
103 /// \endcode
104 ///
105 /// Examples matching error: "variable has incomplete type 'struct s'"
106 ///
107 /// \code
108 ///   // expected-error {{variable has incomplete type 'struct s'}}
109 ///   // expected-error {{variable has incomplete type}}
110 ///
111 ///   // expected-error-re {{variable has has type 'struct .'}}
112 ///   // expected-error-re {{variable has has type 'struct .*'}}
113 ///   // expected-error-re {{variable has has type 'struct (.*)'}}
114 ///   // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}}
115 /// \endcode
116 ///
117 /// VerifyDiagnosticConsumer expects at least one expected-* directive to
118 /// be found inside the source code.  If no diagnostics are expected the
119 /// following directive can be used to indicate this:
120 ///
121 /// \code
122 ///   // expected-no-diagnostics
123 /// \endcode
124 ///
125 class VerifyDiagnosticConsumer: public DiagnosticConsumer,
126                                 public CommentHandler {
127 public:
128   /// Directive - Abstract class representing a parsed verify directive.
129   ///
130   class Directive {
131   public:
132     static Directive *create(bool RegexKind, SourceLocation DirectiveLoc,
133                              SourceLocation DiagnosticLoc,
134                              StringRef Text, unsigned Min, unsigned Max);
135   public:
136     /// Constant representing n or more matches.
137     static const unsigned MaxCount = UINT_MAX;
138
139     SourceLocation DirectiveLoc;
140     SourceLocation DiagnosticLoc;
141     const std::string Text;
142     unsigned Min, Max;
143
144     virtual ~Directive() { }
145
146     // Returns true if directive text is valid.
147     // Otherwise returns false and populates E.
148     virtual bool isValid(std::string &Error) = 0;
149
150     // Returns true on match.
151     virtual bool match(StringRef S) = 0;
152
153   protected:
154     Directive(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
155               StringRef Text, unsigned Min, unsigned Max)
156       : DirectiveLoc(DirectiveLoc), DiagnosticLoc(DiagnosticLoc),
157         Text(Text), Min(Min), Max(Max) {
158     assert(!DirectiveLoc.isInvalid() && "DirectiveLoc is invalid!");
159     assert(!DiagnosticLoc.isInvalid() && "DiagnosticLoc is invalid!");
160     }
161
162   private:
163     Directive(const Directive &) LLVM_DELETED_FUNCTION;
164     void operator=(const Directive &) LLVM_DELETED_FUNCTION;
165   };
166
167   typedef std::vector<Directive*> DirectiveList;
168
169   /// ExpectedData - owns directive objects and deletes on destructor.
170   ///
171   struct ExpectedData {
172     DirectiveList Errors;
173     DirectiveList Warnings;
174     DirectiveList Notes;
175
176     ~ExpectedData() {
177       llvm::DeleteContainerPointers(Errors);
178       llvm::DeleteContainerPointers(Warnings);
179       llvm::DeleteContainerPointers(Notes);
180     }
181   };
182
183   enum DirectiveStatus {
184     HasNoDirectives,
185     HasNoDirectivesReported,
186     HasExpectedNoDiagnostics,
187     HasOtherExpectedDirectives
188   };
189
190 private:
191   DiagnosticsEngine &Diags;
192   DiagnosticConsumer *PrimaryClient;
193   bool OwnsPrimaryClient;
194   OwningPtr<TextDiagnosticBuffer> Buffer;
195   const Preprocessor *CurrentPreprocessor;
196   const LangOptions *LangOpts;
197   SourceManager *SrcManager;
198   unsigned ActiveSourceFiles;
199   DirectiveStatus Status;
200   ExpectedData ED;
201
202   void CheckDiagnostics();
203   void setSourceManager(SourceManager &SM) {
204     assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!");
205     SrcManager = &SM;
206   }
207
208 #ifndef NDEBUG
209   class UnparsedFileStatus {
210     llvm::PointerIntPair<const FileEntry *, 1, bool> Data;
211
212   public:
213     UnparsedFileStatus(const FileEntry *File, bool FoundDirectives)
214       : Data(File, FoundDirectives) {}
215
216     const FileEntry *getFile() const { return Data.getPointer(); }
217     bool foundDirectives() const { return Data.getInt(); }
218   };
219
220   typedef llvm::DenseMap<FileID, const FileEntry *> ParsedFilesMap;
221   typedef llvm::DenseMap<FileID, UnparsedFileStatus> UnparsedFilesMap;
222
223   ParsedFilesMap ParsedFiles;
224   UnparsedFilesMap UnparsedFiles;
225 #endif
226
227 public:
228   /// Create a new verifying diagnostic client, which will issue errors to
229   /// the currently-attached diagnostic client when a diagnostic does not match 
230   /// what is expected (as indicated in the source file).
231   VerifyDiagnosticConsumer(DiagnosticsEngine &Diags);
232   ~VerifyDiagnosticConsumer();
233
234   virtual void BeginSourceFile(const LangOptions &LangOpts,
235                                const Preprocessor *PP);
236
237   virtual void EndSourceFile();
238
239   enum ParsedStatus {
240     /// File has been processed via HandleComment.
241     IsParsed,
242
243     /// File has diagnostics and may have directives.
244     IsUnparsed,
245
246     /// File has diagnostics but guaranteed no directives.
247     IsUnparsedNoDirectives
248   };
249
250   /// \brief Update lists of parsed and unparsed files.
251   void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS);
252
253   virtual bool HandleComment(Preprocessor &PP, SourceRange Comment);
254
255   virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
256                                 const Diagnostic &Info);
257   
258   virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const;
259 };
260
261 } // end namspace clang
262
263 #endif