VerifyDiagnosticConsumer.cpp revision 234353
1226586Sdim//===---- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ------===// 2226586Sdim// 3226586Sdim// The LLVM Compiler Infrastructure 4226586Sdim// 5226586Sdim// This file is distributed under the University of Illinois Open Source 6226586Sdim// License. See LICENSE.TXT for details. 7226586Sdim// 8226586Sdim//===----------------------------------------------------------------------===// 9226586Sdim// 10226586Sdim// This is a concrete diagnostic client, which buffers the diagnostic messages. 11226586Sdim// 12226586Sdim//===----------------------------------------------------------------------===// 13226586Sdim 14226586Sdim#include "clang/Frontend/VerifyDiagnosticConsumer.h" 15226586Sdim#include "clang/Frontend/FrontendDiagnostic.h" 16226586Sdim#include "clang/Frontend/TextDiagnosticBuffer.h" 17226586Sdim#include "clang/Lex/Preprocessor.h" 18226586Sdim#include "llvm/ADT/SmallString.h" 19226586Sdim#include "llvm/Support/Regex.h" 20226586Sdim#include "llvm/Support/raw_ostream.h" 21234353Sdim#include <climits> 22234353Sdim 23226586Sdimusing namespace clang; 24226586Sdim 25226586SdimVerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags) 26226586Sdim : Diags(_Diags), PrimaryClient(Diags.getClient()), 27226586Sdim OwnsPrimaryClient(Diags.ownsClient()), 28226586Sdim Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) 29226586Sdim{ 30226586Sdim Diags.takeClient(); 31226586Sdim} 32226586Sdim 33226586SdimVerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { 34226586Sdim CheckDiagnostics(); 35226586Sdim Diags.takeClient(); 36226586Sdim if (OwnsPrimaryClient) 37226586Sdim delete PrimaryClient; 38226586Sdim} 39226586Sdim 40226586Sdim// DiagnosticConsumer interface. 41226586Sdim 42226586Sdimvoid VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts, 43234353Sdim const Preprocessor *PP) { 44226586Sdim // FIXME: Const hack, we screw up the preprocessor but in practice its ok 45226586Sdim // because it doesn't get reused. It would be better if we could make a copy 46226586Sdim // though. 47226586Sdim CurrentPreprocessor = const_cast<Preprocessor*>(PP); 48226586Sdim 49226586Sdim PrimaryClient->BeginSourceFile(LangOpts, PP); 50226586Sdim} 51226586Sdim 52226586Sdimvoid VerifyDiagnosticConsumer::EndSourceFile() { 53226586Sdim CheckDiagnostics(); 54226586Sdim 55226586Sdim PrimaryClient->EndSourceFile(); 56226586Sdim 57226586Sdim CurrentPreprocessor = 0; 58226586Sdim} 59226586Sdim 60226586Sdimvoid VerifyDiagnosticConsumer::HandleDiagnostic( 61226586Sdim DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { 62226586Sdim if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) { 63226586Sdim const SourceManager &SM = Info.getSourceManager(); 64226586Sdim FirstErrorFID = SM.getFileID(Info.getLocation()); 65226586Sdim } 66226586Sdim // Send the diagnostic to the buffer, we will check it once we reach the end 67226586Sdim // of the source file (or are destructed). 68226586Sdim Buffer->HandleDiagnostic(DiagLevel, Info); 69226586Sdim} 70226586Sdim 71226586Sdim//===----------------------------------------------------------------------===// 72226586Sdim// Checking diagnostics implementation. 73226586Sdim//===----------------------------------------------------------------------===// 74226586Sdim 75226586Sdimtypedef TextDiagnosticBuffer::DiagList DiagList; 76226586Sdimtypedef TextDiagnosticBuffer::const_iterator const_diag_iterator; 77226586Sdim 78226586Sdimnamespace { 79226586Sdim 80226586Sdim/// Directive - Abstract class representing a parsed verify directive. 81226586Sdim/// 82226586Sdimclass Directive { 83226586Sdimpublic: 84226586Sdim static Directive* Create(bool RegexKind, const SourceLocation &Location, 85226586Sdim const std::string &Text, unsigned Count); 86226586Sdimpublic: 87234353Sdim /// Constant representing one or more matches aka regex "+". 88234353Sdim static const unsigned OneOrMoreCount = UINT_MAX; 89234353Sdim 90226586Sdim SourceLocation Location; 91226586Sdim const std::string Text; 92226586Sdim unsigned Count; 93226586Sdim 94226586Sdim virtual ~Directive() { } 95226586Sdim 96226586Sdim // Returns true if directive text is valid. 97226586Sdim // Otherwise returns false and populates E. 98226586Sdim virtual bool isValid(std::string &Error) = 0; 99226586Sdim 100226586Sdim // Returns true on match. 101226586Sdim virtual bool Match(const std::string &S) = 0; 102226586Sdim 103226586Sdimprotected: 104226586Sdim Directive(const SourceLocation &Location, const std::string &Text, 105226586Sdim unsigned Count) 106226586Sdim : Location(Location), Text(Text), Count(Count) { } 107226586Sdim 108226586Sdimprivate: 109226586Sdim Directive(const Directive&); // DO NOT IMPLEMENT 110226586Sdim void operator=(const Directive&); // DO NOT IMPLEMENT 111226586Sdim}; 112226586Sdim 113226586Sdim/// StandardDirective - Directive with string matching. 114226586Sdim/// 115226586Sdimclass StandardDirective : public Directive { 116226586Sdimpublic: 117226586Sdim StandardDirective(const SourceLocation &Location, const std::string &Text, 118226586Sdim unsigned Count) 119226586Sdim : Directive(Location, Text, Count) { } 120226586Sdim 121226586Sdim virtual bool isValid(std::string &Error) { 122226586Sdim // all strings are considered valid; even empty ones 123226586Sdim return true; 124226586Sdim } 125226586Sdim 126226586Sdim virtual bool Match(const std::string &S) { 127234353Sdim return S.find(Text) != std::string::npos; 128226586Sdim } 129226586Sdim}; 130226586Sdim 131226586Sdim/// RegexDirective - Directive with regular-expression matching. 132226586Sdim/// 133226586Sdimclass RegexDirective : public Directive { 134226586Sdimpublic: 135226586Sdim RegexDirective(const SourceLocation &Location, const std::string &Text, 136226586Sdim unsigned Count) 137226586Sdim : Directive(Location, Text, Count), Regex(Text) { } 138226586Sdim 139226586Sdim virtual bool isValid(std::string &Error) { 140226586Sdim if (Regex.isValid(Error)) 141226586Sdim return true; 142226586Sdim return false; 143226586Sdim } 144226586Sdim 145226586Sdim virtual bool Match(const std::string &S) { 146226586Sdim return Regex.match(S); 147226586Sdim } 148226586Sdim 149226586Sdimprivate: 150226586Sdim llvm::Regex Regex; 151226586Sdim}; 152226586Sdim 153226586Sdimtypedef std::vector<Directive*> DirectiveList; 154226586Sdim 155226586Sdim/// ExpectedData - owns directive objects and deletes on destructor. 156226586Sdim/// 157226586Sdimstruct ExpectedData { 158226586Sdim DirectiveList Errors; 159226586Sdim DirectiveList Warnings; 160226586Sdim DirectiveList Notes; 161226586Sdim 162226586Sdim ~ExpectedData() { 163226586Sdim DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 }; 164226586Sdim for (DirectiveList **PL = Lists; *PL; ++PL) { 165226586Sdim DirectiveList * const L = *PL; 166226586Sdim for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I) 167226586Sdim delete *I; 168226586Sdim } 169226586Sdim } 170226586Sdim}; 171226586Sdim 172226586Sdimclass ParseHelper 173226586Sdim{ 174226586Sdimpublic: 175226586Sdim ParseHelper(const char *Begin, const char *End) 176226586Sdim : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } 177226586Sdim 178226586Sdim // Return true if string literal is next. 179226586Sdim bool Next(StringRef S) { 180226586Sdim P = C; 181226586Sdim PEnd = C + S.size(); 182226586Sdim if (PEnd > End) 183226586Sdim return false; 184226586Sdim return !memcmp(P, S.data(), S.size()); 185226586Sdim } 186226586Sdim 187226586Sdim // Return true if number is next. 188226586Sdim // Output N only if number is next. 189226586Sdim bool Next(unsigned &N) { 190226586Sdim unsigned TMP = 0; 191226586Sdim P = C; 192226586Sdim for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) { 193226586Sdim TMP *= 10; 194226586Sdim TMP += P[0] - '0'; 195226586Sdim } 196226586Sdim if (P == C) 197226586Sdim return false; 198226586Sdim PEnd = P; 199226586Sdim N = TMP; 200226586Sdim return true; 201226586Sdim } 202226586Sdim 203226586Sdim // Return true if string literal is found. 204226586Sdim // When true, P marks begin-position of S in content. 205226586Sdim bool Search(StringRef S) { 206226586Sdim P = std::search(C, End, S.begin(), S.end()); 207226586Sdim PEnd = P + S.size(); 208226586Sdim return P != End; 209226586Sdim } 210226586Sdim 211226586Sdim // Advance 1-past previous next/search. 212226586Sdim // Behavior is undefined if previous next/search failed. 213226586Sdim bool Advance() { 214226586Sdim C = PEnd; 215226586Sdim return C < End; 216226586Sdim } 217226586Sdim 218226586Sdim // Skip zero or more whitespace. 219226586Sdim void SkipWhitespace() { 220226586Sdim for (; C < End && isspace(*C); ++C) 221226586Sdim ; 222226586Sdim } 223226586Sdim 224226586Sdim // Return true if EOF reached. 225226586Sdim bool Done() { 226226586Sdim return !(C < End); 227226586Sdim } 228226586Sdim 229226586Sdim const char * const Begin; // beginning of expected content 230226586Sdim const char * const End; // end of expected content (1-past) 231226586Sdim const char *C; // position of next char in content 232226586Sdim const char *P; 233226586Sdim 234226586Sdimprivate: 235226586Sdim const char *PEnd; // previous next/search subject end (1-past) 236226586Sdim}; 237226586Sdim 238226586Sdim} // namespace anonymous 239226586Sdim 240226586Sdim/// ParseDirective - Go through the comment and see if it indicates expected 241226586Sdim/// diagnostics. If so, then put them in the appropriate directive list. 242226586Sdim/// 243226586Sdimstatic void ParseDirective(const char *CommentStart, unsigned CommentLen, 244226586Sdim ExpectedData &ED, Preprocessor &PP, 245226586Sdim SourceLocation Pos) { 246226586Sdim // A single comment may contain multiple directives. 247226586Sdim for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) { 248226586Sdim // search for token: expected 249226586Sdim if (!PH.Search("expected")) 250226586Sdim break; 251226586Sdim PH.Advance(); 252226586Sdim 253226586Sdim // next token: - 254226586Sdim if (!PH.Next("-")) 255226586Sdim continue; 256226586Sdim PH.Advance(); 257226586Sdim 258226586Sdim // next token: { error | warning | note } 259226586Sdim DirectiveList* DL = NULL; 260226586Sdim if (PH.Next("error")) 261226586Sdim DL = &ED.Errors; 262226586Sdim else if (PH.Next("warning")) 263226586Sdim DL = &ED.Warnings; 264226586Sdim else if (PH.Next("note")) 265226586Sdim DL = &ED.Notes; 266226586Sdim else 267226586Sdim continue; 268226586Sdim PH.Advance(); 269226586Sdim 270226586Sdim // default directive kind 271226586Sdim bool RegexKind = false; 272226586Sdim const char* KindStr = "string"; 273226586Sdim 274226586Sdim // next optional token: - 275226586Sdim if (PH.Next("-re")) { 276226586Sdim PH.Advance(); 277226586Sdim RegexKind = true; 278226586Sdim KindStr = "regex"; 279226586Sdim } 280226586Sdim 281226586Sdim // skip optional whitespace 282226586Sdim PH.SkipWhitespace(); 283226586Sdim 284234353Sdim // next optional token: positive integer or a '+'. 285226586Sdim unsigned Count = 1; 286226586Sdim if (PH.Next(Count)) 287226586Sdim PH.Advance(); 288234353Sdim else if (PH.Next("+")) { 289234353Sdim Count = Directive::OneOrMoreCount; 290234353Sdim PH.Advance(); 291234353Sdim } 292226586Sdim 293226586Sdim // skip optional whitespace 294226586Sdim PH.SkipWhitespace(); 295226586Sdim 296226586Sdim // next token: {{ 297226586Sdim if (!PH.Next("{{")) { 298226586Sdim PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), 299226586Sdim diag::err_verify_missing_start) << KindStr; 300226586Sdim continue; 301226586Sdim } 302226586Sdim PH.Advance(); 303226586Sdim const char* const ContentBegin = PH.C; // mark content begin 304226586Sdim 305226586Sdim // search for token: }} 306226586Sdim if (!PH.Search("}}")) { 307226586Sdim PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), 308226586Sdim diag::err_verify_missing_end) << KindStr; 309226586Sdim continue; 310226586Sdim } 311226586Sdim const char* const ContentEnd = PH.P; // mark content end 312226586Sdim PH.Advance(); 313226586Sdim 314226586Sdim // build directive text; convert \n to newlines 315226586Sdim std::string Text; 316226586Sdim StringRef NewlineStr = "\\n"; 317226586Sdim StringRef Content(ContentBegin, ContentEnd-ContentBegin); 318226586Sdim size_t CPos = 0; 319226586Sdim size_t FPos; 320226586Sdim while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) { 321226586Sdim Text += Content.substr(CPos, FPos-CPos); 322226586Sdim Text += '\n'; 323226586Sdim CPos = FPos + NewlineStr.size(); 324226586Sdim } 325226586Sdim if (Text.empty()) 326226586Sdim Text.assign(ContentBegin, ContentEnd); 327226586Sdim 328226586Sdim // construct new directive 329226586Sdim Directive *D = Directive::Create(RegexKind, Pos, Text, Count); 330226586Sdim std::string Error; 331226586Sdim if (D->isValid(Error)) 332226586Sdim DL->push_back(D); 333226586Sdim else { 334226586Sdim PP.Diag(Pos.getLocWithOffset(ContentBegin-PH.Begin), 335226586Sdim diag::err_verify_invalid_content) 336226586Sdim << KindStr << Error; 337226586Sdim } 338226586Sdim } 339226586Sdim} 340226586Sdim 341226586Sdim/// FindExpectedDiags - Lex the main source file to find all of the 342226586Sdim// expected errors and warnings. 343226586Sdimstatic void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) { 344226586Sdim // Create a raw lexer to pull all the comments out of FID. 345226586Sdim if (FID.isInvalid()) 346226586Sdim return; 347226586Sdim 348226586Sdim SourceManager& SM = PP.getSourceManager(); 349226586Sdim // Create a lexer to lex all the tokens of the main file in raw mode. 350226586Sdim const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); 351234353Sdim Lexer RawLex(FID, FromFile, SM, PP.getLangOpts()); 352226586Sdim 353226586Sdim // Return comments as tokens, this is how we find expected diagnostics. 354226586Sdim RawLex.SetCommentRetentionState(true); 355226586Sdim 356226586Sdim Token Tok; 357226586Sdim Tok.setKind(tok::comment); 358226586Sdim while (Tok.isNot(tok::eof)) { 359226586Sdim RawLex.Lex(Tok); 360226586Sdim if (!Tok.is(tok::comment)) continue; 361226586Sdim 362226586Sdim std::string Comment = PP.getSpelling(Tok); 363226586Sdim if (Comment.empty()) continue; 364226586Sdim 365226586Sdim // Find all expected errors/warnings/notes. 366226586Sdim ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation()); 367226586Sdim }; 368226586Sdim} 369226586Sdim 370226586Sdim/// PrintProblem - This takes a diagnostic map of the delta between expected and 371226586Sdim/// seen diagnostics. If there's anything in it, then something unexpected 372226586Sdim/// happened. Print the map out in a nice format and return "true". If the map 373226586Sdim/// is empty and we're not going to print things, then return "false". 374226586Sdim/// 375226586Sdimstatic unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, 376226586Sdim const_diag_iterator diag_begin, 377226586Sdim const_diag_iterator diag_end, 378226586Sdim const char *Kind, bool Expected) { 379226586Sdim if (diag_begin == diag_end) return 0; 380226586Sdim 381234353Sdim SmallString<256> Fmt; 382226586Sdim llvm::raw_svector_ostream OS(Fmt); 383226586Sdim for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) { 384226586Sdim if (I->first.isInvalid() || !SourceMgr) 385226586Sdim OS << "\n (frontend)"; 386226586Sdim else 387226586Sdim OS << "\n Line " << SourceMgr->getPresumedLineNumber(I->first); 388226586Sdim OS << ": " << I->second; 389226586Sdim } 390226586Sdim 391226586Sdim Diags.Report(diag::err_verify_inconsistent_diags) 392226586Sdim << Kind << !Expected << OS.str(); 393226586Sdim return std::distance(diag_begin, diag_end); 394226586Sdim} 395226586Sdim 396226586Sdimstatic unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, 397226586Sdim DirectiveList &DL, const char *Kind, 398226586Sdim bool Expected) { 399226586Sdim if (DL.empty()) 400226586Sdim return 0; 401226586Sdim 402234353Sdim SmallString<256> Fmt; 403226586Sdim llvm::raw_svector_ostream OS(Fmt); 404226586Sdim for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { 405226586Sdim Directive& D = **I; 406226586Sdim if (D.Location.isInvalid() || !SourceMgr) 407226586Sdim OS << "\n (frontend)"; 408226586Sdim else 409226586Sdim OS << "\n Line " << SourceMgr->getPresumedLineNumber(D.Location); 410226586Sdim OS << ": " << D.Text; 411226586Sdim } 412226586Sdim 413226586Sdim Diags.Report(diag::err_verify_inconsistent_diags) 414226586Sdim << Kind << !Expected << OS.str(); 415226586Sdim return DL.size(); 416226586Sdim} 417226586Sdim 418226586Sdim/// CheckLists - Compare expected to seen diagnostic lists and return the 419226586Sdim/// the difference between them. 420226586Sdim/// 421226586Sdimstatic unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, 422226586Sdim const char *Label, 423226586Sdim DirectiveList &Left, 424226586Sdim const_diag_iterator d2_begin, 425226586Sdim const_diag_iterator d2_end) { 426226586Sdim DirectiveList LeftOnly; 427226586Sdim DiagList Right(d2_begin, d2_end); 428226586Sdim 429226586Sdim for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) { 430226586Sdim Directive& D = **I; 431226586Sdim unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location); 432234353Sdim bool FoundOnce = false; 433226586Sdim 434226586Sdim for (unsigned i = 0; i < D.Count; ++i) { 435226586Sdim DiagList::iterator II, IE; 436226586Sdim for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { 437226586Sdim unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first); 438226586Sdim if (LineNo1 != LineNo2) 439226586Sdim continue; 440226586Sdim 441226586Sdim const std::string &RightText = II->second; 442226586Sdim if (D.Match(RightText)) 443226586Sdim break; 444226586Sdim } 445226586Sdim if (II == IE) { 446234353Sdim if (D.Count == D.OneOrMoreCount) { 447234353Sdim if (!FoundOnce) 448234353Sdim LeftOnly.push_back(*I); 449234353Sdim // We are only interested in at least one match, so exit the loop. 450234353Sdim break; 451234353Sdim } 452226586Sdim // Not found. 453226586Sdim LeftOnly.push_back(*I); 454226586Sdim } else { 455226586Sdim // Found. The same cannot be found twice. 456226586Sdim Right.erase(II); 457234353Sdim FoundOnce = true; 458226586Sdim } 459226586Sdim } 460226586Sdim } 461226586Sdim // Now all that's left in Right are those that were not matched. 462234353Sdim unsigned num = PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true); 463234353Sdim num += PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(), 464234353Sdim Label, false); 465234353Sdim return num; 466226586Sdim} 467226586Sdim 468226586Sdim/// CheckResults - This compares the expected results to those that 469226586Sdim/// were actually reported. It emits any discrepencies. Return "true" if there 470226586Sdim/// were problems. Return "false" otherwise. 471226586Sdim/// 472226586Sdimstatic unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, 473226586Sdim const TextDiagnosticBuffer &Buffer, 474226586Sdim ExpectedData &ED) { 475226586Sdim // We want to capture the delta between what was expected and what was 476226586Sdim // seen. 477226586Sdim // 478226586Sdim // Expected \ Seen - set expected but not seen 479226586Sdim // Seen \ Expected - set seen but not expected 480226586Sdim unsigned NumProblems = 0; 481226586Sdim 482226586Sdim // See if there are error mismatches. 483226586Sdim NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors, 484226586Sdim Buffer.err_begin(), Buffer.err_end()); 485226586Sdim 486226586Sdim // See if there are warning mismatches. 487226586Sdim NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings, 488226586Sdim Buffer.warn_begin(), Buffer.warn_end()); 489226586Sdim 490226586Sdim // See if there are note mismatches. 491226586Sdim NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes, 492226586Sdim Buffer.note_begin(), Buffer.note_end()); 493226586Sdim 494226586Sdim return NumProblems; 495226586Sdim} 496226586Sdim 497226586Sdimvoid VerifyDiagnosticConsumer::CheckDiagnostics() { 498226586Sdim ExpectedData ED; 499226586Sdim 500226586Sdim // Ensure any diagnostics go to the primary client. 501226586Sdim bool OwnsCurClient = Diags.ownsClient(); 502226586Sdim DiagnosticConsumer *CurClient = Diags.takeClient(); 503226586Sdim Diags.setClient(PrimaryClient, false); 504226586Sdim 505226586Sdim // If we have a preprocessor, scan the source for expected diagnostic 506226586Sdim // markers. If not then any diagnostics are unexpected. 507226586Sdim if (CurrentPreprocessor) { 508226586Sdim SourceManager &SM = CurrentPreprocessor->getSourceManager(); 509226586Sdim // Extract expected-error strings from main file. 510226586Sdim FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID()); 511226586Sdim // Only check for expectations in other diagnostic locations 512226586Sdim // if they are not the main file (via ID or FileEntry) - the main 513226586Sdim // file has already been looked at, and its expectations must not 514226586Sdim // be added twice. 515226586Sdim if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID() 516226586Sdim && (!SM.getFileEntryForID(FirstErrorFID) 517226586Sdim || (SM.getFileEntryForID(FirstErrorFID) != 518226586Sdim SM.getFileEntryForID(SM.getMainFileID())))) { 519226586Sdim FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID); 520226586Sdim FirstErrorFID = FileID(); 521226586Sdim } 522226586Sdim 523226586Sdim // Check that the expected diagnostics occurred. 524226586Sdim NumErrors += CheckResults(Diags, SM, *Buffer, ED); 525226586Sdim } else { 526226586Sdim NumErrors += (PrintProblem(Diags, 0, 527226586Sdim Buffer->err_begin(), Buffer->err_end(), 528226586Sdim "error", false) + 529226586Sdim PrintProblem(Diags, 0, 530226586Sdim Buffer->warn_begin(), Buffer->warn_end(), 531226586Sdim "warn", false) + 532226586Sdim PrintProblem(Diags, 0, 533226586Sdim Buffer->note_begin(), Buffer->note_end(), 534226586Sdim "note", false)); 535226586Sdim } 536226586Sdim 537226586Sdim Diags.takeClient(); 538226586Sdim Diags.setClient(CurClient, OwnsCurClient); 539226586Sdim 540226586Sdim // Reset the buffer, we have processed all the diagnostics in it. 541226586Sdim Buffer.reset(new TextDiagnosticBuffer()); 542226586Sdim} 543226586Sdim 544226586SdimDiagnosticConsumer * 545226586SdimVerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const { 546226586Sdim if (!Diags.getClient()) 547226586Sdim Diags.setClient(PrimaryClient->clone(Diags)); 548226586Sdim 549226586Sdim return new VerifyDiagnosticConsumer(Diags); 550226586Sdim} 551226586Sdim 552226586SdimDirective* Directive::Create(bool RegexKind, const SourceLocation &Location, 553226586Sdim const std::string &Text, unsigned Count) { 554226586Sdim if (RegexKind) 555226586Sdim return new RegexDirective(Location, Text, Count); 556226586Sdim return new StandardDirective(Location, Text, Count); 557226586Sdim} 558