clang API Documentation

VerifyDiagnosticConsumer.cpp
Go to the documentation of this file.
00001 //===---- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This is a concrete diagnostic client, which buffers the diagnostic messages.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "clang/Frontend/VerifyDiagnosticConsumer.h"
00015 #include "clang/Basic/CharInfo.h"
00016 #include "clang/Basic/FileManager.h"
00017 #include "clang/Frontend/FrontendDiagnostic.h"
00018 #include "clang/Frontend/TextDiagnosticBuffer.h"
00019 #include "clang/Lex/HeaderSearch.h"
00020 #include "clang/Lex/Preprocessor.h"
00021 #include "llvm/ADT/SmallString.h"
00022 #include "llvm/Support/Regex.h"
00023 #include "llvm/Support/raw_ostream.h"
00024 
00025 using namespace clang;
00026 typedef VerifyDiagnosticConsumer::Directive Directive;
00027 typedef VerifyDiagnosticConsumer::DirectiveList DirectiveList;
00028 typedef VerifyDiagnosticConsumer::ExpectedData ExpectedData;
00029 
00030 VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &Diags_)
00031   : Diags(Diags_),
00032     PrimaryClient(Diags.getClient()), PrimaryClientOwner(Diags.takeClient()),
00033     Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(nullptr),
00034     LangOpts(nullptr), SrcManager(nullptr), ActiveSourceFiles(0),
00035     Status(HasNoDirectives)
00036 {
00037   if (Diags.hasSourceManager())
00038     setSourceManager(Diags.getSourceManager());
00039 }
00040 
00041 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
00042   assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
00043   assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
00044   SrcManager = nullptr;
00045   CheckDiagnostics();
00046   Diags.takeClient().release();
00047 }
00048 
00049 #ifndef NDEBUG
00050 namespace {
00051 class VerifyFileTracker : public PPCallbacks {
00052   VerifyDiagnosticConsumer &Verify;
00053   SourceManager &SM;
00054 
00055 public:
00056   VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM)
00057     : Verify(Verify), SM(SM) { }
00058 
00059   /// \brief Hook into the preprocessor and update the list of parsed
00060   /// files when the preprocessor indicates a new file is entered.
00061   virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
00062                            SrcMgr::CharacteristicKind FileType,
00063                            FileID PrevFID) {
00064     Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
00065                                   VerifyDiagnosticConsumer::IsParsed);
00066   }
00067 };
00068 } // End anonymous namespace.
00069 #endif
00070 
00071 // DiagnosticConsumer interface.
00072 
00073 void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
00074                                                const Preprocessor *PP) {
00075   // Attach comment handler on first invocation.
00076   if (++ActiveSourceFiles == 1) {
00077     if (PP) {
00078       CurrentPreprocessor = PP;
00079       this->LangOpts = &LangOpts;
00080       setSourceManager(PP->getSourceManager());
00081       const_cast<Preprocessor*>(PP)->addCommentHandler(this);
00082 #ifndef NDEBUG
00083       // Debug build tracks parsed files.
00084       const_cast<Preprocessor*>(PP)->addPPCallbacks(
00085                       llvm::make_unique<VerifyFileTracker>(*this, *SrcManager));
00086 #endif
00087     }
00088   }
00089 
00090   assert((!PP || CurrentPreprocessor == PP) && "Preprocessor changed!");
00091   PrimaryClient->BeginSourceFile(LangOpts, PP);
00092 }
00093 
00094 void VerifyDiagnosticConsumer::EndSourceFile() {
00095   assert(ActiveSourceFiles && "No active source files!");
00096   PrimaryClient->EndSourceFile();
00097 
00098   // Detach comment handler once last active source file completed.
00099   if (--ActiveSourceFiles == 0) {
00100     if (CurrentPreprocessor)
00101       const_cast<Preprocessor*>(CurrentPreprocessor)->removeCommentHandler(this);
00102 
00103     // Check diagnostics once last file completed.
00104     CheckDiagnostics();
00105     CurrentPreprocessor = nullptr;
00106     LangOpts = nullptr;
00107   }
00108 }
00109 
00110 void VerifyDiagnosticConsumer::HandleDiagnostic(
00111       DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
00112   if (Info.hasSourceManager()) {
00113     // If this diagnostic is for a different source manager, ignore it.
00114     if (SrcManager && &Info.getSourceManager() != SrcManager)
00115       return;
00116 
00117     setSourceManager(Info.getSourceManager());
00118   }
00119 
00120 #ifndef NDEBUG
00121   // Debug build tracks unparsed files for possible
00122   // unparsed expected-* directives.
00123   if (SrcManager) {
00124     SourceLocation Loc = Info.getLocation();
00125     if (Loc.isValid()) {
00126       ParsedStatus PS = IsUnparsed;
00127 
00128       Loc = SrcManager->getExpansionLoc(Loc);
00129       FileID FID = SrcManager->getFileID(Loc);
00130 
00131       const FileEntry *FE = SrcManager->getFileEntryForID(FID);
00132       if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
00133         // If the file is a modules header file it shall not be parsed
00134         // for expected-* directives.
00135         HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
00136         if (HS.findModuleForHeader(FE))
00137           PS = IsUnparsedNoDirectives;
00138       }
00139 
00140       UpdateParsedFileStatus(*SrcManager, FID, PS);
00141     }
00142   }
00143 #endif
00144 
00145   // Send the diagnostic to the buffer, we will check it once we reach the end
00146   // of the source file (or are destructed).
00147   Buffer->HandleDiagnostic(DiagLevel, Info);
00148 }
00149 
00150 //===----------------------------------------------------------------------===//
00151 // Checking diagnostics implementation.
00152 //===----------------------------------------------------------------------===//
00153 
00154 typedef TextDiagnosticBuffer::DiagList DiagList;
00155 typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
00156 
00157 namespace {
00158 
00159 /// StandardDirective - Directive with string matching.
00160 ///
00161 class StandardDirective : public Directive {
00162 public:
00163   StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
00164                     bool MatchAnyLine, StringRef Text, unsigned Min,
00165                     unsigned Max)
00166     : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max) { }
00167 
00168   bool isValid(std::string &Error) override {
00169     // all strings are considered valid; even empty ones
00170     return true;
00171   }
00172 
00173   bool match(StringRef S) override {
00174     return S.find(Text) != StringRef::npos;
00175   }
00176 };
00177 
00178 /// RegexDirective - Directive with regular-expression matching.
00179 ///
00180 class RegexDirective : public Directive {
00181 public:
00182   RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
00183                  bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max,
00184                  StringRef RegexStr)
00185     : Directive(DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max),
00186       Regex(RegexStr) { }
00187 
00188   bool isValid(std::string &Error) override {
00189     if (Regex.isValid(Error))
00190       return true;
00191     return false;
00192   }
00193 
00194   bool match(StringRef S) override {
00195     return Regex.match(S);
00196   }
00197 
00198 private:
00199   llvm::Regex Regex;
00200 };
00201 
00202 class ParseHelper
00203 {
00204 public:
00205   ParseHelper(StringRef S)
00206     : Begin(S.begin()), End(S.end()), C(Begin), P(Begin), PEnd(nullptr) {}
00207 
00208   // Return true if string literal is next.
00209   bool Next(StringRef S) {
00210     P = C;
00211     PEnd = C + S.size();
00212     if (PEnd > End)
00213       return false;
00214     return !memcmp(P, S.data(), S.size());
00215   }
00216 
00217   // Return true if number is next.
00218   // Output N only if number is next.
00219   bool Next(unsigned &N) {
00220     unsigned TMP = 0;
00221     P = C;
00222     for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) {
00223       TMP *= 10;
00224       TMP += P[0] - '0';
00225     }
00226     if (P == C)
00227       return false;
00228     PEnd = P;
00229     N = TMP;
00230     return true;
00231   }
00232 
00233   // Return true if string literal is found.
00234   // When true, P marks begin-position of S in content.
00235   bool Search(StringRef S, bool EnsureStartOfWord = false) {
00236     do {
00237       P = std::search(C, End, S.begin(), S.end());
00238       PEnd = P + S.size();
00239       if (P == End)
00240         break;
00241       if (!EnsureStartOfWord
00242             // Check if string literal starts a new word.
00243             || P == Begin || isWhitespace(P[-1])
00244             // Or it could be preceded by the start of a comment.
00245             || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
00246                                 &&  P[-2] == '/'))
00247         return true;
00248       // Otherwise, skip and search again.
00249     } while (Advance());
00250     return false;
00251   }
00252 
00253   // Return true if a CloseBrace that closes the OpenBrace at the current nest
00254   // level is found. When true, P marks begin-position of CloseBrace.
00255   bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
00256     unsigned Depth = 1;
00257     P = C;
00258     while (P < End) {
00259       StringRef S(P, End - P);
00260       if (S.startswith(OpenBrace)) {
00261         ++Depth;
00262         P += OpenBrace.size();
00263       } else if (S.startswith(CloseBrace)) {
00264         --Depth;
00265         if (Depth == 0) {
00266           PEnd = P + CloseBrace.size();
00267           return true;
00268         }
00269         P += CloseBrace.size();
00270       } else {
00271         ++P;
00272       }
00273     }
00274     return false;
00275   }
00276 
00277   // Advance 1-past previous next/search.
00278   // Behavior is undefined if previous next/search failed.
00279   bool Advance() {
00280     C = PEnd;
00281     return C < End;
00282   }
00283 
00284   // Skip zero or more whitespace.
00285   void SkipWhitespace() {
00286     for (; C < End && isWhitespace(*C); ++C)
00287       ;
00288   }
00289 
00290   // Return true if EOF reached.
00291   bool Done() {
00292     return !(C < End);
00293   }
00294 
00295   const char * const Begin; // beginning of expected content
00296   const char * const End;   // end of expected content (1-past)
00297   const char *C;            // position of next char in content
00298   const char *P;
00299 
00300 private:
00301   const char *PEnd; // previous next/search subject end (1-past)
00302 };
00303 
00304 } // namespace anonymous
00305 
00306 /// ParseDirective - Go through the comment and see if it indicates expected
00307 /// diagnostics. If so, then put them in the appropriate directive list.
00308 ///
00309 /// Returns true if any valid directives were found.
00310 static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
00311                            Preprocessor *PP, SourceLocation Pos,
00312                            VerifyDiagnosticConsumer::DirectiveStatus &Status) {
00313   DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();
00314 
00315   // A single comment may contain multiple directives.
00316   bool FoundDirective = false;
00317   for (ParseHelper PH(S); !PH.Done();) {
00318     // Search for token: expected
00319     if (!PH.Search("expected", true))
00320       break;
00321     PH.Advance();
00322 
00323     // Next token: -
00324     if (!PH.Next("-"))
00325       continue;
00326     PH.Advance();
00327 
00328     // Next token: { error | warning | note }
00329     DirectiveList *DL = nullptr;
00330     if (PH.Next("error"))
00331       DL = ED ? &ED->Errors : nullptr;
00332     else if (PH.Next("warning"))
00333       DL = ED ? &ED->Warnings : nullptr;
00334     else if (PH.Next("remark"))
00335       DL = ED ? &ED->Remarks : nullptr;
00336     else if (PH.Next("note"))
00337       DL = ED ? &ED->Notes : nullptr;
00338     else if (PH.Next("no-diagnostics")) {
00339       if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
00340         Diags.Report(Pos, diag::err_verify_invalid_no_diags)
00341           << /*IsExpectedNoDiagnostics=*/true;
00342       else
00343         Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
00344       continue;
00345     } else
00346       continue;
00347     PH.Advance();
00348 
00349     if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
00350       Diags.Report(Pos, diag::err_verify_invalid_no_diags)
00351         << /*IsExpectedNoDiagnostics=*/false;
00352       continue;
00353     }
00354     Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;
00355 
00356     // If a directive has been found but we're not interested
00357     // in storing the directive information, return now.
00358     if (!DL)
00359       return true;
00360 
00361     // Default directive kind.
00362     bool RegexKind = false;
00363     const char* KindStr = "string";
00364 
00365     // Next optional token: -
00366     if (PH.Next("-re")) {
00367       PH.Advance();
00368       RegexKind = true;
00369       KindStr = "regex";
00370     }
00371 
00372     // Next optional token: @
00373     SourceLocation ExpectedLoc;
00374     bool MatchAnyLine = false;
00375     if (!PH.Next("@")) {
00376       ExpectedLoc = Pos;
00377     } else {
00378       PH.Advance();
00379       unsigned Line = 0;
00380       bool FoundPlus = PH.Next("+");
00381       if (FoundPlus || PH.Next("-")) {
00382         // Relative to current line.
00383         PH.Advance();
00384         bool Invalid = false;
00385         unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
00386         if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
00387           if (FoundPlus) ExpectedLine += Line;
00388           else ExpectedLine -= Line;
00389           ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
00390         }
00391       } else if (PH.Next(Line)) {
00392         // Absolute line number.
00393         if (Line > 0)
00394           ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
00395       } else if (PP && PH.Search(":")) {
00396         // Specific source file.
00397         StringRef Filename(PH.C, PH.P-PH.C);
00398         PH.Advance();
00399 
00400         // Lookup file via Preprocessor, like a #include.
00401         const DirectoryLookup *CurDir;
00402         const FileEntry *FE =
00403             PP->LookupFile(Pos, Filename, false, nullptr, nullptr, CurDir,
00404                            nullptr, nullptr, nullptr);
00405         if (!FE) {
00406           Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
00407                        diag::err_verify_missing_file) << Filename << KindStr;
00408           continue;
00409         }
00410 
00411         if (SM.translateFile(FE).isInvalid())
00412           SM.createFileID(FE, Pos, SrcMgr::C_User);
00413 
00414         if (PH.Next(Line) && Line > 0)
00415           ExpectedLoc = SM.translateFileLineCol(FE, Line, 1);
00416         else if (PH.Next("*")) {
00417           MatchAnyLine = true;
00418           ExpectedLoc = SM.translateFileLineCol(FE, 1, 1);
00419         }
00420       }
00421 
00422       if (ExpectedLoc.isInvalid()) {
00423         Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
00424                      diag::err_verify_missing_line) << KindStr;
00425         continue;
00426       }
00427       PH.Advance();
00428     }
00429 
00430     // Skip optional whitespace.
00431     PH.SkipWhitespace();
00432 
00433     // Next optional token: positive integer or a '+'.
00434     unsigned Min = 1;
00435     unsigned Max = 1;
00436     if (PH.Next(Min)) {
00437       PH.Advance();
00438       // A positive integer can be followed by a '+' meaning min
00439       // or more, or by a '-' meaning a range from min to max.
00440       if (PH.Next("+")) {
00441         Max = Directive::MaxCount;
00442         PH.Advance();
00443       } else if (PH.Next("-")) {
00444         PH.Advance();
00445         if (!PH.Next(Max) || Max < Min) {
00446           Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
00447                        diag::err_verify_invalid_range) << KindStr;
00448           continue;
00449         }
00450         PH.Advance();
00451       } else {
00452         Max = Min;
00453       }
00454     } else if (PH.Next("+")) {
00455       // '+' on its own means "1 or more".
00456       Max = Directive::MaxCount;
00457       PH.Advance();
00458     }
00459 
00460     // Skip optional whitespace.
00461     PH.SkipWhitespace();
00462 
00463     // Next token: {{
00464     if (!PH.Next("{{")) {
00465       Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
00466                    diag::err_verify_missing_start) << KindStr;
00467       continue;
00468     }
00469     PH.Advance();
00470     const char* const ContentBegin = PH.C; // mark content begin
00471 
00472     // Search for token: }}
00473     if (!PH.SearchClosingBrace("{{", "}}")) {
00474       Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
00475                    diag::err_verify_missing_end) << KindStr;
00476       continue;
00477     }
00478     const char* const ContentEnd = PH.P; // mark content end
00479     PH.Advance();
00480 
00481     // Build directive text; convert \n to newlines.
00482     std::string Text;
00483     StringRef NewlineStr = "\\n";
00484     StringRef Content(ContentBegin, ContentEnd-ContentBegin);
00485     size_t CPos = 0;
00486     size_t FPos;
00487     while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
00488       Text += Content.substr(CPos, FPos-CPos);
00489       Text += '\n';
00490       CPos = FPos + NewlineStr.size();
00491     }
00492     if (Text.empty())
00493       Text.assign(ContentBegin, ContentEnd);
00494 
00495     // Check that regex directives contain at least one regex.
00496     if (RegexKind && Text.find("{{") == StringRef::npos) {
00497       Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
00498                    diag::err_verify_missing_regex) << Text;
00499       return false;
00500     }
00501 
00502     // Construct new directive.
00503     std::unique_ptr<Directive> D = Directive::create(
00504         RegexKind, Pos, ExpectedLoc, MatchAnyLine, Text, Min, Max);
00505 
00506     std::string Error;
00507     if (D->isValid(Error)) {
00508       DL->push_back(std::move(D));
00509       FoundDirective = true;
00510     } else {
00511       Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
00512                    diag::err_verify_invalid_content)
00513         << KindStr << Error;
00514     }
00515   }
00516 
00517   return FoundDirective;
00518 }
00519 
00520 /// HandleComment - Hook into the preprocessor and extract comments containing
00521 ///  expected errors and warnings.
00522 bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
00523                                              SourceRange Comment) {
00524   SourceManager &SM = PP.getSourceManager();
00525 
00526   // If this comment is for a different source manager, ignore it.
00527   if (SrcManager && &SM != SrcManager)
00528     return false;
00529 
00530   SourceLocation CommentBegin = Comment.getBegin();
00531 
00532   const char *CommentRaw = SM.getCharacterData(CommentBegin);
00533   StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
00534 
00535   if (C.empty())
00536     return false;
00537 
00538   // Fold any "<EOL>" sequences
00539   size_t loc = C.find('\\');
00540   if (loc == StringRef::npos) {
00541     ParseDirective(C, &ED, SM, &PP, CommentBegin, Status);
00542     return false;
00543   }
00544 
00545   std::string C2;
00546   C2.reserve(C.size());
00547 
00548   for (size_t last = 0;; loc = C.find('\\', last)) {
00549     if (loc == StringRef::npos || loc == C.size()) {
00550       C2 += C.substr(last);
00551       break;
00552     }
00553     C2 += C.substr(last, loc-last);
00554     last = loc + 1;
00555 
00556     if (C[last] == '\n' || C[last] == '\r') {
00557       ++last;
00558 
00559       // Escape \r\n  or \n\r, but not \n\n.
00560       if (last < C.size())
00561         if (C[last] == '\n' || C[last] == '\r')
00562           if (C[last] != C[last-1])
00563             ++last;
00564     } else {
00565       // This was just a normal backslash.
00566       C2 += '\\';
00567     }
00568   }
00569 
00570   if (!C2.empty())
00571     ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status);
00572   return false;
00573 }
00574 
00575 #ifndef NDEBUG
00576 /// \brief Lex the specified source file to determine whether it contains
00577 /// any expected-* directives.  As a Lexer is used rather than a full-blown
00578 /// Preprocessor, directives inside skipped #if blocks will still be found.
00579 ///
00580 /// \return true if any directives were found.
00581 static bool findDirectives(SourceManager &SM, FileID FID,
00582                            const LangOptions &LangOpts) {
00583   // Create a raw lexer to pull all the comments out of FID.
00584   if (FID.isInvalid())
00585     return false;
00586 
00587   // Create a lexer to lex all the tokens of the main file in raw mode.
00588   const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
00589   Lexer RawLex(FID, FromFile, SM, LangOpts);
00590 
00591   // Return comments as tokens, this is how we find expected diagnostics.
00592   RawLex.SetCommentRetentionState(true);
00593 
00594   Token Tok;
00595   Tok.setKind(tok::comment);
00596   VerifyDiagnosticConsumer::DirectiveStatus Status =
00597     VerifyDiagnosticConsumer::HasNoDirectives;
00598   while (Tok.isNot(tok::eof)) {
00599     RawLex.LexFromRawLexer(Tok);
00600     if (!Tok.is(tok::comment)) continue;
00601 
00602     std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
00603     if (Comment.empty()) continue;
00604 
00605     // Find first directive.
00606     if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(),
00607                        Status))
00608       return true;
00609   }
00610   return false;
00611 }
00612 #endif // !NDEBUG
00613 
00614 /// \brief Takes a list of diagnostics that have been generated but not matched
00615 /// by an expected-* directive and produces a diagnostic to the user from this.
00616 static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
00617                                 const_diag_iterator diag_begin,
00618                                 const_diag_iterator diag_end,
00619                                 const char *Kind) {
00620   if (diag_begin == diag_end) return 0;
00621 
00622   SmallString<256> Fmt;
00623   llvm::raw_svector_ostream OS(Fmt);
00624   for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
00625     if (I->first.isInvalid() || !SourceMgr)
00626       OS << "\n  (frontend)";
00627     else {
00628       OS << "\n ";
00629       if (const FileEntry *File = SourceMgr->getFileEntryForID(
00630                                                 SourceMgr->getFileID(I->first)))
00631         OS << " File " << File->getName();
00632       OS << " Line " << SourceMgr->getPresumedLineNumber(I->first);
00633     }
00634     OS << ": " << I->second;
00635   }
00636 
00637   Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
00638     << Kind << /*Unexpected=*/true << OS.str();
00639   return std::distance(diag_begin, diag_end);
00640 }
00641 
00642 /// \brief Takes a list of diagnostics that were expected to have been generated
00643 /// but were not and produces a diagnostic to the user from this.
00644 static unsigned PrintExpected(DiagnosticsEngine &Diags,
00645                               SourceManager &SourceMgr,
00646                               std::vector<Directive *> &DL, const char *Kind) {
00647   if (DL.empty())
00648     return 0;
00649 
00650   SmallString<256> Fmt;
00651   llvm::raw_svector_ostream OS(Fmt);
00652   for (auto *DirPtr : DL) {
00653     Directive &D = *DirPtr;
00654     OS << "\n  File " << SourceMgr.getFilename(D.DiagnosticLoc);
00655     if (D.MatchAnyLine)
00656       OS << " Line *";
00657     else
00658       OS << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
00659     if (D.DirectiveLoc != D.DiagnosticLoc)
00660       OS << " (directive at "
00661          << SourceMgr.getFilename(D.DirectiveLoc) << ':'
00662          << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ')';
00663     OS << ": " << D.Text;
00664   }
00665 
00666   Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
00667     << Kind << /*Unexpected=*/false << OS.str();
00668   return DL.size();
00669 }
00670 
00671 /// \brief Determine whether two source locations come from the same file.
00672 static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
00673                            SourceLocation DiagnosticLoc) {
00674   while (DiagnosticLoc.isMacroID())
00675     DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);
00676 
00677   if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
00678     return true;
00679 
00680   const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
00681   if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
00682     return true;
00683 
00684   return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
00685 }
00686 
00687 /// CheckLists - Compare expected to seen diagnostic lists and return the
00688 /// the difference between them.
00689 ///
00690 static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
00691                            const char *Label,
00692                            DirectiveList &Left,
00693                            const_diag_iterator d2_begin,
00694                            const_diag_iterator d2_end) {
00695   std::vector<Directive *> LeftOnly;
00696   DiagList Right(d2_begin, d2_end);
00697 
00698   for (auto &Owner : Left) {
00699     Directive &D = *Owner;
00700     unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
00701 
00702     for (unsigned i = 0; i < D.Max; ++i) {
00703       DiagList::iterator II, IE;
00704       for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
00705         if (!D.MatchAnyLine) {
00706           unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
00707           if (LineNo1 != LineNo2)
00708             continue;
00709         }
00710 
00711         if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
00712           continue;
00713 
00714         const std::string &RightText = II->second;
00715         if (D.match(RightText))
00716           break;
00717       }
00718       if (II == IE) {
00719         // Not found.
00720         if (i >= D.Min) break;
00721         LeftOnly.push_back(&D);
00722       } else {
00723         // Found. The same cannot be found twice.
00724         Right.erase(II);
00725       }
00726     }
00727   }
00728   // Now all that's left in Right are those that were not matched.
00729   unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
00730   num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
00731   return num;
00732 }
00733 
00734 /// CheckResults - This compares the expected results to those that
00735 /// were actually reported. It emits any discrepencies. Return "true" if there
00736 /// were problems. Return "false" otherwise.
00737 ///
00738 static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
00739                              const TextDiagnosticBuffer &Buffer,
00740                              ExpectedData &ED) {
00741   // We want to capture the delta between what was expected and what was
00742   // seen.
00743   //
00744   //   Expected \ Seen - set expected but not seen
00745   //   Seen \ Expected - set seen but not expected
00746   unsigned NumProblems = 0;
00747 
00748   // See if there are error mismatches.
00749   NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
00750                             Buffer.err_begin(), Buffer.err_end());
00751 
00752   // See if there are warning mismatches.
00753   NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
00754                             Buffer.warn_begin(), Buffer.warn_end());
00755 
00756   // See if there are remark mismatches.
00757   NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,
00758                             Buffer.remark_begin(), Buffer.remark_end());
00759 
00760   // See if there are note mismatches.
00761   NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
00762                             Buffer.note_begin(), Buffer.note_end());
00763 
00764   return NumProblems;
00765 }
00766 
00767 void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
00768                                                       FileID FID,
00769                                                       ParsedStatus PS) {
00770   // Check SourceManager hasn't changed.
00771   setSourceManager(SM);
00772 
00773 #ifndef NDEBUG
00774   if (FID.isInvalid())
00775     return;
00776 
00777   const FileEntry *FE = SM.getFileEntryForID(FID);
00778 
00779   if (PS == IsParsed) {
00780     // Move the FileID from the unparsed set to the parsed set.
00781     UnparsedFiles.erase(FID);
00782     ParsedFiles.insert(std::make_pair(FID, FE));
00783   } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
00784     // Add the FileID to the unparsed set if we haven't seen it before.
00785 
00786     // Check for directives.
00787     bool FoundDirectives;
00788     if (PS == IsUnparsedNoDirectives)
00789       FoundDirectives = false;
00790     else
00791       FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
00792 
00793     // Add the FileID to the unparsed set.
00794     UnparsedFiles.insert(std::make_pair(FID,
00795                                       UnparsedFileStatus(FE, FoundDirectives)));
00796   }
00797 #endif
00798 }
00799 
00800 void VerifyDiagnosticConsumer::CheckDiagnostics() {
00801   // Ensure any diagnostics go to the primary client.
00802   DiagnosticConsumer *CurClient = Diags.getClient();
00803   std::unique_ptr<DiagnosticConsumer> Owner = Diags.takeClient();
00804   Diags.setClient(PrimaryClient, false);
00805 
00806 #ifndef NDEBUG
00807   // In a debug build, scan through any files that may have been missed
00808   // during parsing and issue a fatal error if directives are contained
00809   // within these files.  If a fatal error occurs, this suggests that
00810   // this file is being parsed separately from the main file, in which
00811   // case consider moving the directives to the correct place, if this
00812   // is applicable.
00813   if (UnparsedFiles.size() > 0) {
00814     // Generate a cache of parsed FileEntry pointers for alias lookups.
00815     llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
00816     for (ParsedFilesMap::iterator I = ParsedFiles.begin(),
00817                                 End = ParsedFiles.end(); I != End; ++I) {
00818       if (const FileEntry *FE = I->second)
00819         ParsedFileCache.insert(FE);
00820     }
00821 
00822     // Iterate through list of unparsed files.
00823     for (UnparsedFilesMap::iterator I = UnparsedFiles.begin(),
00824                                   End = UnparsedFiles.end(); I != End; ++I) {
00825       const UnparsedFileStatus &Status = I->second;
00826       const FileEntry *FE = Status.getFile();
00827 
00828       // Skip files that have been parsed via an alias.
00829       if (FE && ParsedFileCache.count(FE))
00830         continue;
00831 
00832       // Report a fatal error if this file contained directives.
00833       if (Status.foundDirectives()) {
00834         llvm::report_fatal_error(Twine("-verify directives found after rather"
00835                                        " than during normal parsing of ",
00836                                  StringRef(FE ? FE->getName() : "(unknown)")));
00837       }
00838     }
00839 
00840     // UnparsedFiles has been processed now, so clear it.
00841     UnparsedFiles.clear();
00842   }
00843 #endif // !NDEBUG
00844 
00845   if (SrcManager) {
00846     // Produce an error if no expected-* directives could be found in the
00847     // source file(s) processed.
00848     if (Status == HasNoDirectives) {
00849       Diags.Report(diag::err_verify_no_directives).setForceEmit();
00850       ++NumErrors;
00851       Status = HasNoDirectivesReported;
00852     }
00853 
00854     // Check that the expected diagnostics occurred.
00855     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
00856   } else {
00857     NumErrors += (PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
00858                                   Buffer->err_end(), "error") +
00859                   PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
00860                                   Buffer->warn_end(), "warn") +
00861                   PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
00862                                   Buffer->note_end(), "note"));
00863   }
00864 
00865   Diags.setClient(CurClient, Owner.release() != nullptr);
00866 
00867   // Reset the buffer, we have processed all the diagnostics in it.
00868   Buffer.reset(new TextDiagnosticBuffer());
00869   ED.Reset();
00870 }
00871 
00872 std::unique_ptr<Directive> Directive::create(bool RegexKind,
00873                                              SourceLocation DirectiveLoc,
00874                                              SourceLocation DiagnosticLoc,
00875                                              bool MatchAnyLine, StringRef Text,
00876                                              unsigned Min, unsigned Max) {
00877   if (!RegexKind)
00878     return llvm::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
00879                                                 MatchAnyLine, Text, Min, Max);
00880 
00881   // Parse the directive into a regular expression.
00882   std::string RegexStr;
00883   StringRef S = Text;
00884   while (!S.empty()) {
00885     if (S.startswith("{{")) {
00886       S = S.drop_front(2);
00887       size_t RegexMatchLength = S.find("}}");
00888       assert(RegexMatchLength != StringRef::npos);
00889       // Append the regex, enclosed in parentheses.
00890       RegexStr += "(";
00891       RegexStr.append(S.data(), RegexMatchLength);
00892       RegexStr += ")";
00893       S = S.drop_front(RegexMatchLength + 2);
00894     } else {
00895       size_t VerbatimMatchLength = S.find("{{");
00896       if (VerbatimMatchLength == StringRef::npos)
00897         VerbatimMatchLength = S.size();
00898       // Escape and append the fixed string.
00899       RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
00900       S = S.drop_front(VerbatimMatchLength);
00901     }
00902   }
00903 
00904   return llvm::make_unique<RegexDirective>(
00905       DirectiveLoc, DiagnosticLoc, MatchAnyLine, Text, Min, Max, RegexStr);
00906 }