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