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