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