blob: fce7973d56a196c5dd931a633dcb6085a232ff7c [file] [log] [blame]
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +00001//===--- VerifyDiagnosticsClient.cpp - Verifying Diagnostic Client --------===//
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// This is a concrete diagnostic client, which buffers the diagnostic messages.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Frontend/VerifyDiagnosticsClient.h"
15#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"
21using namespace clang;
22
Daniel Dunbar221c7212009-11-14 07:53:24 +000023VerifyDiagnosticsClient::VerifyDiagnosticsClient(Diagnostic &_Diags,
24 DiagnosticClient *_Primary)
25 : Diags(_Diags), PrimaryClient(_Primary),
Argyrios Kyrtzidisab41b972010-11-18 21:13:57 +000026 Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) {
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000027}
28
29VerifyDiagnosticsClient::~VerifyDiagnosticsClient() {
30 CheckDiagnostics();
31}
32
33// DiagnosticClient interface.
34
35void VerifyDiagnosticsClient::BeginSourceFile(const LangOptions &LangOpts,
36 const Preprocessor *PP) {
37 // FIXME: Const hack, we screw up the preprocessor but in practice its ok
38 // because it doesn't get reused. It would be better if we could make a copy
39 // though.
40 CurrentPreprocessor = const_cast<Preprocessor*>(PP);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000041
42 PrimaryClient->BeginSourceFile(LangOpts, PP);
43}
44
45void VerifyDiagnosticsClient::EndSourceFile() {
46 CheckDiagnostics();
47
48 PrimaryClient->EndSourceFile();
49
50 CurrentPreprocessor = 0;
51}
Daniel Dunbar221c7212009-11-14 07:53:24 +000052
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000053void VerifyDiagnosticsClient::HandleDiagnostic(Diagnostic::Level DiagLevel,
54 const DiagnosticInfo &Info) {
Axel Naumann01231612011-07-25 19:18:12 +000055 if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) {
56 const SourceManager &SM = Info.getSourceManager();
57 FirstErrorFID = SM.getFileID(Info.getLocation());
58 }
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000059 // Send the diagnostic to the buffer, we will check it once we reach the end
60 // of the source file (or are destructed).
61 Buffer->HandleDiagnostic(DiagLevel, Info);
62}
63
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000064//===----------------------------------------------------------------------===//
65// Checking diagnostics implementation.
66//===----------------------------------------------------------------------===//
67
68typedef TextDiagnosticBuffer::DiagList DiagList;
69typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
70
Chris Lattner60909e12010-04-28 20:02:30 +000071namespace {
72
73/// Directive - Abstract class representing a parsed verify directive.
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000074///
Chris Lattner60909e12010-04-28 20:02:30 +000075class Directive {
76public:
77 static Directive* Create(bool RegexKind, const SourceLocation &Location,
78 const std::string &Text, unsigned Count);
79public:
80 SourceLocation Location;
81 const std::string Text;
82 unsigned Count;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000083
Chris Lattner60909e12010-04-28 20:02:30 +000084 virtual ~Directive() { }
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +000085
Chris Lattner60909e12010-04-28 20:02:30 +000086 // Returns true if directive text is valid.
87 // Otherwise returns false and populates E.
88 virtual bool isValid(std::string &Error) = 0;
89
90 // Returns true on match.
91 virtual bool Match(const std::string &S) = 0;
92
93protected:
94 Directive(const SourceLocation &Location, const std::string &Text,
95 unsigned Count)
96 : Location(Location), Text(Text), Count(Count) { }
97
98private:
Argyrios Kyrtzidisc83d2d72010-08-15 10:17:39 +000099 Directive(const Directive&); // DO NOT IMPLEMENT
100 void operator=(const Directive&); // DO NOT IMPLEMENT
Chris Lattner60909e12010-04-28 20:02:30 +0000101};
102
103/// StandardDirective - Directive with string matching.
104///
105class StandardDirective : public Directive {
106public:
107 StandardDirective(const SourceLocation &Location, const std::string &Text,
108 unsigned Count)
109 : Directive(Location, Text, Count) { }
110
111 virtual bool isValid(std::string &Error) {
112 // all strings are considered valid; even empty ones
113 return true;
114 }
115
116 virtual bool Match(const std::string &S) {
117 return S.find(Text) != std::string::npos ||
118 Text.find(S) != std::string::npos;
119 }
120};
121
122/// RegexDirective - Directive with regular-expression matching.
123///
124class RegexDirective : public Directive {
125public:
126 RegexDirective(const SourceLocation &Location, const std::string &Text,
127 unsigned Count)
128 : Directive(Location, Text, Count), Regex(Text) { }
129
130 virtual bool isValid(std::string &Error) {
131 if (Regex.isValid(Error))
132 return true;
133 return false;
134 }
135
136 virtual bool Match(const std::string &S) {
137 return Regex.match(S);
138 }
139
140private:
141 llvm::Regex Regex;
142};
143
144typedef std::vector<Directive*> DirectiveList;
145
146/// ExpectedData - owns directive objects and deletes on destructor.
147///
148struct ExpectedData {
149 DirectiveList Errors;
150 DirectiveList Warnings;
151 DirectiveList Notes;
152
153 ~ExpectedData() {
154 DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 };
155 for (DirectiveList **PL = Lists; *PL; ++PL) {
156 DirectiveList * const L = *PL;
157 for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I)
158 delete *I;
159 }
160 }
161};
162
163class ParseHelper
164{
165public:
166 ParseHelper(const char *Begin, const char *End)
167 : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { }
168
169 // Return true if string literal is next.
Chris Lattner5f9e2722011-07-23 10:55:15 +0000170 bool Next(StringRef S) {
Chris Lattner60909e12010-04-28 20:02:30 +0000171 P = C;
Benjamin Kramer0080f0c2010-09-01 17:28:48 +0000172 PEnd = C + S.size();
Chris Lattner60909e12010-04-28 20:02:30 +0000173 if (PEnd > End)
174 return false;
Benjamin Kramer0080f0c2010-09-01 17:28:48 +0000175 return !memcmp(P, S.data(), S.size());
Chris Lattner60909e12010-04-28 20:02:30 +0000176 }
177
178 // Return true if number is next.
179 // Output N only if number is next.
180 bool Next(unsigned &N) {
181 unsigned TMP = 0;
182 P = C;
183 for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) {
184 TMP *= 10;
185 TMP += P[0] - '0';
186 }
187 if (P == C)
188 return false;
189 PEnd = P;
190 N = TMP;
191 return true;
192 }
193
194 // Return true if string literal is found.
195 // When true, P marks begin-position of S in content.
Chris Lattner5f9e2722011-07-23 10:55:15 +0000196 bool Search(StringRef S) {
Chris Lattner60909e12010-04-28 20:02:30 +0000197 P = std::search(C, End, S.begin(), S.end());
Benjamin Kramer0080f0c2010-09-01 17:28:48 +0000198 PEnd = P + S.size();
Chris Lattner60909e12010-04-28 20:02:30 +0000199 return P != End;
200 }
201
202 // Advance 1-past previous next/search.
203 // Behavior is undefined if previous next/search failed.
204 bool Advance() {
205 C = PEnd;
206 return C < End;
207 }
208
209 // Skip zero or more whitespace.
210 void SkipWhitespace() {
211 for (; C < End && isspace(*C); ++C)
212 ;
213 }
214
215 // Return true if EOF reached.
216 bool Done() {
217 return !(C < End);
218 }
219
220 const char * const Begin; // beginning of expected content
221 const char * const End; // end of expected content (1-past)
222 const char *C; // position of next char in content
223 const char *P;
224
225private:
226 const char *PEnd; // previous next/search subject end (1-past)
227};
228
229} // namespace anonymous
230
231/// ParseDirective - Go through the comment and see if it indicates expected
232/// diagnostics. If so, then put them in the appropriate directive list.
233///
234static void ParseDirective(const char *CommentStart, unsigned CommentLen,
235 ExpectedData &ED, Preprocessor &PP,
236 SourceLocation Pos) {
237 // A single comment may contain multiple directives.
238 for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) {
239 // search for token: expected
240 if (!PH.Search("expected"))
241 break;
242 PH.Advance();
243
244 // next token: -
245 if (!PH.Next("-"))
246 continue;
247 PH.Advance();
248
249 // next token: { error | warning | note }
250 DirectiveList* DL = NULL;
251 if (PH.Next("error"))
252 DL = &ED.Errors;
253 else if (PH.Next("warning"))
254 DL = &ED.Warnings;
255 else if (PH.Next("note"))
256 DL = &ED.Notes;
257 else
258 continue;
259 PH.Advance();
260
261 // default directive kind
262 bool RegexKind = false;
263 const char* KindStr = "string";
264
265 // next optional token: -
266 if (PH.Next("-re")) {
267 PH.Advance();
268 RegexKind = true;
269 KindStr = "regex";
270 }
271
272 // skip optional whitespace
273 PH.SkipWhitespace();
274
275 // next optional token: positive integer
276 unsigned Count = 1;
277 if (PH.Next(Count))
278 PH.Advance();
279
280 // skip optional whitespace
281 PH.SkipWhitespace();
282
283 // next token: {{
284 if (!PH.Next("{{")) {
285 PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
286 diag::err_verify_missing_start) << KindStr;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000287 continue;
288 }
Chris Lattner60909e12010-04-28 20:02:30 +0000289 PH.Advance();
290 const char* const ContentBegin = PH.C; // mark content begin
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000291
Chris Lattner60909e12010-04-28 20:02:30 +0000292 // search for token: }}
293 if (!PH.Search("}}")) {
294 PP.Diag(Pos.getFileLocWithOffset(PH.C-PH.Begin),
295 diag::err_verify_missing_end) << KindStr;
296 continue;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000297 }
Chris Lattner60909e12010-04-28 20:02:30 +0000298 const char* const ContentEnd = PH.P; // mark content end
299 PH.Advance();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000300
Chris Lattner60909e12010-04-28 20:02:30 +0000301 // build directive text; convert \n to newlines
302 std::string Text;
Chris Lattner5f9e2722011-07-23 10:55:15 +0000303 StringRef NewlineStr = "\\n";
304 StringRef Content(ContentBegin, ContentEnd-ContentBegin);
Chris Lattner60909e12010-04-28 20:02:30 +0000305 size_t CPos = 0;
306 size_t FPos;
Chris Lattner5f9e2722011-07-23 10:55:15 +0000307 while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
Chris Lattner60909e12010-04-28 20:02:30 +0000308 Text += Content.substr(CPos, FPos-CPos);
309 Text += '\n';
310 CPos = FPos + NewlineStr.size();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000311 }
Chris Lattner60909e12010-04-28 20:02:30 +0000312 if (Text.empty())
313 Text.assign(ContentBegin, ContentEnd);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000314
Chris Lattner60909e12010-04-28 20:02:30 +0000315 // construct new directive
316 Directive *D = Directive::Create(RegexKind, Pos, Text, Count);
317 std::string Error;
318 if (D->isValid(Error))
319 DL->push_back(D);
320 else {
321 PP.Diag(Pos.getFileLocWithOffset(ContentBegin-PH.Begin),
322 diag::err_verify_invalid_content)
323 << KindStr << Error;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000324 }
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000325 }
326}
327
328/// FindExpectedDiags - Lex the main source file to find all of the
329// expected errors and warnings.
Axel Naumann01231612011-07-25 19:18:12 +0000330static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) {
331 // Create a raw lexer to pull all the comments out of FID.
332 if (FID.isInvalid())
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000333 return;
334
Axel Naumann01231612011-07-25 19:18:12 +0000335 SourceManager& SM = PP.getSourceManager();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000336 // Create a lexer to lex all the tokens of the main file in raw mode.
Chris Lattner6e290142009-11-30 04:18:44 +0000337 const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
338 Lexer RawLex(FID, FromFile, SM, PP.getLangOptions());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000339
340 // Return comments as tokens, this is how we find expected diagnostics.
341 RawLex.SetCommentRetentionState(true);
342
343 Token Tok;
344 Tok.setKind(tok::comment);
345 while (Tok.isNot(tok::eof)) {
346 RawLex.Lex(Tok);
347 if (!Tok.is(tok::comment)) continue;
348
349 std::string Comment = PP.getSpelling(Tok);
350 if (Comment.empty()) continue;
351
Chris Lattner60909e12010-04-28 20:02:30 +0000352 // Find all expected errors/warnings/notes.
353 ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000354 };
355}
356
357/// PrintProblem - This takes a diagnostic map of the delta between expected and
358/// seen diagnostics. If there's anything in it, then something unexpected
359/// happened. Print the map out in a nice format and return "true". If the map
360/// is empty and we're not going to print things, then return "false".
361///
Daniel Dunbar221c7212009-11-14 07:53:24 +0000362static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000363 const_diag_iterator diag_begin,
364 const_diag_iterator diag_end,
365 const char *Kind, bool Expected) {
366 if (diag_begin == diag_end) return 0;
367
368 llvm::SmallString<256> Fmt;
369 llvm::raw_svector_ostream OS(Fmt);
370 for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
Daniel Dunbar221c7212009-11-14 07:53:24 +0000371 if (I->first.isInvalid() || !SourceMgr)
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000372 OS << "\n (frontend)";
373 else
Chandler Carruth5ef04ee2011-02-23 00:47:48 +0000374 OS << "\n Line " << SourceMgr->getPresumedLineNumber(I->first);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000375 OS << ": " << I->second;
376 }
377
378 Diags.Report(diag::err_verify_inconsistent_diags)
Daniel Dunbar221c7212009-11-14 07:53:24 +0000379 << Kind << !Expected << OS.str();
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000380 return std::distance(diag_begin, diag_end);
381}
382
Chris Lattner60909e12010-04-28 20:02:30 +0000383static unsigned PrintProblem(Diagnostic &Diags, SourceManager *SourceMgr,
384 DirectiveList &DL, const char *Kind,
385 bool Expected) {
386 if (DL.empty())
387 return 0;
388
389 llvm::SmallString<256> Fmt;
390 llvm::raw_svector_ostream OS(Fmt);
391 for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
392 Directive& D = **I;
393 if (D.Location.isInvalid() || !SourceMgr)
394 OS << "\n (frontend)";
395 else
Chandler Carruth5ef04ee2011-02-23 00:47:48 +0000396 OS << "\n Line " << SourceMgr->getPresumedLineNumber(D.Location);
Chris Lattner60909e12010-04-28 20:02:30 +0000397 OS << ": " << D.Text;
398 }
399
400 Diags.Report(diag::err_verify_inconsistent_diags)
401 << Kind << !Expected << OS.str();
402 return DL.size();
403}
404
405/// CheckLists - Compare expected to seen diagnostic lists and return the
406/// the difference between them.
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000407///
Chris Lattner60909e12010-04-28 20:02:30 +0000408static unsigned CheckLists(Diagnostic &Diags, SourceManager &SourceMgr,
409 const char *Label,
410 DirectiveList &Left,
411 const_diag_iterator d2_begin,
412 const_diag_iterator d2_end) {
413 DirectiveList LeftOnly;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000414 DiagList Right(d2_begin, d2_end);
415
Chris Lattner60909e12010-04-28 20:02:30 +0000416 for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
417 Directive& D = **I;
Chandler Carruth5ef04ee2011-02-23 00:47:48 +0000418 unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000419
Chris Lattner60909e12010-04-28 20:02:30 +0000420 for (unsigned i = 0; i < D.Count; ++i) {
421 DiagList::iterator II, IE;
422 for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
Chandler Carruth5ef04ee2011-02-23 00:47:48 +0000423 unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
Chris Lattner60909e12010-04-28 20:02:30 +0000424 if (LineNo1 != LineNo2)
425 continue;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000426
Chris Lattner60909e12010-04-28 20:02:30 +0000427 const std::string &RightText = II->second;
428 if (D.Match(RightText))
429 break;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000430 }
Chris Lattner60909e12010-04-28 20:02:30 +0000431 if (II == IE) {
432 // Not found.
433 LeftOnly.push_back(*I);
434 } else {
435 // Found. The same cannot be found twice.
436 Right.erase(II);
437 }
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000438 }
439 }
440 // Now all that's left in Right are those that were not matched.
441
Chris Lattner60909e12010-04-28 20:02:30 +0000442 return (PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true) +
443 PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(),
444 Label, false));
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000445}
446
447/// CheckResults - This compares the expected results to those that
448/// were actually reported. It emits any discrepencies. Return "true" if there
449/// were problems. Return "false" otherwise.
450///
451static unsigned CheckResults(Diagnostic &Diags, SourceManager &SourceMgr,
452 const TextDiagnosticBuffer &Buffer,
Chris Lattner60909e12010-04-28 20:02:30 +0000453 ExpectedData &ED) {
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000454 // We want to capture the delta between what was expected and what was
455 // seen.
456 //
457 // Expected \ Seen - set expected but not seen
458 // Seen \ Expected - set seen but not expected
459 unsigned NumProblems = 0;
460
461 // See if there are error mismatches.
Chris Lattner60909e12010-04-28 20:02:30 +0000462 NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
463 Buffer.err_begin(), Buffer.err_end());
Daniel Dunbar221c7212009-11-14 07:53:24 +0000464
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000465 // See if there are warning mismatches.
Chris Lattner60909e12010-04-28 20:02:30 +0000466 NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
467 Buffer.warn_begin(), Buffer.warn_end());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000468
469 // See if there are note mismatches.
Chris Lattner60909e12010-04-28 20:02:30 +0000470 NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
471 Buffer.note_begin(), Buffer.note_end());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000472
473 return NumProblems;
474}
475
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000476void VerifyDiagnosticsClient::CheckDiagnostics() {
Chris Lattner60909e12010-04-28 20:02:30 +0000477 ExpectedData ED;
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000478
479 // Ensure any diagnostics go to the primary client.
Douglas Gregorbdbb0042010-08-18 22:29:43 +0000480 DiagnosticClient *CurClient = Diags.takeClient();
Daniel Dunbar221c7212009-11-14 07:53:24 +0000481 Diags.setClient(PrimaryClient.get());
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000482
483 // If we have a preprocessor, scan the source for expected diagnostic
484 // markers. If not then any diagnostics are unexpected.
485 if (CurrentPreprocessor) {
Axel Naumann01231612011-07-25 19:18:12 +0000486 SourceManager &SM = CurrentPreprocessor->getSourceManager();
487 // Extract expected-error strings from main file.
488 FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID());
489 // Only check for expectations in other diagnostic locations
490 // if they are not the main file (via ID or FileEntry) - the main
491 // file has already been looked at, and its expectations must not
492 // be added twice.
493 if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID()
494 && (!SM.getFileEntryForID(FirstErrorFID)
495 || (SM.getFileEntryForID(FirstErrorFID) !=
496 SM.getFileEntryForID(SM.getMainFileID()))))
497 FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID);
Daniel Dunbar221c7212009-11-14 07:53:24 +0000498
499 // Check that the expected diagnostics occurred.
Axel Naumann01231612011-07-25 19:18:12 +0000500 NumErrors += CheckResults(Diags, SM, *Buffer, ED);
Daniel Dunbar221c7212009-11-14 07:53:24 +0000501 } else {
502 NumErrors += (PrintProblem(Diags, 0,
503 Buffer->err_begin(), Buffer->err_end(),
504 "error", false) +
505 PrintProblem(Diags, 0,
506 Buffer->warn_begin(), Buffer->warn_end(),
507 "warn", false) +
508 PrintProblem(Diags, 0,
509 Buffer->note_begin(), Buffer->note_end(),
510 "note", false));
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000511 }
512
Douglas Gregorbdbb0042010-08-18 22:29:43 +0000513 Diags.takeClient();
Daniel Dunbar221c7212009-11-14 07:53:24 +0000514 Diags.setClient(CurClient);
Daniel Dunbar81f5a1e2009-11-14 03:23:19 +0000515
516 // Reset the buffer, we have processed all the diagnostics in it.
517 Buffer.reset(new TextDiagnosticBuffer());
518}
Chris Lattner60909e12010-04-28 20:02:30 +0000519
520Directive* Directive::Create(bool RegexKind, const SourceLocation &Location,
521 const std::string &Text, unsigned Count) {
522 if (RegexKind)
523 return new RegexDirective(Location, Text, Count);
524 return new StandardDirective(Location, Text, Count);
525}