Home | History | Annotate | Download | only in Frontend
      1 //===---- VerifyDiagnosticConsumer.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/VerifyDiagnosticConsumer.h"
     15 #include "clang/Basic/CharInfo.h"
     16 #include "clang/Basic/FileManager.h"
     17 #include "clang/Frontend/FrontendDiagnostic.h"
     18 #include "clang/Frontend/TextDiagnosticBuffer.h"
     19 #include "clang/Lex/HeaderSearch.h"
     20 #include "clang/Lex/Preprocessor.h"
     21 #include "llvm/ADT/SmallString.h"
     22 #include "llvm/Support/Regex.h"
     23 #include "llvm/Support/raw_ostream.h"
     24 
     25 using namespace clang;
     26 typedef VerifyDiagnosticConsumer::Directive Directive;
     27 typedef VerifyDiagnosticConsumer::DirectiveList DirectiveList;
     28 typedef VerifyDiagnosticConsumer::ExpectedData ExpectedData;
     29 
     30 VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags)
     31   : Diags(_Diags),
     32     PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()),
     33     Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0),
     34     LangOpts(0), SrcManager(0), ActiveSourceFiles(0), Status(HasNoDirectives)
     35 {
     36   Diags.takeClient();
     37   if (Diags.hasSourceManager())
     38     setSourceManager(Diags.getSourceManager());
     39 }
     40 
     41 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
     42   assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
     43   assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
     44   SrcManager = 0;
     45   CheckDiagnostics();
     46   Diags.takeClient();
     47   if (OwnsPrimaryClient)
     48     delete PrimaryClient;
     49 }
     50 
     51 #ifndef NDEBUG
     52 namespace {
     53 class VerifyFileTracker : public PPCallbacks {
     54   VerifyDiagnosticConsumer &Verify;
     55   SourceManager &SM;
     56 
     57 public:
     58   VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM)
     59     : Verify(Verify), SM(SM) { }
     60 
     61   /// \brief Hook into the preprocessor and update the list of parsed
     62   /// files when the preprocessor indicates a new file is entered.
     63   virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
     64                            SrcMgr::CharacteristicKind FileType,
     65                            FileID PrevFID) {
     66     Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
     67                                   VerifyDiagnosticConsumer::IsParsed);
     68   }
     69 };
     70 } // End anonymous namespace.
     71 #endif
     72 
     73 // DiagnosticConsumer interface.
     74 
     75 void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
     76                                                const Preprocessor *PP) {
     77   // Attach comment handler on first invocation.
     78   if (++ActiveSourceFiles == 1) {
     79     if (PP) {
     80       CurrentPreprocessor = PP;
     81       this->LangOpts = &LangOpts;
     82       setSourceManager(PP->getSourceManager());
     83       const_cast<Preprocessor*>(PP)->addCommentHandler(this);
     84 #ifndef NDEBUG
     85       // Debug build tracks parsed files.
     86       VerifyFileTracker *V = new VerifyFileTracker(*this, *SrcManager);
     87       const_cast<Preprocessor*>(PP)->addPPCallbacks(V);
     88 #endif
     89     }
     90   }
     91 
     92   assert((!PP || CurrentPreprocessor == PP) && "Preprocessor changed!");
     93   PrimaryClient->BeginSourceFile(LangOpts, PP);
     94 }
     95 
     96 void VerifyDiagnosticConsumer::EndSourceFile() {
     97   assert(ActiveSourceFiles && "No active source files!");
     98   PrimaryClient->EndSourceFile();
     99 
    100   // Detach comment handler once last active source file completed.
    101   if (--ActiveSourceFiles == 0) {
    102     if (CurrentPreprocessor)
    103       const_cast<Preprocessor*>(CurrentPreprocessor)->removeCommentHandler(this);
    104 
    105     // Check diagnostics once last file completed.
    106     CheckDiagnostics();
    107     CurrentPreprocessor = 0;
    108     LangOpts = 0;
    109   }
    110 }
    111 
    112 void VerifyDiagnosticConsumer::HandleDiagnostic(
    113       DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
    114   if (Info.hasSourceManager()) {
    115     // If this diagnostic is for a different source manager, ignore it.
    116     if (SrcManager && &Info.getSourceManager() != SrcManager)
    117       return;
    118 
    119     setSourceManager(Info.getSourceManager());
    120   }
    121 
    122 #ifndef NDEBUG
    123   // Debug build tracks unparsed files for possible
    124   // unparsed expected-* directives.
    125   if (SrcManager) {
    126     SourceLocation Loc = Info.getLocation();
    127     if (Loc.isValid()) {
    128       ParsedStatus PS = IsUnparsed;
    129 
    130       Loc = SrcManager->getExpansionLoc(Loc);
    131       FileID FID = SrcManager->getFileID(Loc);
    132 
    133       const FileEntry *FE = SrcManager->getFileEntryForID(FID);
    134       if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
    135         // If the file is a modules header file it shall not be parsed
    136         // for expected-* directives.
    137         HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
    138         if (HS.findModuleForHeader(FE))
    139           PS = IsUnparsedNoDirectives;
    140       }
    141 
    142       UpdateParsedFileStatus(*SrcManager, FID, PS);
    143     }
    144   }
    145 #endif
    146 
    147   // Send the diagnostic to the buffer, we will check it once we reach the end
    148   // of the source file (or are destructed).
    149   Buffer->HandleDiagnostic(DiagLevel, Info);
    150 }
    151 
    152 //===----------------------------------------------------------------------===//
    153 // Checking diagnostics implementation.
    154 //===----------------------------------------------------------------------===//
    155 
    156 typedef TextDiagnosticBuffer::DiagList DiagList;
    157 typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
    158 
    159 namespace {
    160 
    161 /// StandardDirective - Directive with string matching.
    162 ///
    163 class StandardDirective : public Directive {
    164 public:
    165   StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
    166                     StringRef Text, unsigned Min, unsigned Max)
    167     : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max) { }
    168 
    169   virtual bool isValid(std::string &Error) {
    170     // all strings are considered valid; even empty ones
    171     return true;
    172   }
    173 
    174   virtual bool match(StringRef S) {
    175     return S.find(Text) != StringRef::npos;
    176   }
    177 };
    178 
    179 /// RegexDirective - Directive with regular-expression matching.
    180 ///
    181 class RegexDirective : public Directive {
    182 public:
    183   RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
    184                  StringRef Text, unsigned Min, unsigned Max)
    185     : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), Regex(Text) { }
    186 
    187   virtual bool isValid(std::string &Error) {
    188     if (Regex.isValid(Error))
    189       return true;
    190     return false;
    191   }
    192 
    193   virtual bool match(StringRef S) {
    194     return Regex.match(S);
    195   }
    196 
    197 private:
    198   llvm::Regex Regex;
    199 };
    200 
    201 class ParseHelper
    202 {
    203 public:
    204   ParseHelper(StringRef S)
    205     : Begin(S.begin()), End(S.end()), C(Begin), P(Begin), PEnd(NULL) { }
    206 
    207   // Return true if string literal is next.
    208   bool Next(StringRef S) {
    209     P = C;
    210     PEnd = C + S.size();
    211     if (PEnd > End)
    212       return false;
    213     return !memcmp(P, S.data(), S.size());
    214   }
    215 
    216   // Return true if number is next.
    217   // Output N only if number is next.
    218   bool Next(unsigned &N) {
    219     unsigned TMP = 0;
    220     P = C;
    221     for (; P < End && P[0] >= '0' && P[0] <= '9'; ++P) {
    222       TMP *= 10;
    223       TMP += P[0] - '0';
    224     }
    225     if (P == C)
    226       return false;
    227     PEnd = P;
    228     N = TMP;
    229     return true;
    230   }
    231 
    232   // Return true if string literal is found.
    233   // When true, P marks begin-position of S in content.
    234   bool Search(StringRef S, bool EnsureStartOfWord = false) {
    235     do {
    236       P = std::search(C, End, S.begin(), S.end());
    237       PEnd = P + S.size();
    238       if (P == End)
    239         break;
    240       if (!EnsureStartOfWord
    241             // Check if string literal starts a new word.
    242             || P == Begin || isWhitespace(P[-1])
    243             // Or it could be preceeded by the start of a comment.
    244             || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
    245                                 &&  P[-2] == '/'))
    246         return true;
    247       // Otherwise, skip and search again.
    248     } while (Advance());
    249     return false;
    250   }
    251 
    252   // Advance 1-past previous next/search.
    253   // Behavior is undefined if previous next/search failed.
    254   bool Advance() {
    255     C = PEnd;
    256     return C < End;
    257   }
    258 
    259   // Skip zero or more whitespace.
    260   void SkipWhitespace() {
    261     for (; C < End && isWhitespace(*C); ++C)
    262       ;
    263   }
    264 
    265   // Return true if EOF reached.
    266   bool Done() {
    267     return !(C < End);
    268   }
    269 
    270   const char * const Begin; // beginning of expected content
    271   const char * const End;   // end of expected content (1-past)
    272   const char *C;            // position of next char in content
    273   const char *P;
    274 
    275 private:
    276   const char *PEnd; // previous next/search subject end (1-past)
    277 };
    278 
    279 } // namespace anonymous
    280 
    281 /// ParseDirective - Go through the comment and see if it indicates expected
    282 /// diagnostics. If so, then put them in the appropriate directive list.
    283 ///
    284 /// Returns true if any valid directives were found.
    285 static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
    286                            Preprocessor *PP, SourceLocation Pos,
    287                            VerifyDiagnosticConsumer::DirectiveStatus &Status) {
    288   DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();
    289 
    290   // A single comment may contain multiple directives.
    291   bool FoundDirective = false;
    292   for (ParseHelper PH(S); !PH.Done();) {
    293     // Search for token: expected
    294     if (!PH.Search("expected", true))
    295       break;
    296     PH.Advance();
    297 
    298     // Next token: -
    299     if (!PH.Next("-"))
    300       continue;
    301     PH.Advance();
    302 
    303     // Next token: { error | warning | note }
    304     DirectiveList* DL = NULL;
    305     if (PH.Next("error"))
    306       DL = ED ? &ED->Errors : NULL;
    307     else if (PH.Next("warning"))
    308       DL = ED ? &ED->Warnings : NULL;
    309     else if (PH.Next("note"))
    310       DL = ED ? &ED->Notes : NULL;
    311     else if (PH.Next("no-diagnostics")) {
    312       if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
    313         Diags.Report(Pos, diag::err_verify_invalid_no_diags)
    314           << /*IsExpectedNoDiagnostics=*/true;
    315       else
    316         Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
    317       continue;
    318     } else
    319       continue;
    320     PH.Advance();
    321 
    322     if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
    323       Diags.Report(Pos, diag::err_verify_invalid_no_diags)
    324         << /*IsExpectedNoDiagnostics=*/false;
    325       continue;
    326     }
    327     Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;
    328 
    329     // If a directive has been found but we're not interested
    330     // in storing the directive information, return now.
    331     if (!DL)
    332       return true;
    333 
    334     // Default directive kind.
    335     bool RegexKind = false;
    336     const char* KindStr = "string";
    337 
    338     // Next optional token: -
    339     if (PH.Next("-re")) {
    340       PH.Advance();
    341       RegexKind = true;
    342       KindStr = "regex";
    343     }
    344 
    345     // Next optional token: @
    346     SourceLocation ExpectedLoc;
    347     if (!PH.Next("@")) {
    348       ExpectedLoc = Pos;
    349     } else {
    350       PH.Advance();
    351       unsigned Line = 0;
    352       bool FoundPlus = PH.Next("+");
    353       if (FoundPlus || PH.Next("-")) {
    354         // Relative to current line.
    355         PH.Advance();
    356         bool Invalid = false;
    357         unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
    358         if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
    359           if (FoundPlus) ExpectedLine += Line;
    360           else ExpectedLine -= Line;
    361           ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
    362         }
    363       } else if (PH.Next(Line)) {
    364         // Absolute line number.
    365         if (Line > 0)
    366           ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
    367       } else if (PP && PH.Search(":")) {
    368         // Specific source file.
    369         StringRef Filename(PH.C, PH.P-PH.C);
    370         PH.Advance();
    371 
    372         // Lookup file via Preprocessor, like a #include.
    373         const DirectoryLookup *CurDir;
    374         const FileEntry *FE = PP->LookupFile(Pos, Filename, false, NULL, CurDir,
    375                                              NULL, NULL, 0);
    376         if (!FE) {
    377           Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
    378                        diag::err_verify_missing_file) << Filename << KindStr;
    379           continue;
    380         }
    381 
    382         if (SM.translateFile(FE).isInvalid())
    383           SM.createFileID(FE, Pos, SrcMgr::C_User);
    384 
    385         if (PH.Next(Line) && Line > 0)
    386           ExpectedLoc = SM.translateFileLineCol(FE, Line, 1);
    387       }
    388 
    389       if (ExpectedLoc.isInvalid()) {
    390         Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
    391                      diag::err_verify_missing_line) << KindStr;
    392         continue;
    393       }
    394       PH.Advance();
    395     }
    396 
    397     // Skip optional whitespace.
    398     PH.SkipWhitespace();
    399 
    400     // Next optional token: positive integer or a '+'.
    401     unsigned Min = 1;
    402     unsigned Max = 1;
    403     if (PH.Next(Min)) {
    404       PH.Advance();
    405       // A positive integer can be followed by a '+' meaning min
    406       // or more, or by a '-' meaning a range from min to max.
    407       if (PH.Next("+")) {
    408         Max = Directive::MaxCount;
    409         PH.Advance();
    410       } else if (PH.Next("-")) {
    411         PH.Advance();
    412         if (!PH.Next(Max) || Max < Min) {
    413           Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
    414                        diag::err_verify_invalid_range) << KindStr;
    415           continue;
    416         }
    417         PH.Advance();
    418       } else {
    419         Max = Min;
    420       }
    421     } else if (PH.Next("+")) {
    422       // '+' on its own means "1 or more".
    423       Max = Directive::MaxCount;
    424       PH.Advance();
    425     }
    426 
    427     // Skip optional whitespace.
    428     PH.SkipWhitespace();
    429 
    430     // Next token: {{
    431     if (!PH.Next("{{")) {
    432       Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
    433                    diag::err_verify_missing_start) << KindStr;
    434       continue;
    435     }
    436     PH.Advance();
    437     const char* const ContentBegin = PH.C; // mark content begin
    438 
    439     // Search for token: }}
    440     if (!PH.Search("}}")) {
    441       Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
    442                    diag::err_verify_missing_end) << KindStr;
    443       continue;
    444     }
    445     const char* const ContentEnd = PH.P; // mark content end
    446     PH.Advance();
    447 
    448     // Build directive text; convert \n to newlines.
    449     std::string Text;
    450     StringRef NewlineStr = "\\n";
    451     StringRef Content(ContentBegin, ContentEnd-ContentBegin);
    452     size_t CPos = 0;
    453     size_t FPos;
    454     while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
    455       Text += Content.substr(CPos, FPos-CPos);
    456       Text += '\n';
    457       CPos = FPos + NewlineStr.size();
    458     }
    459     if (Text.empty())
    460       Text.assign(ContentBegin, ContentEnd);
    461 
    462     // Construct new directive.
    463     Directive *D = Directive::create(RegexKind, Pos, ExpectedLoc, Text,
    464                                      Min, Max);
    465     std::string Error;
    466     if (D->isValid(Error)) {
    467       DL->push_back(D);
    468       FoundDirective = true;
    469     } else {
    470       Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
    471                    diag::err_verify_invalid_content)
    472         << KindStr << Error;
    473     }
    474   }
    475 
    476   return FoundDirective;
    477 }
    478 
    479 /// HandleComment - Hook into the preprocessor and extract comments containing
    480 ///  expected errors and warnings.
    481 bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
    482                                              SourceRange Comment) {
    483   SourceManager &SM = PP.getSourceManager();
    484 
    485   // If this comment is for a different source manager, ignore it.
    486   if (SrcManager && &SM != SrcManager)
    487     return false;
    488 
    489   SourceLocation CommentBegin = Comment.getBegin();
    490 
    491   const char *CommentRaw = SM.getCharacterData(CommentBegin);
    492   StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
    493 
    494   if (C.empty())
    495     return false;
    496 
    497   // Fold any "\<EOL>" sequences
    498   size_t loc = C.find('\\');
    499   if (loc == StringRef::npos) {
    500     ParseDirective(C, &ED, SM, &PP, CommentBegin, Status);
    501     return false;
    502   }
    503 
    504   std::string C2;
    505   C2.reserve(C.size());
    506 
    507   for (size_t last = 0;; loc = C.find('\\', last)) {
    508     if (loc == StringRef::npos || loc == C.size()) {
    509       C2 += C.substr(last);
    510       break;
    511     }
    512     C2 += C.substr(last, loc-last);
    513     last = loc + 1;
    514 
    515     if (C[last] == '\n' || C[last] == '\r') {
    516       ++last;
    517 
    518       // Escape \r\n  or \n\r, but not \n\n.
    519       if (last < C.size())
    520         if (C[last] == '\n' || C[last] == '\r')
    521           if (C[last] != C[last-1])
    522             ++last;
    523     } else {
    524       // This was just a normal backslash.
    525       C2 += '\\';
    526     }
    527   }
    528 
    529   if (!C2.empty())
    530     ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status);
    531   return false;
    532 }
    533 
    534 #ifndef NDEBUG
    535 /// \brief Lex the specified source file to determine whether it contains
    536 /// any expected-* directives.  As a Lexer is used rather than a full-blown
    537 /// Preprocessor, directives inside skipped #if blocks will still be found.
    538 ///
    539 /// \return true if any directives were found.
    540 static bool findDirectives(SourceManager &SM, FileID FID,
    541                            const LangOptions &LangOpts) {
    542   // Create a raw lexer to pull all the comments out of FID.
    543   if (FID.isInvalid())
    544     return false;
    545 
    546   // Create a lexer to lex all the tokens of the main file in raw mode.
    547   const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
    548   Lexer RawLex(FID, FromFile, SM, LangOpts);
    549 
    550   // Return comments as tokens, this is how we find expected diagnostics.
    551   RawLex.SetCommentRetentionState(true);
    552 
    553   Token Tok;
    554   Tok.setKind(tok::comment);
    555   VerifyDiagnosticConsumer::DirectiveStatus Status =
    556     VerifyDiagnosticConsumer::HasNoDirectives;
    557   while (Tok.isNot(tok::eof)) {
    558     RawLex.Lex(Tok);
    559     if (!Tok.is(tok::comment)) continue;
    560 
    561     std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
    562     if (Comment.empty()) continue;
    563 
    564     // Find first directive.
    565     if (ParseDirective(Comment, 0, SM, 0, Tok.getLocation(), Status))
    566       return true;
    567   }
    568   return false;
    569 }
    570 #endif // !NDEBUG
    571 
    572 /// \brief Takes a list of diagnostics that have been generated but not matched
    573 /// by an expected-* directive and produces a diagnostic to the user from this.
    574 static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
    575                                 const_diag_iterator diag_begin,
    576                                 const_diag_iterator diag_end,
    577                                 const char *Kind) {
    578   if (diag_begin == diag_end) return 0;
    579 
    580   SmallString<256> Fmt;
    581   llvm::raw_svector_ostream OS(Fmt);
    582   for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
    583     if (I->first.isInvalid() || !SourceMgr)
    584       OS << "\n  (frontend)";
    585     else {
    586       OS << "\n ";
    587       if (const FileEntry *File = SourceMgr->getFileEntryForID(
    588                                                 SourceMgr->getFileID(I->first)))
    589         OS << " File " << File->getName();
    590       OS << " Line " << SourceMgr->getPresumedLineNumber(I->first);
    591     }
    592     OS << ": " << I->second;
    593   }
    594 
    595   Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
    596     << Kind << /*Unexpected=*/true << OS.str();
    597   return std::distance(diag_begin, diag_end);
    598 }
    599 
    600 /// \brief Takes a list of diagnostics that were expected to have been generated
    601 /// but were not and produces a diagnostic to the user from this.
    602 static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
    603                               DirectiveList &DL, const char *Kind) {
    604   if (DL.empty())
    605     return 0;
    606 
    607   SmallString<256> Fmt;
    608   llvm::raw_svector_ostream OS(Fmt);
    609   for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
    610     Directive &D = **I;
    611     OS << "\n  File " << SourceMgr.getFilename(D.DiagnosticLoc)
    612           << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
    613     if (D.DirectiveLoc != D.DiagnosticLoc)
    614       OS << " (directive at "
    615          << SourceMgr.getFilename(D.DirectiveLoc) << ':'
    616          << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ')';
    617     OS << ": " << D.Text;
    618   }
    619 
    620   Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
    621     << Kind << /*Unexpected=*/false << OS.str();
    622   return DL.size();
    623 }
    624 
    625 /// \brief Determine whether two source locations come from the same file.
    626 static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
    627                            SourceLocation DiagnosticLoc) {
    628   while (DiagnosticLoc.isMacroID())
    629     DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);
    630 
    631   if (SM.isFromSameFile(DirectiveLoc, DiagnosticLoc))
    632     return true;
    633 
    634   const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
    635   if (!DiagFile && SM.isFromMainFile(DirectiveLoc))
    636     return true;
    637 
    638   return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
    639 }
    640 
    641 /// CheckLists - Compare expected to seen diagnostic lists and return the
    642 /// the difference between them.
    643 ///
    644 static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
    645                            const char *Label,
    646                            DirectiveList &Left,
    647                            const_diag_iterator d2_begin,
    648                            const_diag_iterator d2_end) {
    649   DirectiveList LeftOnly;
    650   DiagList Right(d2_begin, d2_end);
    651 
    652   for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
    653     Directive& D = **I;
    654     unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
    655 
    656     for (unsigned i = 0; i < D.Max; ++i) {
    657       DiagList::iterator II, IE;
    658       for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
    659         unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
    660         if (LineNo1 != LineNo2)
    661           continue;
    662 
    663         if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
    664           continue;
    665 
    666         const std::string &RightText = II->second;
    667         if (D.match(RightText))
    668           break;
    669       }
    670       if (II == IE) {
    671         // Not found.
    672         if (i >= D.Min) break;
    673         LeftOnly.push_back(*I);
    674       } else {
    675         // Found. The same cannot be found twice.
    676         Right.erase(II);
    677       }
    678     }
    679   }
    680   // Now all that's left in Right are those that were not matched.
    681   unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
    682   num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
    683   return num;
    684 }
    685 
    686 /// CheckResults - This compares the expected results to those that
    687 /// were actually reported. It emits any discrepencies. Return "true" if there
    688 /// were problems. Return "false" otherwise.
    689 ///
    690 static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
    691                              const TextDiagnosticBuffer &Buffer,
    692                              ExpectedData &ED) {
    693   // We want to capture the delta between what was expected and what was
    694   // seen.
    695   //
    696   //   Expected \ Seen - set expected but not seen
    697   //   Seen \ Expected - set seen but not expected
    698   unsigned NumProblems = 0;
    699 
    700   // See if there are error mismatches.
    701   NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
    702                             Buffer.err_begin(), Buffer.err_end());
    703 
    704   // See if there are warning mismatches.
    705   NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
    706                             Buffer.warn_begin(), Buffer.warn_end());
    707 
    708   // See if there are note mismatches.
    709   NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
    710                             Buffer.note_begin(), Buffer.note_end());
    711 
    712   return NumProblems;
    713 }
    714 
    715 void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
    716                                                       FileID FID,
    717                                                       ParsedStatus PS) {
    718   // Check SourceManager hasn't changed.
    719   setSourceManager(SM);
    720 
    721 #ifndef NDEBUG
    722   if (FID.isInvalid())
    723     return;
    724 
    725   const FileEntry *FE = SM.getFileEntryForID(FID);
    726 
    727   if (PS == IsParsed) {
    728     // Move the FileID from the unparsed set to the parsed set.
    729     UnparsedFiles.erase(FID);
    730     ParsedFiles.insert(std::make_pair(FID, FE));
    731   } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
    732     // Add the FileID to the unparsed set if we haven't seen it before.
    733 
    734     // Check for directives.
    735     bool FoundDirectives;
    736     if (PS == IsUnparsedNoDirectives)
    737       FoundDirectives = false;
    738     else
    739       FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
    740 
    741     // Add the FileID to the unparsed set.
    742     UnparsedFiles.insert(std::make_pair(FID,
    743                                       UnparsedFileStatus(FE, FoundDirectives)));
    744   }
    745 #endif
    746 }
    747 
    748 void VerifyDiagnosticConsumer::CheckDiagnostics() {
    749   // Ensure any diagnostics go to the primary client.
    750   bool OwnsCurClient = Diags.ownsClient();
    751   DiagnosticConsumer *CurClient = Diags.takeClient();
    752   Diags.setClient(PrimaryClient, false);
    753 
    754 #ifndef NDEBUG
    755   // In a debug build, scan through any files that may have been missed
    756   // during parsing and issue a fatal error if directives are contained
    757   // within these files.  If a fatal error occurs, this suggests that
    758   // this file is being parsed separately from the main file, in which
    759   // case consider moving the directives to the correct place, if this
    760   // is applicable.
    761   if (UnparsedFiles.size() > 0) {
    762     // Generate a cache of parsed FileEntry pointers for alias lookups.
    763     llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
    764     for (ParsedFilesMap::iterator I = ParsedFiles.begin(),
    765                                 End = ParsedFiles.end(); I != End; ++I) {
    766       if (const FileEntry *FE = I->second)
    767         ParsedFileCache.insert(FE);
    768     }
    769 
    770     // Iterate through list of unparsed files.
    771     for (UnparsedFilesMap::iterator I = UnparsedFiles.begin(),
    772                                   End = UnparsedFiles.end(); I != End; ++I) {
    773       const UnparsedFileStatus &Status = I->second;
    774       const FileEntry *FE = Status.getFile();
    775 
    776       // Skip files that have been parsed via an alias.
    777       if (FE && ParsedFileCache.count(FE))
    778         continue;
    779 
    780       // Report a fatal error if this file contained directives.
    781       if (Status.foundDirectives()) {
    782         llvm::report_fatal_error(Twine("-verify directives found after rather"
    783                                        " than during normal parsing of ",
    784                                  StringRef(FE ? FE->getName() : "(unknown)")));
    785       }
    786     }
    787 
    788     // UnparsedFiles has been processed now, so clear it.
    789     UnparsedFiles.clear();
    790   }
    791 #endif // !NDEBUG
    792 
    793   if (SrcManager) {
    794     // Produce an error if no expected-* directives could be found in the
    795     // source file(s) processed.
    796     if (Status == HasNoDirectives) {
    797       Diags.Report(diag::err_verify_no_directives).setForceEmit();
    798       ++NumErrors;
    799       Status = HasNoDirectivesReported;
    800     }
    801 
    802     // Check that the expected diagnostics occurred.
    803     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
    804   } else {
    805     NumErrors += (PrintUnexpected(Diags, 0, Buffer->err_begin(),
    806                                   Buffer->err_end(), "error") +
    807                   PrintUnexpected(Diags, 0, Buffer->warn_begin(),
    808                                   Buffer->warn_end(), "warn") +
    809                   PrintUnexpected(Diags, 0, Buffer->note_begin(),
    810                                   Buffer->note_end(), "note"));
    811   }
    812 
    813   Diags.takeClient();
    814   Diags.setClient(CurClient, OwnsCurClient);
    815 
    816   // Reset the buffer, we have processed all the diagnostics in it.
    817   Buffer.reset(new TextDiagnosticBuffer());
    818   ED.Errors.clear();
    819   ED.Warnings.clear();
    820   ED.Notes.clear();
    821 }
    822 
    823 Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
    824                              SourceLocation DiagnosticLoc, StringRef Text,
    825                              unsigned Min, unsigned Max) {
    826   if (RegexKind)
    827     return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
    828   return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
    829 }
    830