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