VerifyDiagnosticConsumer.cpp revision 234353
118334Speter//===---- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ------===// 250506Sobrien// 318334Speter// The LLVM Compiler Infrastructure 418334Speter// 518334Speter// This file is distributed under the University of Illinois Open Source 618334Speter// License. See LICENSE.TXT for details. 718334Speter// 818334Speter//===----------------------------------------------------------------------===// 918334Speter// 1018334Speter// This is a concrete diagnostic client, which buffers the diagnostic messages. 1118334Speter// 1218334Speter//===----------------------------------------------------------------------===// 1318334Speter 1418334Speter#include "clang/Frontend/VerifyDiagnosticConsumer.h" 1518334Speter#include "clang/Frontend/FrontendDiagnostic.h" 1618334Speter#include "clang/Frontend/TextDiagnosticBuffer.h" 1718334Speter#include "clang/Lex/Preprocessor.h" 1818334Speter#include "llvm/ADT/SmallString.h" 1918334Speter#include "llvm/Support/Regex.h" 2018334Speter#include "llvm/Support/raw_ostream.h" 2118334Speter#include <climits> 2218334Speter 2318334Speterusing namespace clang; 2418334Speter 2518334SpeterVerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags) 2618334Speter : Diags(_Diags), PrimaryClient(Diags.getClient()), 2718334Speter OwnsPrimaryClient(Diags.ownsClient()), 2818334Speter Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0) 2918334Speter{ 3050506Sobrien Diags.takeClient(); 3118334Speter} 3218334Speter 3318334SpeterVerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { 3418334Speter CheckDiagnostics(); 3518334Speter Diags.takeClient(); 3618334Speter if (OwnsPrimaryClient) 3718334Speter delete PrimaryClient; 3818334Speter} 3918334Speter 4018334Speter// DiagnosticConsumer interface. 4118334Speter 4218334Spetervoid VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts, 4318334Speter const Preprocessor *PP) { 4418334Speter // FIXME: Const hack, we screw up the preprocessor but in practice its ok 4518334Speter // because it doesn't get reused. It would be better if we could make a copy 4618334Speter // though. 4718334Speter CurrentPreprocessor = const_cast<Preprocessor*>(PP); 4818334Speter 4918334Speter PrimaryClient->BeginSourceFile(LangOpts, PP); 5018334Speter} 5118334Speter 5218334Spetervoid VerifyDiagnosticConsumer::EndSourceFile() { 5318334Speter CheckDiagnostics(); 5418334Speter 5518334Speter PrimaryClient->EndSourceFile(); 5650506Sobrien 5750506Sobrien CurrentPreprocessor = 0; 5850506Sobrien} 5950506Sobrien 6018334Spetervoid VerifyDiagnosticConsumer::HandleDiagnostic( 6118334Speter DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { 6218334Speter if (FirstErrorFID.isInvalid() && Info.hasSourceManager()) { 6318334Speter const SourceManager &SM = Info.getSourceManager(); 6418334Speter FirstErrorFID = SM.getFileID(Info.getLocation()); 6518334Speter } 6618334Speter // Send the diagnostic to the buffer, we will check it once we reach the end 6718334Speter // of the source file (or are destructed). 6818334Speter Buffer->HandleDiagnostic(DiagLevel, Info); 6918334Speter} 7018334Speter 7118334Speter//===----------------------------------------------------------------------===// 7218334Speter// Checking diagnostics implementation. 7318334Speter//===----------------------------------------------------------------------===// 7418334Speter 7518334Spetertypedef TextDiagnosticBuffer::DiagList DiagList; 7618334Spetertypedef TextDiagnosticBuffer::const_iterator const_diag_iterator; 7718334Speter 7818334Speternamespace { 7918334Speter 8018334Speter/// Directive - Abstract class representing a parsed verify directive. 8118334Speter/// 8218334Speterclass Directive { 8318334Speterpublic: 8418334Speter static Directive* Create(bool RegexKind, const SourceLocation &Location, 8518334Speter const std::string &Text, unsigned Count); 8618334Speterpublic: 8718334Speter /// Constant representing one or more matches aka regex "+". 8818334Speter static const unsigned OneOrMoreCount = UINT_MAX; 8918334Speter 9050506Sobrien SourceLocation Location; 9150506Sobrien const std::string Text; 9250506Sobrien unsigned Count; 9350506Sobrien 9450506Sobrien virtual ~Directive() { } 9550506Sobrien 9650506Sobrien // Returns true if directive text is valid. 9750506Sobrien // Otherwise returns false and populates E. 9818334Speter virtual bool isValid(std::string &Error) = 0; 9918334Speter 10018334Speter // Returns true on match. 10118334Speter virtual bool Match(const std::string &S) = 0; 10218334Speter 10318334Speterprotected: 10418334Speter Directive(const SourceLocation &Location, const std::string &Text, 10518334Speter unsigned Count) 10618334Speter : Location(Location), Text(Text), Count(Count) { } 10718334Speter 10818334Speterprivate: 10918334Speter Directive(const Directive&); // DO NOT IMPLEMENT 11018334Speter void operator=(const Directive&); // DO NOT IMPLEMENT 11118334Speter}; 11218334Speter 11318334Speter/// StandardDirective - Directive with string matching. 11418334Speter/// 11518334Speterclass StandardDirective : public Directive { 11618334Speterpublic: 11718334Speter StandardDirective(const SourceLocation &Location, const std::string &Text, 11818334Speter unsigned Count) 11918334Speter : Directive(Location, Text, Count) { } 12018334Speter 12118334Speter virtual bool isValid(std::string &Error) { 12218334Speter // all strings are considered valid; even empty ones 12318334Speter return true; 12418334Speter } 12518334Speter 12618334Speter virtual bool Match(const std::string &S) { 12718334Speter return S.find(Text) != std::string::npos; 12818334Speter } 12918334Speter}; 13018334Speter 13118334Speter/// RegexDirective - Directive with regular-expression matching. 13218334Speter/// 13318334Speterclass RegexDirective : public Directive { 13418334Speterpublic: 13518334Speter RegexDirective(const SourceLocation &Location, const std::string &Text, 13618334Speter unsigned Count) 13718334Speter : Directive(Location, Text, Count), Regex(Text) { } 13818334Speter 13918334Speter virtual bool isValid(std::string &Error) { 14050506Sobrien if (Regex.isValid(Error)) 14150506Sobrien return true; 14250506Sobrien return false; 14350506Sobrien } 14418334Speter 14518334Speter virtual bool Match(const std::string &S) { 14618334Speter return Regex.match(S); 14718334Speter } 14818334Speter 14918334Speterprivate: 15018334Speter llvm::Regex Regex; 15118334Speter}; 15250506Sobrien 15350506Sobrientypedef std::vector<Directive*> DirectiveList; 15450506Sobrien 15550506Sobrien/// ExpectedData - owns directive objects and deletes on destructor. 15650506Sobrien/// 15750506Sobrienstruct ExpectedData { 15850506Sobrien DirectiveList Errors; 15950506Sobrien DirectiveList Warnings; 16050506Sobrien DirectiveList Notes; 16150506Sobrien 16250506Sobrien ~ExpectedData() { 16350506Sobrien DirectiveList* Lists[] = { &Errors, &Warnings, &Notes, 0 }; 16418334Speter for (DirectiveList **PL = Lists; *PL; ++PL) { 16518334Speter DirectiveList * const L = *PL; 16618334Speter for (DirectiveList::iterator I = L->begin(), E = L->end(); I != E; ++I) 16718334Speter delete *I; 16818334Speter } 16918334Speter } 17018334Speter}; 17118334Speter 17218334Speterclass ParseHelper 17318334Speter{ 17418334Speterpublic: 17518334Speter ParseHelper(const char *Begin, const char *End) 17618334Speter : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } 17718334Speter 17818334Speter // Return true if string literal is next. 17918334Speter bool Next(StringRef S) { 18018334Speter P = C; 18118334Speter PEnd = C + S.size(); 18218334Speter if (PEnd > End) 18318334Speter return false; 18418334Speter return !memcmp(P, S.data(), S.size()); 18518334Speter } 18618334Speter 18718334Speter // Return true if number is next. 18818334Speter // Output N only if number is next. 18918334Speter bool Next(unsigned &N) { 19018334Speter unsigned TMP = 0; 19118334Speter P = C; 19218334Speter for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) { 19318334Speter TMP *= 10; 19418334Speter TMP += P[0] - '0'; 19518334Speter } 19618334Speter if (P == C) 19718334Speter return false; 19818334Speter PEnd = P; 19918334Speter N = TMP; 20018334Speter return true; 20118334Speter } 20218334Speter 20318334Speter // Return true if string literal is found. 20418334Speter // When true, P marks begin-position of S in content. 20518334Speter bool Search(StringRef S) { 20618334Speter P = std::search(C, End, S.begin(), S.end()); 20718334Speter PEnd = P + S.size(); 20818334Speter return P != End; 20918334Speter } 21018334Speter 21118334Speter // Advance 1-past previous next/search. 21218334Speter // Behavior is undefined if previous next/search failed. 21318334Speter bool Advance() { 21418334Speter C = PEnd; 21518334Speter return C < End; 21618334Speter } 21718334Speter 21818334Speter // Skip zero or more whitespace. 21918334Speter void SkipWhitespace() { 22018334Speter for (; C < End && isspace(*C); ++C) 22118334Speter ; 22218334Speter } 22318334Speter 22418334Speter // Return true if EOF reached. 22518334Speter bool Done() { 22618334Speter return !(C < End); 22718334Speter } 22818334Speter 22918334Speter const char * const Begin; // beginning of expected content 23018334Speter const char * const End; // end of expected content (1-past) 23118334Speter const char *C; // position of next char in content 23218334Speter const char *P; 23318334Speter 23418334Speterprivate: 23550506Sobrien const char *PEnd; // previous next/search subject end (1-past) 23650506Sobrien}; 23750506Sobrien 23850506Sobrien} // namespace anonymous 23950506Sobrien 24050506Sobrien/// ParseDirective - Go through the comment and see if it indicates expected 24150506Sobrien/// diagnostics. If so, then put them in the appropriate directive list. 24250506Sobrien/// 24350506Sobrienstatic void ParseDirective(const char *CommentStart, unsigned CommentLen, 24450506Sobrien ExpectedData &ED, Preprocessor &PP, 24518334Speter SourceLocation Pos) { 24618334Speter // A single comment may contain multiple directives. 24718334Speter for (ParseHelper PH(CommentStart, CommentStart+CommentLen); !PH.Done();) { 24818334Speter // search for token: expected 24918334Speter if (!PH.Search("expected")) 25018334Speter break; 25118334Speter PH.Advance(); 25218334Speter 25318334Speter // next token: - 25418334Speter if (!PH.Next("-")) 25518334Speter continue; 25618334Speter PH.Advance(); 25718334Speter 25818334Speter // next token: { error | warning | note } 25918334Speter DirectiveList* DL = NULL; 26018334Speter if (PH.Next("error")) 26118334Speter DL = &ED.Errors; 26218334Speter else if (PH.Next("warning")) 26318334Speter DL = &ED.Warnings; 26418334Speter else if (PH.Next("note")) 26518334Speter DL = &ED.Notes; 26618334Speter else 26718334Speter continue; 26818334Speter PH.Advance(); 26918334Speter 27018334Speter // default directive kind 27118334Speter bool RegexKind = false; 27218334Speter const char* KindStr = "string"; 27318334Speter 27418334Speter // next optional token: - 27518334Speter if (PH.Next("-re")) { 27618334Speter PH.Advance(); 27718334Speter RegexKind = true; 27818334Speter KindStr = "regex"; 27918334Speter } 28018334Speter 28118334Speter // skip optional whitespace 28218334Speter PH.SkipWhitespace(); 28318334Speter 28418334Speter // next optional token: positive integer or a '+'. 28518334Speter unsigned Count = 1; 28618334Speter if (PH.Next(Count)) 28718334Speter PH.Advance(); 28818334Speter else if (PH.Next("+")) { 28918334Speter Count = Directive::OneOrMoreCount; 29018334Speter PH.Advance(); 29118334Speter } 29218334Speter 29318334Speter // skip optional whitespace 29450506Sobrien PH.SkipWhitespace(); 29550506Sobrien 29650506Sobrien // next token: {{ 29750506Sobrien if (!PH.Next("{{")) { 29850506Sobrien PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), 29950506Sobrien diag::err_verify_missing_start) << KindStr; 30050506Sobrien continue; 30150506Sobrien } 30250506Sobrien PH.Advance(); 30318334Speter const char* const ContentBegin = PH.C; // mark content begin 30418334Speter 30518334Speter // search for token: }} 30618334Speter if (!PH.Search("}}")) { 30718334Speter PP.Diag(Pos.getLocWithOffset(PH.C-PH.Begin), 30818334Speter diag::err_verify_missing_end) << KindStr; 30918334Speter continue; 31018334Speter } 31118334Speter const char* const ContentEnd = PH.P; // mark content end 31218334Speter PH.Advance(); 31318334Speter 31418334Speter // build directive text; convert \n to newlines 31518334Speter std::string Text; 31618334Speter StringRef NewlineStr = "\\n"; 31718334Speter StringRef Content(ContentBegin, ContentEnd-ContentBegin); 31818334Speter size_t CPos = 0; 31918334Speter size_t FPos; 32018334Speter while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) { 32118334Speter Text += Content.substr(CPos, FPos-CPos); 32218334Speter Text += '\n'; 32318334Speter CPos = FPos + NewlineStr.size(); 32418334Speter } 32518334Speter if (Text.empty()) 32618334Speter Text.assign(ContentBegin, ContentEnd); 32718334Speter 32818334Speter // construct new directive 32918334Speter Directive *D = Directive::Create(RegexKind, Pos, Text, Count); 33018334Speter std::string Error; 33118334Speter if (D->isValid(Error)) 33218334Speter DL->push_back(D); 33318334Speter else { 33418334Speter PP.Diag(Pos.getLocWithOffset(ContentBegin-PH.Begin), 33518334Speter diag::err_verify_invalid_content) 33618334Speter << KindStr << Error; 33718334Speter } 33818334Speter } 33918334Speter} 34018334Speter 34118334Speter/// FindExpectedDiags - Lex the main source file to find all of the 34250506Sobrien// expected errors and warnings. 34350506Sobrienstatic void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED, FileID FID) { 34450506Sobrien // Create a raw lexer to pull all the comments out of FID. 34550506Sobrien if (FID.isInvalid()) 34650506Sobrien return; 34750506Sobrien 34850506Sobrien SourceManager& SM = PP.getSourceManager(); 34950506Sobrien // Create a lexer to lex all the tokens of the main file in raw mode. 35050506Sobrien const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); 35150506Sobrien Lexer RawLex(FID, FromFile, SM, PP.getLangOpts()); 35250506Sobrien 35350506Sobrien // Return comments as tokens, this is how we find expected diagnostics. 35450506Sobrien RawLex.SetCommentRetentionState(true); 35550506Sobrien 35650506Sobrien Token Tok; 35750506Sobrien Tok.setKind(tok::comment); 35850506Sobrien while (Tok.isNot(tok::eof)) { 35950506Sobrien RawLex.Lex(Tok); 36050506Sobrien if (!Tok.is(tok::comment)) continue; 36150506Sobrien 36250506Sobrien std::string Comment = PP.getSpelling(Tok); 36350506Sobrien if (Comment.empty()) continue; 36418334Speter 36518334Speter // Find all expected errors/warnings/notes. 36618334Speter ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation()); 36718334Speter }; 36818334Speter} 36918334Speter 37018334Speter/// PrintProblem - This takes a diagnostic map of the delta between expected and 37118334Speter/// seen diagnostics. If there's anything in it, then something unexpected 37218334Speter/// happened. Print the map out in a nice format and return "true". If the map 37318334Speter/// is empty and we're not going to print things, then return "false". 37418334Speter/// 37518334Speterstatic unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, 37618334Speter const_diag_iterator diag_begin, 37718334Speter const_diag_iterator diag_end, 37818334Speter const char *Kind, bool Expected) { 37918334Speter if (diag_begin == diag_end) return 0; 38018334Speter 38118334Speter SmallString<256> Fmt; 38218334Speter llvm::raw_svector_ostream OS(Fmt); 38318334Speter for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) { 38450506Sobrien if (I->first.isInvalid() || !SourceMgr) 38550506Sobrien OS << "\n (frontend)"; 38618334Speter else 38750506Sobrien OS << "\n Line " << SourceMgr->getPresumedLineNumber(I->first); 38850506Sobrien OS << ": " << I->second; 38950506Sobrien } 39050506Sobrien 39150506Sobrien Diags.Report(diag::err_verify_inconsistent_diags) 39250506Sobrien << Kind << !Expected << OS.str(); 39350506Sobrien return std::distance(diag_begin, diag_end); 39450506Sobrien} 39550506Sobrien 39650506Sobrienstatic unsigned PrintProblem(DiagnosticsEngine &Diags, SourceManager *SourceMgr, 39718334Speter DirectiveList &DL, const char *Kind, 39818334Speter bool Expected) { 39918334Speter if (DL.empty()) 40018334Speter return 0; 40118334Speter 40218334Speter SmallString<256> Fmt; 40318334Speter llvm::raw_svector_ostream OS(Fmt); 40418334Speter for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) { 40550506Sobrien Directive& D = **I; 40650506Sobrien if (D.Location.isInvalid() || !SourceMgr) 40750506Sobrien OS << "\n (frontend)"; 40850506Sobrien else 40950506Sobrien OS << "\n Line " << SourceMgr->getPresumedLineNumber(D.Location); 41018334Speter OS << ": " << D.Text; 41118334Speter } 41218334Speter 41350506Sobrien Diags.Report(diag::err_verify_inconsistent_diags) 41450506Sobrien << Kind << !Expected << OS.str(); 41550506Sobrien return DL.size(); 41618334Speter} 41718334Speter 41818334Speter/// CheckLists - Compare expected to seen diagnostic lists and return the 41950506Sobrien/// the difference between them. 42050506Sobrien/// 42150506Sobrienstatic unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, 42250506Sobrien const char *Label, 42350506Sobrien DirectiveList &Left, 42450506Sobrien const_diag_iterator d2_begin, 42550506Sobrien const_diag_iterator d2_end) { 42650506Sobrien DirectiveList LeftOnly; 42750506Sobrien DiagList Right(d2_begin, d2_end); 42818334Speter 42918334Speter for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) { 43018334Speter Directive& D = **I; 43118334Speter unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.Location); 43218334Speter bool FoundOnce = false; 43318334Speter 43438510Sbde for (unsigned i = 0; i < D.Count; ++i) { 43550506Sobrien DiagList::iterator II, IE; 43650506Sobrien for (II = Right.begin(), IE = Right.end(); II != IE; ++II) { 43750506Sobrien unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first); 43850506Sobrien if (LineNo1 != LineNo2) 43950506Sobrien continue; 44050506Sobrien 44150506Sobrien const std::string &RightText = II->second; 44250506Sobrien if (D.Match(RightText)) 44338510Sbde break; 44450506Sobrien } 44550506Sobrien if (II == IE) { 44650506Sobrien if (D.Count == D.OneOrMoreCount) { 44750506Sobrien if (!FoundOnce) 44850506Sobrien LeftOnly.push_back(*I); 44950506Sobrien // We are only interested in at least one match, so exit the loop. 45050506Sobrien break; 45150506Sobrien } 45250506Sobrien // Not found. 45350506Sobrien LeftOnly.push_back(*I); 45450506Sobrien } else { 45550506Sobrien // Found. The same cannot be found twice. 45618334Speter Right.erase(II); 45718334Speter FoundOnce = true; 45818334Speter } 45918334Speter } 46018334Speter } 46118334Speter // Now all that's left in Right are those that were not matched. 46218334Speter unsigned num = PrintProblem(Diags, &SourceMgr, LeftOnly, Label, true); 46318334Speter num += PrintProblem(Diags, &SourceMgr, Right.begin(), Right.end(), 46418334Speter Label, false); 46518334Speter return num; 46618334Speter} 46718334Speter 46818334Speter/// CheckResults - This compares the expected results to those that 46918334Speter/// were actually reported. It emits any discrepencies. Return "true" if there 47018334Speter/// were problems. Return "false" otherwise. 47118334Speter/// 47218334Speterstatic unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, 47318334Speter const TextDiagnosticBuffer &Buffer, 47418334Speter ExpectedData &ED) { 47518334Speter // We want to capture the delta between what was expected and what was 47618334Speter // seen. 47718334Speter // 47818334Speter // Expected \ Seen - set expected but not seen 47950506Sobrien // Seen \ Expected - set seen but not expected 48050506Sobrien unsigned NumProblems = 0; 48150506Sobrien 48250506Sobrien // See if there are error mismatches. 48350506Sobrien NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors, 48450506Sobrien Buffer.err_begin(), Buffer.err_end()); 48550506Sobrien 48650506Sobrien // See if there are warning mismatches. 48750506Sobrien NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings, 48850506Sobrien Buffer.warn_begin(), Buffer.warn_end()); 48950506Sobrien 49050506Sobrien // See if there are note mismatches. 49150506Sobrien NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes, 49250506Sobrien Buffer.note_begin(), Buffer.note_end()); 49350506Sobrien 49450506Sobrien return NumProblems; 49550506Sobrien} 49650506Sobrien 49750506Sobrienvoid VerifyDiagnosticConsumer::CheckDiagnostics() { 49850506Sobrien ExpectedData ED; 49950506Sobrien 50050506Sobrien // Ensure any diagnostics go to the primary client. 50150506Sobrien bool OwnsCurClient = Diags.ownsClient(); 502 DiagnosticConsumer *CurClient = Diags.takeClient(); 503 Diags.setClient(PrimaryClient, false); 504 505 // If we have a preprocessor, scan the source for expected diagnostic 506 // markers. If not then any diagnostics are unexpected. 507 if (CurrentPreprocessor) { 508 SourceManager &SM = CurrentPreprocessor->getSourceManager(); 509 // Extract expected-error strings from main file. 510 FindExpectedDiags(*CurrentPreprocessor, ED, SM.getMainFileID()); 511 // Only check for expectations in other diagnostic locations 512 // if they are not the main file (via ID or FileEntry) - the main 513 // file has already been looked at, and its expectations must not 514 // be added twice. 515 if (!FirstErrorFID.isInvalid() && FirstErrorFID != SM.getMainFileID() 516 && (!SM.getFileEntryForID(FirstErrorFID) 517 || (SM.getFileEntryForID(FirstErrorFID) != 518 SM.getFileEntryForID(SM.getMainFileID())))) { 519 FindExpectedDiags(*CurrentPreprocessor, ED, FirstErrorFID); 520 FirstErrorFID = FileID(); 521 } 522 523 // Check that the expected diagnostics occurred. 524 NumErrors += CheckResults(Diags, SM, *Buffer, ED); 525 } else { 526 NumErrors += (PrintProblem(Diags, 0, 527 Buffer->err_begin(), Buffer->err_end(), 528 "error", false) + 529 PrintProblem(Diags, 0, 530 Buffer->warn_begin(), Buffer->warn_end(), 531 "warn", false) + 532 PrintProblem(Diags, 0, 533 Buffer->note_begin(), Buffer->note_end(), 534 "note", false)); 535 } 536 537 Diags.takeClient(); 538 Diags.setClient(CurClient, OwnsCurClient); 539 540 // Reset the buffer, we have processed all the diagnostics in it. 541 Buffer.reset(new TextDiagnosticBuffer()); 542} 543 544DiagnosticConsumer * 545VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const { 546 if (!Diags.getClient()) 547 Diags.setClient(PrimaryClient->clone(Diags)); 548 549 return new VerifyDiagnosticConsumer(Diags); 550} 551 552Directive* Directive::Create(bool RegexKind, const SourceLocation &Location, 553 const std::string &Text, unsigned Count) { 554 if (RegexKind) 555 return new RegexDirective(Location, Text, Count); 556 return new StandardDirective(Location, Text, Count); 557} 558