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