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