blob: 4dc1bf33d6e6c47515d08cc13c4600640248791c [file] [log] [blame]
David Blaikie621bc692011-09-26 00:38:03 +00001//===---- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ------===//
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +00002//
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// This is a concrete diagnostic client, which buffers the diagnostic messages.
11//
12//===----------------------------------------------------------------------===//
13
David Blaikie621bc692011-09-26 00:38:03 +000014#include "clang/Frontend/VerifyDiagnosticConsumer.h"
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000015#include "clang/Frontend/FrontendDiagnostic.h"
16#include "clang/Frontend/TextDiagnosticBuffer.h"
17#include "clang/Lex/Preprocessor.h"
18#include "llvm/ADT/SmallString.h"
Chris Lattner60909e12010-04-28 20:02:30 +000019#include "llvm/Support/Regex.h"
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000020#include "llvm/Support/raw_ostream.h"
Anna Zaksc035e092011-12-15 02:58:00 +000021
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000022using namespace clang;
Jordan Rose4313c012012-07-10 02:56:15 +000023typedef VerifyDiagnosticConsumer::Directive Directive;
24typedef VerifyDiagnosticConsumer::DirectiveList DirectiveList;
25typedef VerifyDiagnosticConsumer::ExpectedData ExpectedData;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000026
David Blaikie621bc692011-09-26 00:38:03 +000027VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
Douglas Gregor78243652011-09-13 01:26:44 +000028 : Diags(_Diags), PrimaryClient(Diags.getClient()),
29 OwnsPrimaryClient(Diags.ownsClient()),
30 Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0)
31{
32 Diags.takeClient();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000033}
34
David Blaikie621bc692011-09-26 00:38:03 +000035VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
Douglas Gregor78243652011-09-13 01:26:44 +000036 CheckDiagnostics();
37 Diags.takeClient();
38 if (OwnsPrimaryClient)
39 delete PrimaryClient;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000040}
41
David Blaikie78ad0b92011-09-25 23:39:51 +000042// DiagnosticConsumer interface.
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000043
David Blaikie621bc692011-09-26 00:38:03 +000044void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
Douglas Gregor1f6b2b52012-01-20 16:28:04 +000045 const Preprocessor *PP) {
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000046 // FIXME: Const hack, we screw up the preprocessor but in practice its ok
47 // because it doesn't get reused. It would be better if we could make a copy
48 // though.
49 CurrentPreprocessor = const_cast<Preprocessor*>(PP);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000050
51 PrimaryClient->BeginSourceFile(LangOpts, PP);
52}
53
David Blaikie621bc692011-09-26 00:38:03 +000054void VerifyDiagnosticConsumer::EndSourceFile() {
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000055 CheckDiagnostics();
56
57 PrimaryClient->EndSourceFile();
58
59 CurrentPreprocessor = 0;
60}
Daniel Dunbar221c7212009-11-14 07:53:24 +000061
David Blaikie621bc692011-09-26 00:38:03 +000062void VerifyDiagnosticConsumer::HandleDiagnostic(
David Blaikie40847cf2011-09-26 01:18:08 +000063 DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
Axel Naumann01231612011-07-25 19:18:12 +000064 if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) {
65 const SourceManager &SM = Info.getSourceManager();
66 FirstErrorFID = SM.getFileID(Info.getLocation());
67 }
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000068 // Send the diagnostic to the buffer, we will check it once we reach the end
69 // of the source file (or are destructed).
70 Buffer->HandleDiagnostic(DiagLevel, Info);
71}
72
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000073//===----------------------------------------------------------------------===//
74// Checking diagnostics implementation.
75//===----------------------------------------------------------------------===//
76
77typedef TextDiagnosticBuffer::DiagList DiagList;
78typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
79
Chris Lattner60909e12010-04-28 20:02:30 +000080namespace {
81
Chris Lattner60909e12010-04-28 20:02:30 +000082/// StandardDirective - Directive with string matching.
83///
84class StandardDirective : public Directive {
85public:
Jordan Rose4313c012012-07-10 02:56:15 +000086 StandardDirective(const SourceLocation &Location, StringRef Text,
Chris Lattner60909e12010-04-28 20:02:30 +000087 unsigned Count)
88 : Directive(Location, Text, Count) { }
89
90 virtual bool isValid(std::string &Error) {
91 // all strings are considered valid; even empty ones
92 return true;
93 }
94
Jordan Rose4313c012012-07-10 02:56:15 +000095 virtual bool match(StringRef S) {
96 return S.find(Text) != StringRef::npos;
Chris Lattner60909e12010-04-28 20:02:30 +000097 }
98};
99
100/// RegexDirective - Directive with regular-expression matching.
101///
102class RegexDirective : public Directive {
103public:
Jordan Rose4313c012012-07-10 02:56:15 +0000104 RegexDirective(const SourceLocation &Location, StringRef Text,
Chris Lattner60909e12010-04-28 20:02:30 +0000105 unsigned Count)
106 : Directive(Location, Text, Count), Regex(Text) { }
107
108 virtual bool isValid(std::string &Error) {
109 if (Regex.isValid(Error))
110 return true;
111 return false;
112 }
113
Jordan Rose4313c012012-07-10 02:56:15 +0000114 virtual bool match(StringRef S) {
Chris Lattner60909e12010-04-28 20:02:30 +0000115 return Regex.match(S);
116 }
117
118private:
119 llvm::Regex Regex;
120};
121
Chris Lattner60909e12010-04-28 20:02:30 +0000122class ParseHelper
123{
124public:
125 ParseHelper(const char *Begin, const char *End)
126 : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
127
128 // Return true if string literal is next.
Chris Lattner5f9e2722011-07-23 10:55:15 +0000129 bool Next(StringRef S) {
Chris Lattner60909e12010-04-28 20:02:30 +0000130 P = C;
Benjamin Kramer0080f0c2010-09-01 17:28:48 +0000131 PEnd = C + S.size();
Chris Lattner60909e12010-04-28 20:02:30 +0000132 if (PEnd > End)
133 return false;
Benjamin Kramer0080f0c2010-09-01 17:28:48 +0000134 return !memcmp(P, S.data(), S.size());
Chris Lattner60909e12010-04-28 20:02:30 +0000135 }
136
137 // Return true if number is next.
138 // Output N only if number is next.
139 bool Next(unsigned &N) {
140 unsigned TMP = 0;
141 P = C;
142 for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) {
143 TMP *= 10;
144 TMP += P[0] - '0';
145 }
146 if (P == C)
147 return false;
148 PEnd = P;
149 N = TMP;
150 return true;
151 }
152
153 // Return true if string literal is found.
154 // When true, P marks begin-position of S in content.
Chris Lattner5f9e2722011-07-23 10:55:15 +0000155 bool Search(StringRef S) {
Chris Lattner60909e12010-04-28 20:02:30 +0000156 P = std::search(C, End, S.begin(), S.end());
Benjamin Kramer0080f0c2010-09-01 17:28:48 +0000157 PEnd = P + S.size();
Chris Lattner60909e12010-04-28 20:02:30 +0000158 return P != End;
159 }
160
161 // Advance 1-past previous next/search.
162 // Behavior is undefined if previous next/search failed.
163 bool Advance() {
164 C = PEnd;
165 return C < End;
166 }
167
168 // Skip zero or more whitespace.
169 void SkipWhitespace() {
170 for (; C < End && isspace(*C); ++C)
171 ;
172 }
173
174 // Return true if EOF reached.
175 bool Done() {
176 return !(C < End);
177 }
178
179 const char * const Begin; // beginning of expected content
180 const char * const End; // end of expected content (1-past)
181 const char *C; // position of next char in content
182 const char *P;
183
184private:
185 const char *PEnd; // previous next/search subject end (1-past)
186};
187
188} // namespace anonymous
189
190/// ParseDirective - Go through the comment and see if it indicates expected
191/// diagnostics. If so, then put them in the appropriate directive list.
192///
193static void ParseDirective(const char *CommentStart, unsigned CommentLen,
Jordan Rose4313c012012-07-10 02:56:15 +0000194 ExpectedData &ED, SourceManager &SM,
195 SourceLocation Pos, DiagnosticsEngine &Diags) {
Chris Lattner60909e12010-04-28 20:02:30 +0000196 // A single comment may contain multiple directives.
197 for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) {
198 // search for token: expected
199 if (!PH.Search("expected"))
200 break;
201 PH.Advance();
202
203 // next token: -
204 if (!PH.Next("-"))
205 continue;
206 PH.Advance();
207
208 // next token: { error | warning | note }
209 DirectiveList* DL = NULL;
210 if (PH.Next("error"))
211 DL = &ED.Errors;
212 else if (PH.Next("warning"))
213 DL = &ED.Warnings;
214 else if (PH.Next("note"))
215 DL = &ED.Notes;
216 else
217 continue;
218 PH.Advance();
219
220 // default directive kind
221 bool RegexKind = false;
222 const char* KindStr = "string";
223
224 // next optional token: -
225 if (PH.Next("-re")) {
226 PH.Advance();
227 RegexKind = true;
228 KindStr = "regex";
229 }
230
231 // skip optional whitespace
232 PH.SkipWhitespace();
233
Anna Zaks2135ebb2011-12-15 02:28:16 +0000234 // next optional token: positive integer or a '+'.
Chris Lattner60909e12010-04-28 20:02:30 +0000235 unsigned Count = 1;
236 if (PH.Next(Count))
237 PH.Advance();
Anna Zaks2135ebb2011-12-15 02:28:16 +0000238 else if (PH.Next("+")) {
239 Count = Directive::OneOrMoreCount;
240 PH.Advance();
241 }
Chris Lattner60909e12010-04-28 20:02:30 +0000242
243 // skip optional whitespace
244 PH.SkipWhitespace();
245
246 // next token: {{
247 if (!PH.Next("{{")) {
Jordan Rose4313c012012-07-10 02:56:15 +0000248 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
249 diag::err_verify_missing_start) << KindStr;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000250 continue;
251 }
Chris Lattner60909e12010-04-28 20:02:30 +0000252 PH.Advance();
253 const char* const ContentBegin = PH.C; // mark content begin
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000254
Chris Lattner60909e12010-04-28 20:02:30 +0000255 // search for token: }}
256 if (!PH.Search("}}")) {
Jordan Rose4313c012012-07-10 02:56:15 +0000257 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
258 diag::err_verify_missing_end) << KindStr;
Chris Lattner60909e12010-04-28 20:02:30 +0000259 continue;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000260 }
Chris Lattner60909e12010-04-28 20:02:30 +0000261 const char* const ContentEnd = PH.P; // mark content end
262 PH.Advance();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000263
Chris Lattner60909e12010-04-28 20:02:30 +0000264 // build directive text; convert \n to newlines
265 std::string Text;
Chris Lattner5f9e2722011-07-23 10:55:15 +0000266 StringRef NewlineStr = "\\n";
267 StringRef Content(ContentBegin, ContentEnd-ContentBegin);
Chris Lattner60909e12010-04-28 20:02:30 +0000268 size_t CPos = 0;
269 size_t FPos;
Chris Lattner5f9e2722011-07-23 10:55:15 +0000270 while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
Chris Lattner60909e12010-04-28 20:02:30 +0000271 Text += Content.substr(CPos, FPos-CPos);
272 Text += '\n';
273 CPos = FPos + NewlineStr.size();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000274 }
Chris Lattner60909e12010-04-28 20:02:30 +0000275 if (Text.empty())
276 Text.assign(ContentBegin, ContentEnd);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000277
Chris Lattner60909e12010-04-28 20:02:30 +0000278 // construct new directive
Jordan Rose4313c012012-07-10 02:56:15 +0000279 Directive *D = Directive::create(RegexKind, Pos, Text, Count);
Chris Lattner60909e12010-04-28 20:02:30 +0000280 std::string Error;
281 if (D->isValid(Error))
282 DL->push_back(D);
283 else {
Jordan Rose4313c012012-07-10 02:56:15 +0000284 Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
285 diag::err_verify_invalid_content)
Chris Lattner60909e12010-04-28 20:02:30 +0000286 << KindStr << Error;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000287 }
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000288 }
289}
290
291/// FindExpectedDiags - Lex the main source file to find all of the
292// expected errors and warnings.
Axel Naumann01231612011-07-25 19:18:12 +0000293static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) {
294 // Create a raw lexer to pull all the comments out of FID.
295 if (FID.isInvalid())
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000296 return;
297
Axel Naumann01231612011-07-25 19:18:12 +0000298 SourceManager& SM = PP.getSourceManager();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000299 // Create a lexer to lex all the tokens of the main file in raw mode.
Chris Lattner6e290142009-11-30 04:18:44 +0000300 const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
David Blaikie4e4d0842012-03-11 07:00:24 +0000301 Lexer RawLex(FID, FromFile, SM, PP.getLangOpts());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000302
303 // Return comments as tokens, this is how we find expected diagnostics.
304 RawLex.SetCommentRetentionState(true);
305
306 Token Tok;
307 Tok.setKind(tok::comment);
308 while (Tok.isNot(tok::eof)) {
309 RawLex.Lex(Tok);
310 if (!Tok.is(tok::comment)) continue;
311
312 std::string Comment = PP.getSpelling(Tok);
313 if (Comment.empty()) continue;
314
Chris Lattner60909e12010-04-28 20:02:30 +0000315 // Find all expected errors/warnings/notes.
Jordan Rose4313c012012-07-10 02:56:15 +0000316 ParseDirective(&Comment[0], Comment.size(), ED, SM, Tok.getLocation(),
317 PP.getDiagnostics());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000318 };
319}
320
321/// PrintProblem - This takes a diagnostic map of the delta between expected and
322/// seen diagnostics. If there's anything in it, then something unexpected
323/// happened. Print the map out in a nice format and return "true". If the map
324/// is empty and we're not going to print things, then return "false".
325///
David Blaikied6471f72011-09-25 23:23:43 +0000326static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000327 const_diag_iterator diag_begin,
328 const_diag_iterator diag_end,
329 const char *Kind, bool Expected) {
330 if (diag_begin == diag_end) return 0;
331
Dylan Noblesmithf7ccbad2012-02-05 02:13:05 +0000332 SmallString<256> Fmt;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000333 llvm::raw_svector_ostream OS(Fmt);
334 for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
Daniel Dunbar221c7212009-11-14 07:53:24 +0000335 if (I->first.isInvalid() || !SourceMgr)
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000336 OS << "\n (frontend)";
337 else
Chandler Carruth5ef04ee2011-02-23 00:47:48 +0000338 OS << "\n Line " << SourceMgr->getPresumedLineNumber(I->first);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000339 OS << ": " << I->second;
340 }
341
342 Diags.Report(diag::err_verify_inconsistent_diags)
Daniel Dunbar221c7212009-11-14 07:53:24 +0000343 << Kind << !Expected << OS.str();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000344 return std::distance(diag_begin, diag_end);
345}
346
David Blaikied6471f72011-09-25 23:23:43 +0000347static unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
Chris Lattner60909e12010-04-28 20:02:30 +0000348 DirectiveList &DL, const char *Kind,
349 bool Expected) {
350 if (DL.empty())
351 return 0;
352
Dylan Noblesmithf7ccbad2012-02-05 02:13:05 +0000353 SmallString<256> Fmt;
Chris Lattner60909e12010-04-28 20:02:30 +0000354 llvm::raw_svector_ostream OS(Fmt);
355 for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
356 Directive& D = **I;
357 if (D.Location.isInvalid() || !SourceMgr)
358 OS << "\n (frontend)";
359 else
Chandler Carruth5ef04ee2011-02-23 00:47:48 +0000360 OS << "\n Line " << SourceMgr->getPresumedLineNumber(D.Location);
Chris Lattner60909e12010-04-28 20:02:30 +0000361 OS << ": " << D.Text;
362 }
363
364 Diags.Report(diag::err_verify_inconsistent_diags)
365 << Kind << !Expected << OS.str();
366 return DL.size();
367}
368
369/// CheckLists - Compare expected to seen diagnostic lists and return the
370/// the difference between them.
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000371///
David Blaikied6471f72011-09-25 23:23:43 +0000372static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
Chris Lattner60909e12010-04-28 20:02:30 +0000373 const char *Label,
374 DirectiveList &Left,
375 const_diag_iterator d2_begin,
376 const_diag_iterator d2_end) {
377 DirectiveList LeftOnly;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000378 DiagList Right(d2_begin, d2_end);
379
Chris Lattner60909e12010-04-28 20:02:30 +0000380 for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
381 Directive& D = **I;
Chandler Carruth5ef04ee2011-02-23 00:47:48 +0000382 unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location);
Anna Zaks2135ebb2011-12-15 02:28:16 +0000383 bool FoundOnce = false;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000384
Chris Lattner60909e12010-04-28 20:02:30 +0000385 for (unsigned i = 0; i < D.Count; ++i) {
386 DiagList::iterator II, IE;
387 for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
Chandler Carruth5ef04ee2011-02-23 00:47:48 +0000388 unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
Chris Lattner60909e12010-04-28 20:02:30 +0000389 if (LineNo1 != LineNo2)
390 continue;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000391
Chris Lattner60909e12010-04-28 20:02:30 +0000392 const std::string &RightText = II->second;
Jordan Rose4313c012012-07-10 02:56:15 +0000393 if (D.match(RightText))
Chris Lattner60909e12010-04-28 20:02:30 +0000394 break;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000395 }
Chris Lattner60909e12010-04-28 20:02:30 +0000396 if (II == IE) {
Anna Zaks0e818a42011-12-16 18:28:45 +0000397 if (D.Count == D.OneOrMoreCount) {
398 if (!FoundOnce)
399 LeftOnly.push_back(*I);
400 // We are only interested in at least one match, so exit the loop.
Anna Zaks2135ebb2011-12-15 02:28:16 +0000401 break;
402 }
Chris Lattner60909e12010-04-28 20:02:30 +0000403 // Not found.
404 LeftOnly.push_back(*I);
405 } else {
406 // Found. The same cannot be found twice.
407 Right.erase(II);
Anna Zaks2135ebb2011-12-15 02:28:16 +0000408 FoundOnce = true;
Chris Lattner60909e12010-04-28 20:02:30 +0000409 }
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000410 }
411 }
412 // Now all that's left in Right are those that were not matched.
NAKAMURA Takumiad646842011-12-17 13:00:31 +0000413 unsigned num = PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true);
414 num += PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
415 Label, false);
416 return num;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000417}
418
419/// CheckResults - This compares the expected results to those that
420/// were actually reported. It emits any discrepencies. Return "true" if there
421/// were problems. Return "false" otherwise.
422///
David Blaikied6471f72011-09-25 23:23:43 +0000423static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000424 const TextDiagnosticBuffer &Buffer,
Chris Lattner60909e12010-04-28 20:02:30 +0000425 ExpectedData &ED) {
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000426 // We want to capture the delta between what was expected and what was
427 // seen.
428 //
429 // Expected \ Seen - set expected but not seen
430 // Seen \ Expected - set seen but not expected
431 unsigned NumProblems = 0;
432
433 // See if there are error mismatches.
Chris Lattner60909e12010-04-28 20:02:30 +0000434 NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
435 Buffer.err_begin(), Buffer.err_end());
Daniel Dunbar221c7212009-11-14 07:53:24 +0000436
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000437 // See if there are warning mismatches.
Chris Lattner60909e12010-04-28 20:02:30 +0000438 NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
439 Buffer.warn_begin(), Buffer.warn_end());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000440
441 // See if there are note mismatches.
Chris Lattner60909e12010-04-28 20:02:30 +0000442 NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
443 Buffer.note_begin(), Buffer.note_end());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000444
445 return NumProblems;
446}
447
David Blaikie621bc692011-09-26 00:38:03 +0000448void VerifyDiagnosticConsumer::CheckDiagnostics() {
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000449 // Ensure any diagnostics go to the primary client.
Douglas Gregor78243652011-09-13 01:26:44 +0000450 bool OwnsCurClient = Diags.ownsClient();
David Blaikie78ad0b92011-09-25 23:39:51 +0000451 DiagnosticConsumer *CurClient = Diags.takeClient();
Douglas Gregor78243652011-09-13 01:26:44 +0000452 Diags.setClient(PrimaryClient, false);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000453
454 // If we have a preprocessor, scan the source for expected diagnostic
455 // markers. If not then any diagnostics are unexpected.
456 if (CurrentPreprocessor) {
Axel Naumann01231612011-07-25 19:18:12 +0000457 SourceManager &SM = CurrentPreprocessor->getSourceManager();
458 // Extract expected-error strings from main file.
459 FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID());
460 // Only check for expectations in other diagnostic locations
461 // if they are not the main file (via ID or FileEntry) - the main
462 // file has already been looked at, and its expectations must not
463 // be added twice.
464 if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID()
465 && (!SM.getFileEntryForID(FirstErrorFID)
466 || (SM.getFileEntryForID(FirstErrorFID) !=
Axel Naumann84c05e32011-08-24 13:36:19 +0000467 SM.getFileEntryForID(SM.getMainFileID())))) {
Axel Naumann01231612011-07-25 19:18:12 +0000468 FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID);
Axel Naumann84c05e32011-08-24 13:36:19 +0000469 FirstErrorFID = FileID();
470 }
Daniel Dunbar221c7212009-11-14 07:53:24 +0000471
472 // Check that the expected diagnostics occurred.
Axel Naumann01231612011-07-25 19:18:12 +0000473 NumErrors += CheckResults(Diags, SM, *Buffer, ED);
Daniel Dunbar221c7212009-11-14 07:53:24 +0000474 } else {
475 NumErrors += (PrintProblem(Diags, 0,
476 Buffer->err_begin(), Buffer->err_end(),
477 "error", false) +
478 PrintProblem(Diags, 0,
479 Buffer->warn_begin(), Buffer->warn_end(),
480 "warn", false) +
481 PrintProblem(Diags, 0,
482 Buffer->note_begin(), Buffer->note_end(),
483 "note", false));
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000484 }
485
Douglas Gregorbdbb0042010-08-18 22:29:43 +0000486 Diags.takeClient();
Douglas Gregor78243652011-09-13 01:26:44 +0000487 Diags.setClient(CurClient, OwnsCurClient);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000488
489 // Reset the buffer, we have processed all the diagnostics in it.
490 Buffer.reset(new TextDiagnosticBuffer());
491}
Chris Lattner60909e12010-04-28 20:02:30 +0000492
Douglas Gregoraee526e2011-09-29 00:38:00 +0000493DiagnosticConsumer *
494VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const {
495 if (!Diags.getClient())
496 Diags.setClient(PrimaryClient->clone(Diags));
497
498 return new VerifyDiagnosticConsumer(Diags);
499}
500
Jordan Rose4313c012012-07-10 02:56:15 +0000501Directive *Directive::create(bool RegexKind, const SourceLocation &Location,
502 StringRef Text, unsigned Count) {
Chris Lattner60909e12010-04-28 20:02:30 +0000503 if (RegexKind)
504 return new RegexDirective(Location, Text, Count);
505 return new StandardDirective(Location, Text, Count);
506}