1 //===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICSCLIENT_H
11 #define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICSCLIENT_H
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"
23 class DiagnosticsEngine;
24 class TextDiagnosticBuffer;
27 /// VerifyDiagnosticConsumer - Create a diagnostic client which will use
28 /// markers in the input source to check that all the emitted diagnostics match
31 /// USING THE DIAGNOSTIC CHECKER:
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:
37 /// expected-{error,warning,note}
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.
44 /// Here's an example:
47 /// int A = B; // expected-error {{use of undeclared identifier 'B'}}
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.
53 /// Alternatively, it is possible to specify the line on which the diagnostic
54 /// should appear by appending "@<line>" to "expected-<type>", for example:
57 /// #warning some text
58 /// // expected-warning@10 {{some text}}
61 /// The line number may be absolute (as above), or relative to the current
62 /// line by prefixing the number with either '+' or '-'.
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:
71 /// void f(); // expected-note 2 {{previous declaration is here}}
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:
78 /// void f(); // expected-note 0+ {{previous declaration is here}}
79 /// void g(); // expected-note 1+ {{previous declaration is here}}
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:
88 /// void g(); // expected-note + {{previous declaration is here}}
91 /// A range can also be specified by "<n>-<m>". Example:
94 /// void f(); // expected-note 0-1 {{previous declaration is here}}
97 /// In this example, the diagnostic may appear only once, if at all.
99 /// Regex matching mode may be selected by appending '-re' to type, such as:
102 /// expected-error-re
105 /// Examples matching error: "variable has incomplete type 'struct s'"
108 /// // expected-error {{variable has incomplete type 'struct s'}}
109 /// // expected-error {{variable has incomplete type}}
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:]](.*)'}}
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:
122 /// // expected-no-diagnostics
125 class VerifyDiagnosticConsumer: public DiagnosticConsumer,
126 public CommentHandler {
128 /// Directive - Abstract class representing a parsed verify directive.
132 static Directive *create(bool RegexKind, SourceLocation DirectiveLoc,
133 SourceLocation DiagnosticLoc,
134 StringRef Text, unsigned Min, unsigned Max);
136 /// Constant representing n or more matches.
137 static const unsigned MaxCount = UINT_MAX;
139 SourceLocation DirectiveLoc;
140 SourceLocation DiagnosticLoc;
141 const std::string Text;
144 virtual ~Directive() { }
146 // Returns true if directive text is valid.
147 // Otherwise returns false and populates E.
148 virtual bool isValid(std::string &Error) = 0;
150 // Returns true on match.
151 virtual bool match(StringRef S) = 0;
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!");
163 Directive(const Directive &) LLVM_DELETED_FUNCTION;
164 void operator=(const Directive &) LLVM_DELETED_FUNCTION;
167 typedef std::vector<Directive*> DirectiveList;
169 /// ExpectedData - owns directive objects and deletes on destructor.
171 struct ExpectedData {
172 DirectiveList Errors;
173 DirectiveList Warnings;
177 llvm::DeleteContainerPointers(Errors);
178 llvm::DeleteContainerPointers(Warnings);
179 llvm::DeleteContainerPointers(Notes);
183 enum DirectiveStatus {
185 HasNoDirectivesReported,
186 HasExpectedNoDiagnostics,
187 HasOtherExpectedDirectives
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;
202 void CheckDiagnostics();
203 void setSourceManager(SourceManager &SM) {
204 assert((!SrcManager || SrcManager == &SM) && "SourceManager changed!");
209 class UnparsedFileStatus {
210 llvm::PointerIntPair<const FileEntry *, 1, bool> Data;
213 UnparsedFileStatus(const FileEntry *File, bool FoundDirectives)
214 : Data(File, FoundDirectives) {}
216 const FileEntry *getFile() const { return Data.getPointer(); }
217 bool foundDirectives() const { return Data.getInt(); }
220 typedef llvm::DenseMap<FileID, const FileEntry *> ParsedFilesMap;
221 typedef llvm::DenseMap<FileID, UnparsedFileStatus> UnparsedFilesMap;
223 ParsedFilesMap ParsedFiles;
224 UnparsedFilesMap UnparsedFiles;
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();
234 virtual void BeginSourceFile(const LangOptions &LangOpts,
235 const Preprocessor *PP);
237 virtual void EndSourceFile();
240 /// File has been processed via HandleComment.
243 /// File has diagnostics and may have directives.
246 /// File has diagnostics but guaranteed no directives.
247 IsUnparsedNoDirectives
250 /// \brief Update lists of parsed and unparsed files.
251 void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS);
253 virtual bool HandleComment(Preprocessor &PP, SourceRange Comment);
255 virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
256 const Diagnostic &Info);
258 virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const;
261 } // end namspace clang