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