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(nullptr),
34     LangOpts(nullptr), SrcManager(nullptr), ActiveSourceFiles(0),
35     Status(HasNoDirectives)
36 {
37   Diags.takeClient();
38   if (Diags.hasSourceManager())
39     setSourceManager(Diags.getSourceManager());
40 }
41 
42 VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() {
43   assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
44   assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
45   SrcManager = nullptr;
46   CheckDiagnostics();
47   Diags.takeClient();
48   if (OwnsPrimaryClient)
49     delete PrimaryClient;
50 }
51 
52 #ifndef NDEBUG
53 namespace {
54 class VerifyFileTracker : public PPCallbacks {
55   VerifyDiagnosticConsumer &Verify;
56   SourceManager &SM;
57 
58 public:
59   VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM)
60     : Verify(Verify), SM(SM) { }
61 
62   /// \brief Hook into the preprocessor and update the list of parsed
63   /// files when the preprocessor indicates a new file is entered.
64   virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
65                            SrcMgr::CharacteristicKind FileType,
66                            FileID PrevFID) {
67     Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
68                                   VerifyDiagnosticConsumer::IsParsed);
69   }
70 };
71 } // End anonymous namespace.
72 #endif
73 
74 // DiagnosticConsumer interface.
75 
76 void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts,
77                                                const Preprocessor *PP) {
78   // Attach comment handler on first invocation.
79   if (++ActiveSourceFiles == 1) {
80     if (PP) {
81       CurrentPreprocessor = PP;
82       this->LangOpts = &LangOpts;
83       setSourceManager(PP->getSourceManager());
84       const_cast<Preprocessor*>(PP)->addCommentHandler(this);
85 #ifndef NDEBUG
86       // Debug build tracks parsed files.
87       VerifyFileTracker *V = new VerifyFileTracker(*this, *SrcManager);
88       const_cast<Preprocessor*>(PP)->addPPCallbacks(V);
89 #endif
90     }
91   }
92 
93   assert((!PP || CurrentPreprocessor == PP) && "Preprocessor changed!");
94   PrimaryClient->BeginSourceFile(LangOpts, PP);
95 }
96 
97 void VerifyDiagnosticConsumer::EndSourceFile() {
98   assert(ActiveSourceFiles && "No active source files!");
99   PrimaryClient->EndSourceFile();
100 
101   // Detach comment handler once last active source file completed.
102   if (--ActiveSourceFiles == 0) {
103     if (CurrentPreprocessor)
104       const_cast<Preprocessor*>(CurrentPreprocessor)->removeCommentHandler(this);
105 
106     // Check diagnostics once last file completed.
107     CheckDiagnostics();
108     CurrentPreprocessor = nullptr;
109     LangOpts = nullptr;
110   }
111 }
112 
113 void VerifyDiagnosticConsumer::HandleDiagnostic(
114       DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
115   if (Info.hasSourceManager()) {
116     // If this diagnostic is for a different source manager, ignore it.
117     if (SrcManager && &Info.getSourceManager() != SrcManager)
118       return;
119 
120     setSourceManager(Info.getSourceManager());
121   }
122 
123 #ifndef NDEBUG
124   // Debug build tracks unparsed files for possible
125   // unparsed expected-* directives.
126   if (SrcManager) {
127     SourceLocation Loc = Info.getLocation();
128     if (Loc.isValid()) {
129       ParsedStatus PS = IsUnparsed;
130 
131       Loc = SrcManager->getExpansionLoc(Loc);
132       FileID FID = SrcManager->getFileID(Loc);
133 
134       const FileEntry *FE = SrcManager->getFileEntryForID(FID);
135       if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
136         // If the file is a modules header file it shall not be parsed
137         // for expected-* directives.
138         HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
139         if (HS.findModuleForHeader(FE))
140           PS = IsUnparsedNoDirectives;
141       }
142 
143       UpdateParsedFileStatus(*SrcManager, FID, PS);
144     }
145   }
146 #endif
147 
148   // Send the diagnostic to the buffer, we will check it once we reach the end
149   // of the source file (or are destructed).
150   Buffer->HandleDiagnostic(DiagLevel, Info);
151 }
152 
153 //===----------------------------------------------------------------------===//
154 // Checking diagnostics implementation.
155 //===----------------------------------------------------------------------===//
156 
157 typedef TextDiagnosticBuffer::DiagList DiagList;
158 typedef TextDiagnosticBuffer::const_iterator const_diag_iterator;
159 
160 namespace {
161 
162 /// StandardDirective - Directive with string matching.
163 ///
164 class StandardDirective : public Directive {
165 public:
166   StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
167                     StringRef Text, unsigned Min, unsigned Max)
168     : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max) { }
169 
170   bool isValid(std::string &Error) override {
171     // all strings are considered valid; even empty ones
172     return true;
173   }
174 
175   bool match(StringRef S) override {
176     return S.find(Text) != StringRef::npos;
177   }
178 };
179 
180 /// RegexDirective - Directive with regular-expression matching.
181 ///
182 class RegexDirective : public Directive {
183 public:
184   RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
185                  StringRef Text, unsigned Min, unsigned Max, StringRef RegexStr)
186     : Directive(DirectiveLoc, DiagnosticLoc, Text, Min, Max), 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     if (!PH.Next("@")) {
375       ExpectedLoc = Pos;
376     } else {
377       PH.Advance();
378       unsigned Line = 0;
379       bool FoundPlus = PH.Next("+");
380       if (FoundPlus || PH.Next("-")) {
381         // Relative to current line.
382         PH.Advance();
383         bool Invalid = false;
384         unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
385         if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
386           if (FoundPlus) ExpectedLine += Line;
387           else ExpectedLine -= Line;
388           ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
389         }
390       } else if (PH.Next(Line)) {
391         // Absolute line number.
392         if (Line > 0)
393           ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
394       } else if (PP && PH.Search(":")) {
395         // Specific source file.
396         StringRef Filename(PH.C, PH.P-PH.C);
397         PH.Advance();
398 
399         // Lookup file via Preprocessor, like a #include.
400         const DirectoryLookup *CurDir;
401         const FileEntry *FE = PP->LookupFile(Pos, Filename, false, nullptr,
402                                              CurDir, 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       }
415 
416       if (ExpectedLoc.isInvalid()) {
417         Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
418                      diag::err_verify_missing_line) << KindStr;
419         continue;
420       }
421       PH.Advance();
422     }
423 
424     // Skip optional whitespace.
425     PH.SkipWhitespace();
426 
427     // Next optional token: positive integer or a '+'.
428     unsigned Min = 1;
429     unsigned Max = 1;
430     if (PH.Next(Min)) {
431       PH.Advance();
432       // A positive integer can be followed by a '+' meaning min
433       // or more, or by a '-' meaning a range from min to max.
434       if (PH.Next("+")) {
435         Max = Directive::MaxCount;
436         PH.Advance();
437       } else if (PH.Next("-")) {
438         PH.Advance();
439         if (!PH.Next(Max) || Max < Min) {
440           Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
441                        diag::err_verify_invalid_range) << KindStr;
442           continue;
443         }
444         PH.Advance();
445       } else {
446         Max = Min;
447       }
448     } else if (PH.Next("+")) {
449       // '+' on its own means "1 or more".
450       Max = Directive::MaxCount;
451       PH.Advance();
452     }
453 
454     // Skip optional whitespace.
455     PH.SkipWhitespace();
456 
457     // Next token: {{
458     if (!PH.Next("{{")) {
459       Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
460                    diag::err_verify_missing_start) << KindStr;
461       continue;
462     }
463     PH.Advance();
464     const char* const ContentBegin = PH.C; // mark content begin
465 
466     // Search for token: }}
467     if (!PH.SearchClosingBrace("{{", "}}")) {
468       Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
469                    diag::err_verify_missing_end) << KindStr;
470       continue;
471     }
472     const char* const ContentEnd = PH.P; // mark content end
473     PH.Advance();
474 
475     // Build directive text; convert \n to newlines.
476     std::string Text;
477     StringRef NewlineStr = "\\n";
478     StringRef Content(ContentBegin, ContentEnd-ContentBegin);
479     size_t CPos = 0;
480     size_t FPos;
481     while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
482       Text += Content.substr(CPos, FPos-CPos);
483       Text += '\n';
484       CPos = FPos + NewlineStr.size();
485     }
486     if (Text.empty())
487       Text.assign(ContentBegin, ContentEnd);
488 
489     // Check that regex directives contain at least one regex.
490     if (RegexKind && Text.find("{{") == StringRef::npos) {
491       Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
492                    diag::err_verify_missing_regex) << Text;
493       return false;
494     }
495 
496     // Construct new directive.
497     std::unique_ptr<Directive> D(
498         Directive::create(RegexKind, Pos, ExpectedLoc, Text, Min, Max));
499 
500     std::string Error;
501     if (D->isValid(Error)) {
502       DL->push_back(D.release());
503       FoundDirective = true;
504     } else {
505       Diags.Report(Pos.getLocWithOffset(ContentBegin-PH.Begin),
506                    diag::err_verify_invalid_content)
507         << KindStr << Error;
508     }
509   }
510 
511   return FoundDirective;
512 }
513 
514 /// HandleComment - Hook into the preprocessor and extract comments containing
515 ///  expected errors and warnings.
516 bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP,
517                                              SourceRange Comment) {
518   SourceManager &SM = PP.getSourceManager();
519 
520   // If this comment is for a different source manager, ignore it.
521   if (SrcManager && &SM != SrcManager)
522     return false;
523 
524   SourceLocation CommentBegin = Comment.getBegin();
525 
526   const char *CommentRaw = SM.getCharacterData(CommentBegin);
527   StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
528 
529   if (C.empty())
530     return false;
531 
532   // Fold any "\<EOL>" sequences
533   size_t loc = C.find('\\');
534   if (loc == StringRef::npos) {
535     ParseDirective(C, &ED, SM, &PP, CommentBegin, Status);
536     return false;
537   }
538 
539   std::string C2;
540   C2.reserve(C.size());
541 
542   for (size_t last = 0;; loc = C.find('\\', last)) {
543     if (loc == StringRef::npos || loc == C.size()) {
544       C2 += C.substr(last);
545       break;
546     }
547     C2 += C.substr(last, loc-last);
548     last = loc + 1;
549 
550     if (C[last] == '\n' || C[last] == '\r') {
551       ++last;
552 
553       // Escape \r\n  or \n\r, but not \n\n.
554       if (last < C.size())
555         if (C[last] == '\n' || C[last] == '\r')
556           if (C[last] != C[last-1])
557             ++last;
558     } else {
559       // This was just a normal backslash.
560       C2 += '\\';
561     }
562   }
563 
564   if (!C2.empty())
565     ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status);
566   return false;
567 }
568 
569 #ifndef NDEBUG
570 /// \brief Lex the specified source file to determine whether it contains
571 /// any expected-* directives.  As a Lexer is used rather than a full-blown
572 /// Preprocessor, directives inside skipped #if blocks will still be found.
573 ///
574 /// \return true if any directives were found.
575 static bool findDirectives(SourceManager &SM, FileID FID,
576                            const LangOptions &LangOpts) {
577   // Create a raw lexer to pull all the comments out of FID.
578   if (FID.isInvalid())
579     return false;
580 
581   // Create a lexer to lex all the tokens of the main file in raw mode.
582   const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
583   Lexer RawLex(FID, FromFile, SM, LangOpts);
584 
585   // Return comments as tokens, this is how we find expected diagnostics.
586   RawLex.SetCommentRetentionState(true);
587 
588   Token Tok;
589   Tok.setKind(tok::comment);
590   VerifyDiagnosticConsumer::DirectiveStatus Status =
591     VerifyDiagnosticConsumer::HasNoDirectives;
592   while (Tok.isNot(tok::eof)) {
593     RawLex.LexFromRawLexer(Tok);
594     if (!Tok.is(tok::comment)) continue;
595 
596     std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
597     if (Comment.empty()) continue;
598 
599     // Find first directive.
600     if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(),
601                        Status))
602       return true;
603   }
604   return false;
605 }
606 #endif // !NDEBUG
607 
608 /// \brief Takes a list of diagnostics that have been generated but not matched
609 /// by an expected-* directive and produces a diagnostic to the user from this.
610 static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
611                                 const_diag_iterator diag_begin,
612                                 const_diag_iterator diag_end,
613                                 const char *Kind) {
614   if (diag_begin == diag_end) return 0;
615 
616   SmallString<256> Fmt;
617   llvm::raw_svector_ostream OS(Fmt);
618   for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
619     if (I->first.isInvalid() || !SourceMgr)
620       OS << "\n  (frontend)";
621     else {
622       OS << "\n ";
623       if (const FileEntry *File = SourceMgr->getFileEntryForID(
624                                                 SourceMgr->getFileID(I->first)))
625         OS << " File " << File->getName();
626       OS << " Line " << SourceMgr->getPresumedLineNumber(I->first);
627     }
628     OS << ": " << I->second;
629   }
630 
631   Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
632     << Kind << /*Unexpected=*/true << OS.str();
633   return std::distance(diag_begin, diag_end);
634 }
635 
636 /// \brief Takes a list of diagnostics that were expected to have been generated
637 /// but were not and produces a diagnostic to the user from this.
638 static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
639                               DirectiveList &DL, const char *Kind) {
640   if (DL.empty())
641     return 0;
642 
643   SmallString<256> Fmt;
644   llvm::raw_svector_ostream OS(Fmt);
645   for (DirectiveList::iterator I = DL.begin(), E = DL.end(); I != E; ++I) {
646     Directive &D = **I;
647     OS << "\n  File " << SourceMgr.getFilename(D.DiagnosticLoc)
648           << " Line " << SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
649     if (D.DirectiveLoc != D.DiagnosticLoc)
650       OS << " (directive at "
651          << SourceMgr.getFilename(D.DirectiveLoc) << ':'
652          << SourceMgr.getPresumedLineNumber(D.DirectiveLoc) << ')';
653     OS << ": " << D.Text;
654   }
655 
656   Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
657     << Kind << /*Unexpected=*/false << OS.str();
658   return DL.size();
659 }
660 
661 /// \brief Determine whether two source locations come from the same file.
662 static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
663                            SourceLocation DiagnosticLoc) {
664   while (DiagnosticLoc.isMacroID())
665     DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);
666 
667   if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
668     return true;
669 
670   const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
671   if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
672     return true;
673 
674   return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
675 }
676 
677 /// CheckLists - Compare expected to seen diagnostic lists and return the
678 /// the difference between them.
679 ///
680 static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
681                            const char *Label,
682                            DirectiveList &Left,
683                            const_diag_iterator d2_begin,
684                            const_diag_iterator d2_end) {
685   DirectiveList LeftOnly;
686   DiagList Right(d2_begin, d2_end);
687 
688   for (DirectiveList::iterator I = Left.begin(), E = Left.end(); I != E; ++I) {
689     Directive& D = **I;
690     unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
691 
692     for (unsigned i = 0; i < D.Max; ++i) {
693       DiagList::iterator II, IE;
694       for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
695         unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
696         if (LineNo1 != LineNo2)
697           continue;
698 
699         if (!IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
700           continue;
701 
702         const std::string &RightText = II->second;
703         if (D.match(RightText))
704           break;
705       }
706       if (II == IE) {
707         // Not found.
708         if (i >= D.Min) break;
709         LeftOnly.push_back(*I);
710       } else {
711         // Found. The same cannot be found twice.
712         Right.erase(II);
713       }
714     }
715   }
716   // Now all that's left in Right are those that were not matched.
717   unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
718   num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
719   return num;
720 }
721 
722 /// CheckResults - This compares the expected results to those that
723 /// were actually reported. It emits any discrepencies. Return "true" if there
724 /// were problems. Return "false" otherwise.
725 ///
726 static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
727                              const TextDiagnosticBuffer &Buffer,
728                              ExpectedData &ED) {
729   // We want to capture the delta between what was expected and what was
730   // seen.
731   //
732   //   Expected \ Seen - set expected but not seen
733   //   Seen \ Expected - set seen but not expected
734   unsigned NumProblems = 0;
735 
736   // See if there are error mismatches.
737   NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
738                             Buffer.err_begin(), Buffer.err_end());
739 
740   // See if there are warning mismatches.
741   NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
742                             Buffer.warn_begin(), Buffer.warn_end());
743 
744   // See if there are remark mismatches.
745   NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,
746                             Buffer.remark_begin(), Buffer.remark_end());
747 
748   // See if there are note mismatches.
749   NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
750                             Buffer.note_begin(), Buffer.note_end());
751 
752   return NumProblems;
753 }
754 
755 void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM,
756                                                       FileID FID,
757                                                       ParsedStatus PS) {
758   // Check SourceManager hasn't changed.
759   setSourceManager(SM);
760 
761 #ifndef NDEBUG
762   if (FID.isInvalid())
763     return;
764 
765   const FileEntry *FE = SM.getFileEntryForID(FID);
766 
767   if (PS == IsParsed) {
768     // Move the FileID from the unparsed set to the parsed set.
769     UnparsedFiles.erase(FID);
770     ParsedFiles.insert(std::make_pair(FID, FE));
771   } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
772     // Add the FileID to the unparsed set if we haven't seen it before.
773 
774     // Check for directives.
775     bool FoundDirectives;
776     if (PS == IsUnparsedNoDirectives)
777       FoundDirectives = false;
778     else
779       FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
780 
781     // Add the FileID to the unparsed set.
782     UnparsedFiles.insert(std::make_pair(FID,
783                                       UnparsedFileStatus(FE, FoundDirectives)));
784   }
785 #endif
786 }
787 
788 void VerifyDiagnosticConsumer::CheckDiagnostics() {
789   // Ensure any diagnostics go to the primary client.
790   bool OwnsCurClient = Diags.ownsClient();
791   DiagnosticConsumer *CurClient = Diags.takeClient();
792   Diags.setClient(PrimaryClient, false);
793 
794 #ifndef NDEBUG
795   // In a debug build, scan through any files that may have been missed
796   // during parsing and issue a fatal error if directives are contained
797   // within these files.  If a fatal error occurs, this suggests that
798   // this file is being parsed separately from the main file, in which
799   // case consider moving the directives to the correct place, if this
800   // is applicable.
801   if (UnparsedFiles.size() > 0) {
802     // Generate a cache of parsed FileEntry pointers for alias lookups.
803     llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache;
804     for (ParsedFilesMap::iterator I = ParsedFiles.begin(),
805                                 End = ParsedFiles.end(); I != End; ++I) {
806       if (const FileEntry *FE = I->second)
807         ParsedFileCache.insert(FE);
808     }
809 
810     // Iterate through list of unparsed files.
811     for (UnparsedFilesMap::iterator I = UnparsedFiles.begin(),
812                                   End = UnparsedFiles.end(); I != End; ++I) {
813       const UnparsedFileStatus &Status = I->second;
814       const FileEntry *FE = Status.getFile();
815 
816       // Skip files that have been parsed via an alias.
817       if (FE && ParsedFileCache.count(FE))
818         continue;
819 
820       // Report a fatal error if this file contained directives.
821       if (Status.foundDirectives()) {
822         llvm::report_fatal_error(Twine("-verify directives found after rather"
823                                        " than during normal parsing of ",
824                                  StringRef(FE ? FE->getName() : "(unknown)")));
825       }
826     }
827 
828     // UnparsedFiles has been processed now, so clear it.
829     UnparsedFiles.clear();
830   }
831 #endif // !NDEBUG
832 
833   if (SrcManager) {
834     // Produce an error if no expected-* directives could be found in the
835     // source file(s) processed.
836     if (Status == HasNoDirectives) {
837       Diags.Report(diag::err_verify_no_directives).setForceEmit();
838       ++NumErrors;
839       Status = HasNoDirectivesReported;
840     }
841 
842     // Check that the expected diagnostics occurred.
843     NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
844   } else {
845     NumErrors += (PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
846                                   Buffer->err_end(), "error") +
847                   PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
848                                   Buffer->warn_end(), "warn") +
849                   PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
850                                   Buffer->note_end(), "note"));
851   }
852 
853   Diags.takeClient();
854   Diags.setClient(CurClient, OwnsCurClient);
855 
856   // Reset the buffer, we have processed all the diagnostics in it.
857   Buffer.reset(new TextDiagnosticBuffer());
858   ED.Reset();
859 }
860 
861 Directive *Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
862                              SourceLocation DiagnosticLoc, StringRef Text,
863                              unsigned Min, unsigned Max) {
864   if (!RegexKind)
865     return new StandardDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max);
866 
867   // Parse the directive into a regular expression.
868   std::string RegexStr;
869   StringRef S = Text;
870   while (!S.empty()) {
871     if (S.startswith("{{")) {
872       S = S.drop_front(2);
873       size_t RegexMatchLength = S.find("}}");
874       assert(RegexMatchLength != StringRef::npos);
875       // Append the regex, enclosed in parentheses.
876       RegexStr += "(";
877       RegexStr.append(S.data(), RegexMatchLength);
878       RegexStr += ")";
879       S = S.drop_front(RegexMatchLength + 2);
880     } else {
881       size_t VerbatimMatchLength = S.find("{{");
882       if (VerbatimMatchLength == StringRef::npos)
883         VerbatimMatchLength = S.size();
884       // Escape and append the fixed string.
885       RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
886       S = S.drop_front(VerbatimMatchLength);
887     }
888   }
889 
890   return new RegexDirective(DirectiveLoc, DiagnosticLoc, Text, Min, Max,
891                             RegexStr);
892 }
893