clang 22.0.0git
VerifyDiagnosticConsumer.cpp
Go to the documentation of this file.
1//===- VerifyDiagnosticConsumer.cpp - Verifying Diagnostic Client ---------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This is a concrete diagnostic client, which buffers the diagnostic messages.
10//
11//===----------------------------------------------------------------------===//
12
17#include "clang/Basic/LLVM.h"
24#include "clang/Lex/Lexer.h"
27#include "clang/Lex/Token.h"
28#include "llvm/ADT/STLExtras.h"
29#include "llvm/ADT/SmallPtrSet.h"
30#include "llvm/ADT/SmallString.h"
31#include "llvm/ADT/StringRef.h"
32#include "llvm/ADT/Twine.h"
33#include "llvm/Support/ErrorHandling.h"
34#include "llvm/Support/Regex.h"
35#include "llvm/Support/raw_ostream.h"
36#include <algorithm>
37#include <cassert>
38#include <cstddef>
39#include <cstring>
40#include <iterator>
41#include <memory>
42#include <string>
43#include <utility>
44#include <vector>
45
46using namespace clang;
47
51
52#ifndef NDEBUG
53
54namespace {
55
56class VerifyFileTracker : public PPCallbacks {
59
60public:
61 VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM)
62 : Verify(Verify), SM(SM) {}
63
64 /// Hook into the preprocessor and update the list of parsed
65 /// files when the preprocessor indicates a new file is entered.
66 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
68 FileID PrevFID) override {
69 Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc),
71 }
72};
73
74} // namespace
75
76#endif
77
78//===----------------------------------------------------------------------===//
79// Checking diagnostics implementation.
80//===----------------------------------------------------------------------===//
81
84
85namespace {
86
87/// StandardDirective - Directive with string matching.
88class StandardDirective : public Directive {
89public:
90 StandardDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
91 StringRef Spelling, bool MatchAnyFileAndLine,
92 bool MatchAnyLine, StringRef Text, unsigned Min,
93 unsigned Max)
94 : Directive(DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine,
95 MatchAnyLine, Text, Min, Max) {}
96
97 bool isValid(std::string &Error) override {
98 // all strings are considered valid; even empty ones
99 return true;
100 }
101
102 bool match(StringRef S) override { return S.contains(Text); }
103};
104
105/// RegexDirective - Directive with regular-expression matching.
106class RegexDirective : public Directive {
107public:
108 RegexDirective(SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc,
109 StringRef Spelling, bool MatchAnyFileAndLine,
110 bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max,
111 StringRef RegexStr)
112 : Directive(DirectiveLoc, DiagnosticLoc, Spelling, MatchAnyFileAndLine,
113 MatchAnyLine, Text, Min, Max),
114 Regex(RegexStr) {}
115
116 bool isValid(std::string &Error) override {
117 return Regex.isValid(Error);
118 }
119
120 bool match(StringRef S) override {
121 return Regex.match(S);
122 }
123
124private:
125 llvm::Regex Regex;
126};
127
128class ParseHelper
129{
130public:
131 ParseHelper(StringRef S)
132 : Begin(S.begin()), End(S.end()), C(Begin), P(Begin) {}
133
134 // Return true if string literal is next.
135 bool Next(StringRef S) {
136 P = C;
137 PEnd = C + S.size();
138 if (PEnd > End)
139 return false;
140 return memcmp(P, S.data(), S.size()) == 0;
141 }
142
143 // Return true if number is next.
144 // Output N only if number is next.
145 bool Next(unsigned &N) {
146 unsigned TMP = 0;
147 P = C;
148 PEnd = P;
149 for (; PEnd < End && *PEnd >= '0' && *PEnd <= '9'; ++PEnd) {
150 TMP *= 10;
151 TMP += *PEnd - '0';
152 }
153 if (PEnd == C)
154 return false;
155 N = TMP;
156 return true;
157 }
158
159 // Return true if a marker is next.
160 // A marker is the longest match for /#[A-Za-z0-9_-]+/.
161 bool NextMarker() {
162 P = C;
163 if (P == End || *P != '#')
164 return false;
165 PEnd = P;
166 ++PEnd;
167 while ((isAlphanumeric(*PEnd) || *PEnd == '-' || *PEnd == '_') &&
168 PEnd < End)
169 ++PEnd;
170 return PEnd > P + 1;
171 }
172
173 // Return true if string literal S is matched in content.
174 // When true, P marks begin-position of the match, and calling Advance sets C
175 // to end-position of the match.
176 // If S is the empty string, then search for any letter instead (makes sense
177 // with FinishDirectiveToken=true).
178 // If EnsureStartOfWord, then skip matches that don't start a new word.
179 // If FinishDirectiveToken, then assume the match is the start of a comment
180 // directive for -verify, and extend the match to include the entire first
181 // token of that directive.
182 bool Search(StringRef S, bool EnsureStartOfWord = false,
183 bool FinishDirectiveToken = false) {
184 do {
185 if (!S.empty()) {
186 P = std::search(C, End, S.begin(), S.end());
187 PEnd = P + S.size();
188 }
189 else {
190 P = C;
191 while (P != End && !isLetter(*P))
192 ++P;
193 PEnd = P + 1;
194 }
195 if (P == End)
196 break;
197 // If not start of word but required, skip and search again.
198 if (EnsureStartOfWord
199 // Check if string literal starts a new word.
200 && !(P == Begin || isWhitespace(P[-1])
201 // Or it could be preceded by the start of a comment.
202 || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*')
203 && P[-2] == '/')))
204 continue;
205 if (FinishDirectiveToken) {
206 while (PEnd != End && (isAlphanumeric(*PEnd)
207 || *PEnd == '-' || *PEnd == '_'))
208 ++PEnd;
209 // Put back trailing digits and hyphens to be parsed later as a count
210 // or count range. Because -verify prefixes must start with letters,
211 // we know the actual directive we found starts with a letter, so
212 // we won't put back the entire directive word and thus record an empty
213 // string.
214 assert(isLetter(*P) && "-verify prefix must start with a letter");
215 while (isDigit(PEnd[-1]) || PEnd[-1] == '-')
216 --PEnd;
217 }
218 return true;
219 } while (Advance());
220 return false;
221 }
222
223 // Return true if a CloseBrace that closes the OpenBrace at the current nest
224 // level is found. When true, P marks begin-position of CloseBrace.
225 bool SearchClosingBrace(StringRef OpenBrace, StringRef CloseBrace) {
226 unsigned Depth = 1;
227 P = C;
228 while (P < End) {
229 StringRef S(P, End - P);
230 if (S.starts_with(OpenBrace)) {
231 ++Depth;
232 P += OpenBrace.size();
233 } else if (S.starts_with(CloseBrace)) {
234 --Depth;
235 if (Depth == 0) {
236 PEnd = P + CloseBrace.size();
237 return true;
238 }
239 P += CloseBrace.size();
240 } else {
241 ++P;
242 }
243 }
244 return false;
245 }
246
247 // Advance 1-past previous next/search.
248 // Behavior is undefined if previous next/search failed.
249 bool Advance() {
250 C = PEnd;
251 return C < End;
252 }
253
254 // Return the text matched by the previous next/search.
255 // Behavior is undefined if previous next/search failed.
256 StringRef Match() { return StringRef(P, PEnd - P); }
257
258 // Skip zero or more whitespace.
259 void SkipWhitespace() {
260 for (; C < End && isWhitespace(*C); ++C)
261 ;
262 }
263
264 // Return true if EOF reached.
265 bool Done() {
266 return !(C < End);
267 }
268
269 // Beginning of expected content.
270 const char * const Begin;
271
272 // End of expected content (1-past).
273 const char * const End;
274
275 // Position of next char in content.
276 const char *C;
277
278 // Previous next/search subject start.
279 const char *P;
280
281private:
282 // Previous next/search subject end (1-past).
283 const char *PEnd = nullptr;
284};
285
286// The information necessary to create a directive.
287struct UnattachedDirective {
288 DirectiveList *DL = nullptr;
289 std::string Spelling;
290 bool RegexKind = false;
291 SourceLocation DirectivePos, ContentBegin;
292 std::string Text;
293 unsigned Min = 1, Max = 1;
294};
295
296// Attach the specified directive to the line of code indicated by
297// \p ExpectedLoc.
298void attachDirective(DiagnosticsEngine &Diags, const UnattachedDirective &UD,
299 SourceLocation ExpectedLoc,
300 bool MatchAnyFileAndLine = false,
301 bool MatchAnyLine = false) {
302 // Construct new directive.
303 std::unique_ptr<Directive> D = Directive::create(
304 UD.RegexKind, UD.DirectivePos, ExpectedLoc, UD.Spelling,
305 MatchAnyFileAndLine, MatchAnyLine, UD.Text, UD.Min, UD.Max);
306
307 std::string Error;
308 if (!D->isValid(Error)) {
309 Diags.Report(UD.ContentBegin, diag::err_verify_invalid_content)
310 << (UD.RegexKind ? "regex" : "string") << Error;
311 }
312
313 UD.DL->push_back(std::move(D));
314}
315
316} // anonymous
317
318// Tracker for markers in the input files. A marker is a comment of the form
319//
320// n = 123; // #123
321//
322// ... that can be referred to by a later expected-* directive:
323//
324// // expected-error@#123 {{undeclared identifier 'n'}}
325//
326// Marker declarations must be at the start of a comment or preceded by
327// whitespace to distinguish them from uses of markers in directives.
329 DiagnosticsEngine &Diags;
330
331 struct Marker {
332 SourceLocation DefLoc;
333 SourceLocation RedefLoc;
334 SourceLocation UseLoc;
335 };
336 llvm::StringMap<Marker> Markers;
337
338 // Directives that couldn't be created yet because they name an unknown
339 // marker.
340 llvm::StringMap<llvm::SmallVector<UnattachedDirective, 2>> DeferredDirectives;
341
342public:
343 MarkerTracker(DiagnosticsEngine &Diags) : Diags(Diags) {}
344
345 // Register a marker.
346 void addMarker(StringRef MarkerName, SourceLocation Pos) {
347 auto InsertResult = Markers.insert(
348 {MarkerName, Marker{Pos, SourceLocation(), SourceLocation()}});
349
350 Marker &M = InsertResult.first->second;
351 if (!InsertResult.second) {
352 // Marker was redefined.
353 M.RedefLoc = Pos;
354 } else {
355 // First definition: build any deferred directives.
356 auto Deferred = DeferredDirectives.find(MarkerName);
357 if (Deferred != DeferredDirectives.end()) {
358 for (auto &UD : Deferred->second) {
359 if (M.UseLoc.isInvalid())
360 M.UseLoc = UD.DirectivePos;
361 attachDirective(Diags, UD, Pos);
362 }
363 DeferredDirectives.erase(Deferred);
364 }
365 }
366 }
367
368 // Register a directive at the specified marker.
369 void addDirective(StringRef MarkerName, const UnattachedDirective &UD) {
370 auto MarkerIt = Markers.find(MarkerName);
371 if (MarkerIt != Markers.end()) {
372 Marker &M = MarkerIt->second;
373 if (M.UseLoc.isInvalid())
374 M.UseLoc = UD.DirectivePos;
375 return attachDirective(Diags, UD, M.DefLoc);
376 }
377 DeferredDirectives[MarkerName].push_back(UD);
378 }
379
380 // Ensure we have no remaining deferred directives, and no
381 // multiply-defined-and-used markers.
382 void finalize() {
383 for (auto &MarkerInfo : Markers) {
384 StringRef Name = MarkerInfo.first();
385 Marker &M = MarkerInfo.second;
386 if (M.RedefLoc.isValid() && M.UseLoc.isValid()) {
387 Diags.Report(M.UseLoc, diag::err_verify_ambiguous_marker) << Name;
388 Diags.Report(M.DefLoc, diag::note_verify_ambiguous_marker) << Name;
389 Diags.Report(M.RedefLoc, diag::note_verify_ambiguous_marker) << Name;
390 }
391 }
392
393 for (auto &DeferredPair : DeferredDirectives) {
394 Diags.Report(DeferredPair.second.front().DirectivePos,
395 diag::err_verify_no_such_marker)
396 << DeferredPair.first();
397 }
398 }
399};
400
401static std::string DetailedErrorString(const DiagnosticsEngine &Diags) {
402 if (Diags.getDiagnosticOptions().VerifyPrefixes.empty())
403 return "expected";
404 return *Diags.getDiagnosticOptions().VerifyPrefixes.begin();
405}
406
407/// ParseDirective - Go through the comment and see if it indicates expected
408/// diagnostics. If so, then put them in the appropriate directive list.
409///
410/// Returns true if any valid directives were found.
411static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
415 DiagnosticsEngine &Diags = PP ? PP->getDiagnostics() : SM.getDiagnostics();
416
417 // First, scan the comment looking for markers.
418 for (ParseHelper PH(S); !PH.Done();) {
419 if (!PH.Search("#", true))
420 break;
421 PH.C = PH.P;
422 if (!PH.NextMarker()) {
423 PH.Next("#");
424 PH.Advance();
425 continue;
426 }
427 PH.Advance();
428 Markers.addMarker(PH.Match(), Pos);
429 }
430
431 // A single comment may contain multiple directives.
432 bool FoundDirective = false;
433 for (ParseHelper PH(S); !PH.Done();) {
434 // Search for the initial directive token.
435 // If one prefix, save time by searching only for its directives.
436 // Otherwise, search for any potential directive token and check it later.
437 const auto &Prefixes = Diags.getDiagnosticOptions().VerifyPrefixes;
438 if (!(Prefixes.size() == 1 ? PH.Search(*Prefixes.begin(), true, true)
439 : PH.Search("", true, true)))
440 break;
441
442 StringRef DToken = PH.Match();
443 PH.Advance();
444
445 UnattachedDirective D;
446 D.Spelling = DToken;
447 // Default directive kind.
448 const char *KindStr = "string";
449
450 // Parse the initial directive token in reverse so we can easily determine
451 // its exact actual prefix. If we were to parse it from the front instead,
452 // it would be harder to determine where the prefix ends because there
453 // might be multiple matching -verify prefixes because some might prefix
454 // others.
455
456 // Regex in initial directive token: -re
457 if (DToken.consume_back("-re")) {
458 D.RegexKind = true;
459 KindStr = "regex";
460 }
461
462 // Type in initial directive token: -{error|warning|note|no-diagnostics}
463 bool NoDiag = false;
464 StringRef DType;
465 if (DToken.ends_with(DType = "-error"))
466 D.DL = ED ? &ED->Errors : nullptr;
467 else if (DToken.ends_with(DType = "-warning"))
468 D.DL = ED ? &ED->Warnings : nullptr;
469 else if (DToken.ends_with(DType = "-remark"))
470 D.DL = ED ? &ED->Remarks : nullptr;
471 else if (DToken.ends_with(DType = "-note"))
472 D.DL = ED ? &ED->Notes : nullptr;
473 else if (DToken.ends_with(DType = "-no-diagnostics")) {
474 NoDiag = true;
475 if (D.RegexKind)
476 continue;
477 } else
478 continue;
479 DToken = DToken.substr(0, DToken.size()-DType.size());
480
481 // What's left in DToken is the actual prefix. That might not be a -verify
482 // prefix even if there is only one -verify prefix (for example, the full
483 // DToken is foo-bar-warning, but foo is the only -verify prefix).
484 if (!llvm::binary_search(Prefixes, DToken))
485 continue;
486
487 if (NoDiag) {
488 if (State.Status ==
490 Diags.Report(Pos, diag::err_verify_invalid_no_diags)
491 << D.Spelling << /*IsExpectedNoDiagnostics=*/true;
492 } else if (State.Status !=
495 State.FirstNoDiagnosticsDirective = D.Spelling;
496 }
497 continue;
498 }
500 Diags.Report(Pos, diag::err_verify_invalid_no_diags)
501 << D.Spelling << /*IsExpectedNoDiagnostics=*/false
502 << State.FirstNoDiagnosticsDirective;
503 continue;
504 }
506
507 // If a directive has been found but we're not interested
508 // in storing the directive information, return now.
509 if (!D.DL)
510 return true;
511
512 // Next optional token: @
513 SourceLocation ExpectedLoc;
514 StringRef Marker;
515 bool MatchAnyFileAndLine = false;
516 bool MatchAnyLine = false;
517 if (!PH.Next("@")) {
518 ExpectedLoc = Pos;
519 } else {
520 PH.Advance();
521 unsigned Line = 0;
522 bool FoundPlus = PH.Next("+");
523 if (FoundPlus || PH.Next("-")) {
524 // Relative to current line.
525 PH.Advance();
526 bool Invalid = false;
527 unsigned ExpectedLine = SM.getSpellingLineNumber(Pos, &Invalid);
528 if (!Invalid && PH.Next(Line) && (FoundPlus || Line < ExpectedLine)) {
529 if (FoundPlus) ExpectedLine += Line;
530 else ExpectedLine -= Line;
531 ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), ExpectedLine, 1);
532 }
533 } else if (PH.Next(Line)) {
534 // Absolute line number.
535 if (Line > 0)
536 ExpectedLoc = SM.translateLineCol(SM.getFileID(Pos), Line, 1);
537 } else if (PH.NextMarker()) {
538 Marker = PH.Match();
539 } else if (PP && PH.Search(":")) {
540 // Specific source file.
541 StringRef Filename(PH.C, PH.P-PH.C);
542 PH.Advance();
543
544 if (Filename == "*") {
545 MatchAnyFileAndLine = true;
546 if (!PH.Next("*")) {
547 Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
548 diag::err_verify_missing_line)
549 << "'*'";
550 continue;
551 }
552 MatchAnyLine = true;
553 ExpectedLoc = SourceLocation();
554 } else {
555 // Lookup file via Preprocessor, like a #include.
557 PP->LookupFile(Pos, Filename, false, nullptr, nullptr, nullptr,
558 nullptr, nullptr, nullptr, nullptr, nullptr);
559 if (!File) {
560 Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
561 diag::err_verify_missing_file)
562 << Filename << KindStr;
563 continue;
564 }
565
566 FileID FID = SM.translateFile(*File);
567 if (FID.isInvalid())
568 FID = SM.createFileID(*File, Pos, SrcMgr::C_User);
569
570 if (PH.Next(Line) && Line > 0)
571 ExpectedLoc = SM.translateLineCol(FID, Line, 1);
572 else if (PH.Next("*")) {
573 MatchAnyLine = true;
574 ExpectedLoc = SM.translateLineCol(FID, 1, 1);
575 }
576 }
577 } else if (PH.Next("*")) {
578 MatchAnyLine = true;
579 ExpectedLoc = SourceLocation();
580 }
581
582 if (ExpectedLoc.isInvalid() && !MatchAnyLine && Marker.empty()) {
583 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
584 diag::err_verify_missing_line) << KindStr;
585 continue;
586 }
587 PH.Advance();
588 }
589
590 // Skip optional whitespace.
591 PH.SkipWhitespace();
592
593 // Next optional token: positive integer or a '+'.
594 if (PH.Next(D.Min)) {
595 PH.Advance();
596 // A positive integer can be followed by a '+' meaning min
597 // or more, or by a '-' meaning a range from min to max.
598 if (PH.Next("+")) {
600 PH.Advance();
601 } else if (PH.Next("-")) {
602 PH.Advance();
603 if (!PH.Next(D.Max) || D.Max < D.Min) {
604 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
605 diag::err_verify_invalid_range) << KindStr;
606 continue;
607 }
608 PH.Advance();
609 } else {
610 D.Max = D.Min;
611 }
612 } else if (PH.Next("+")) {
613 // '+' on its own means "1 or more".
615 PH.Advance();
616 }
617
618 // Skip optional whitespace.
619 PH.SkipWhitespace();
620
621 // Next token: {{
622 if (!PH.Next("{{")) {
623 Diags.Report(Pos.getLocWithOffset(PH.C-PH.Begin),
624 diag::err_verify_missing_start) << KindStr;
625 continue;
626 }
627 llvm::SmallString<8> CloseBrace("}}");
628 const char *const DelimBegin = PH.C;
629 PH.Advance();
630 // Count the number of opening braces for `string` kinds
631 for (; !D.RegexKind && PH.Next("{"); PH.Advance())
632 CloseBrace += '}';
633 const char* const ContentBegin = PH.C; // mark content begin
634 // Search for closing brace
635 StringRef OpenBrace(DelimBegin, ContentBegin - DelimBegin);
636 if (!PH.SearchClosingBrace(OpenBrace, CloseBrace)) {
637 Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
638 diag::err_verify_missing_end)
639 << KindStr << CloseBrace;
640 continue;
641 }
642 const char* const ContentEnd = PH.P; // mark content end
643 PH.Advance();
644
645 D.DirectivePos = Pos;
646 D.ContentBegin = Pos.getLocWithOffset(ContentBegin - PH.Begin);
647
648 // Build directive text; convert \n to newlines.
649 StringRef NewlineStr = "\\n";
650 StringRef Content(ContentBegin, ContentEnd-ContentBegin);
651 size_t CPos = 0;
652 size_t FPos;
653 while ((FPos = Content.find(NewlineStr, CPos)) != StringRef::npos) {
654 D.Text += Content.substr(CPos, FPos-CPos);
655 D.Text += '\n';
656 CPos = FPos + NewlineStr.size();
657 }
658 if (D.Text.empty())
659 D.Text.assign(ContentBegin, ContentEnd);
660
661 // Check that regex directives contain at least one regex.
662 if (D.RegexKind && D.Text.find("{{") == StringRef::npos) {
663 Diags.Report(D.ContentBegin, diag::err_verify_missing_regex) << D.Text;
664 return false;
665 }
666
667 if (Marker.empty())
668 attachDirective(Diags, D, ExpectedLoc, MatchAnyFileAndLine, MatchAnyLine);
669 else
670 Markers.addDirective(Marker, D);
671 FoundDirective = true;
672 }
673
674 return FoundDirective;
675}
676
678 : Diags(Diags_), PrimaryClient(Diags.getClient()),
679 PrimaryClientOwner(Diags.takeClient()),
680 Buffer(new TextDiagnosticBuffer()), Markers(new MarkerTracker(Diags)),
681 State{HasNoDirectives, {}} {
682 if (Diags.hasSourceManager())
683 setSourceManager(Diags.getSourceManager());
684}
685
687 assert(!ActiveSourceFiles && "Incomplete parsing of source files!");
688 assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!");
689 SrcManager = nullptr;
690 CheckDiagnostics();
691 assert(!Diags.ownsClient() &&
692 "The VerifyDiagnosticConsumer takes over ownership of the client!");
693}
694
695// DiagnosticConsumer interface.
696
698 const Preprocessor *PP) {
699 // Attach comment handler on first invocation.
700 if (++ActiveSourceFiles == 1) {
701 if (PP) {
702 CurrentPreprocessor = PP;
703 this->LangOpts = &LangOpts;
704 setSourceManager(PP->getSourceManager());
705 const_cast<Preprocessor *>(PP)->addCommentHandler(this);
706#ifndef NDEBUG
707 // Debug build tracks parsed files.
708 const_cast<Preprocessor *>(PP)->addPPCallbacks(
709 std::make_unique<VerifyFileTracker>(*this, *SrcManager));
710#endif
711 }
712 }
713
714 assert((!PP || CurrentPreprocessor == PP) && "Preprocessor changed!");
715 PrimaryClient->BeginSourceFile(LangOpts, PP);
716}
717
719 assert(ActiveSourceFiles && "No active source files!");
720 PrimaryClient->EndSourceFile();
721
722 // Detach comment handler once last active source file completed.
723 if (--ActiveSourceFiles == 0) {
724 if (CurrentPreprocessor)
725 const_cast<Preprocessor *>(CurrentPreprocessor)->
726 removeCommentHandler(this);
727
728 // Diagnose any used-but-not-defined markers.
729 Markers->finalize();
730
731 // Check diagnostics once last file completed.
732 CheckDiagnostics();
733 CurrentPreprocessor = nullptr;
734 LangOpts = nullptr;
735 }
736}
737
739 DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
740 if (Info.hasSourceManager()) {
741 // If this diagnostic is for a different source manager, ignore it.
742 if (SrcManager && &Info.getSourceManager() != SrcManager)
743 return;
744
745 setSourceManager(Info.getSourceManager());
746 }
747
748#ifndef NDEBUG
749 // Debug build tracks unparsed files for possible
750 // unparsed expected-* directives.
751 if (SrcManager) {
753 if (Loc.isValid()) {
755
756 Loc = SrcManager->getExpansionLoc(Loc);
757 FileID FID = SrcManager->getFileID(Loc);
758
759 auto FE = SrcManager->getFileEntryRefForID(FID);
760 if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) {
761 // If the file is a modules header file it shall not be parsed
762 // for expected-* directives.
763 HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo();
764 if (HS.findModuleForHeader(*FE))
766 }
767
768 UpdateParsedFileStatus(*SrcManager, FID, PS);
769 }
770 }
771#endif
772
773 // Send the diagnostic to the buffer, we will check it once we reach the end
774 // of the source file (or are destructed).
775 Buffer->HandleDiagnostic(DiagLevel, Info);
776}
777
778/// HandleComment - Hook into the preprocessor and extract comments containing
779/// expected errors and warnings.
781 SourceRange Comment) {
783
784 // If this comment is for a different source manager, ignore it.
785 if (SrcManager && &SM != SrcManager)
786 return false;
787
788 SourceLocation CommentBegin = Comment.getBegin();
789
790 const char *CommentRaw = SM.getCharacterData(CommentBegin);
791 StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw);
792
793 if (C.empty())
794 return false;
795
796 // Fold any "<EOL>" sequences
797 size_t loc = C.find('\\');
798 if (loc == StringRef::npos) {
799 ParseDirective(C, &ED, SM, &PP, CommentBegin, State, *Markers);
800 return false;
801 }
802
803 std::string C2;
804 C2.reserve(C.size());
805
806 for (size_t last = 0;; loc = C.find('\\', last)) {
807 if (loc == StringRef::npos || loc == C.size()) {
808 C2 += C.substr(last);
809 break;
810 }
811 C2 += C.substr(last, loc-last);
812 last = loc + 1;
813
814 if (last < C.size() && (C[last] == '\n' || C[last] == '\r')) {
815 ++last;
816
817 // Escape \r\n or \n\r, but not \n\n.
818 if (last < C.size())
819 if (C[last] == '\n' || C[last] == '\r')
820 if (C[last] != C[last-1])
821 ++last;
822 } else {
823 // This was just a normal backslash.
824 C2 += '\\';
825 }
826 }
827
828 if (!C2.empty())
829 ParseDirective(C2, &ED, SM, &PP, CommentBegin, State, *Markers);
830 return false;
831}
832
833#ifndef NDEBUG
834/// Lex the specified source file to determine whether it contains
835/// any expected-* directives. As a Lexer is used rather than a full-blown
836/// Preprocessor, directives inside skipped #if blocks will still be found.
837///
838/// \return true if any directives were found.
840 const LangOptions &LangOpts) {
841 // Create a raw lexer to pull all the comments out of FID.
842 if (FID.isInvalid())
843 return false;
844
845 // Create a lexer to lex all the tokens of the main file in raw mode.
846 llvm::MemoryBufferRef FromFile = SM.getBufferOrFake(FID);
847 Lexer RawLex(FID, FromFile, SM, LangOpts);
848
849 // Return comments as tokens, this is how we find expected diagnostics.
850 RawLex.SetCommentRetentionState(true);
851
852 Token Tok;
853 Tok.setKind(tok::comment);
856 while (Tok.isNot(tok::eof)) {
857 RawLex.LexFromRawLexer(Tok);
858 if (!Tok.is(tok::comment)) continue;
859
860 std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts);
861 if (Comment.empty()) continue;
862
863 // We don't care about tracking markers for this phase.
864 VerifyDiagnosticConsumer::MarkerTracker Markers(SM.getDiagnostics());
865
866 // Find first directive.
867 if (ParseDirective(Comment, nullptr, SM, nullptr, Tok.getLocation(), State,
868 Markers))
869 return true;
870 }
871 return false;
872}
873#endif // !NDEBUG
874
875/// Takes a list of diagnostics that have been generated but not matched
876/// by an expected-* directive and produces a diagnostic to the user from this.
877static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr,
878 const_diag_iterator diag_begin,
879 const_diag_iterator diag_end,
880 const char *Kind) {
881 if (diag_begin == diag_end) return 0;
882
884 llvm::raw_svector_ostream OS(Fmt);
885 for (const_diag_iterator I = diag_begin, E = diag_end; I != E; ++I) {
886 if (I->first.isInvalid() || !SourceMgr)
887 OS << "\n (frontend)";
888 else {
889 OS << "\n ";
891 SourceMgr->getFileEntryRefForID(SourceMgr->getFileID(I->first)))
892 OS << " File " << File->getName();
893 OS << " Line " << SourceMgr->getPresumedLineNumber(I->first);
894 }
895 OS << ": " << I->second;
896 }
897
898 const bool IsSinglePrefix =
899 Diags.getDiagnosticOptions().VerifyPrefixes.size() == 1;
900 std::string Prefix = *Diags.getDiagnosticOptions().VerifyPrefixes.begin();
901 Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
902 << IsSinglePrefix << Prefix << Kind << /*Unexpected=*/true << OS.str();
903 return std::distance(diag_begin, diag_end);
904}
905
906/// Takes a list of diagnostics that were expected to have been generated
907/// but were not and produces a diagnostic to the user from this.
908static unsigned PrintExpected(DiagnosticsEngine &Diags,
909 SourceManager &SourceMgr,
910 std::vector<Directive *> &DL, const char *Kind) {
911 if (DL.empty())
912 return 0;
913
914 const bool IsSinglePrefix =
915 Diags.getDiagnosticOptions().VerifyPrefixes.size() == 1;
916
918 llvm::raw_svector_ostream OS(Fmt);
919 for (const auto *D : DL) {
920 if (D->DiagnosticLoc.isInvalid() || D->MatchAnyFileAndLine)
921 OS << "\n File *";
922 else
923 OS << "\n File " << SourceMgr.getFilename(D->DiagnosticLoc);
924 if (D->MatchAnyLine)
925 OS << " Line *";
926 else
927 OS << " Line " << SourceMgr.getPresumedLineNumber(D->DiagnosticLoc);
928 if (D->DirectiveLoc != D->DiagnosticLoc)
929 OS << " (directive at "
930 << SourceMgr.getFilename(D->DirectiveLoc) << ':'
931 << SourceMgr.getPresumedLineNumber(D->DirectiveLoc) << ')';
932 if (!IsSinglePrefix)
933 OS << " \'" << D->Spelling << '\'';
934 OS << ": " << D->Text;
935 }
936
937 std::string Prefix = *Diags.getDiagnosticOptions().VerifyPrefixes.begin();
938 Diags.Report(diag::err_verify_inconsistent_diags).setForceEmit()
939 << IsSinglePrefix << Prefix << Kind << /*Unexpected=*/false << OS.str();
940 return DL.size();
941}
942
943/// Determine whether two source locations come from the same file.
945 SourceLocation DiagnosticLoc) {
946 while (DiagnosticLoc.isMacroID())
947 DiagnosticLoc = SM.getImmediateMacroCallerLoc(DiagnosticLoc);
948
949 if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
950 return true;
951
952 const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
953 if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
954 return true;
955
956 return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
957}
958
959/// CheckLists - Compare expected to seen diagnostic lists and return the
960/// the difference between them.
961static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
962 const char *Label,
963 DirectiveList &Left,
964 const_diag_iterator d2_begin,
965 const_diag_iterator d2_end,
966 bool IgnoreUnexpected) {
967 std::vector<Directive *> LeftOnly;
968 DiagList Right(d2_begin, d2_end);
969
970 for (auto &Owner : Left) {
971 Directive &D = *Owner;
972 unsigned LineNo1 = SourceMgr.getPresumedLineNumber(D.DiagnosticLoc);
973
974 for (unsigned i = 0; i < D.Max; ++i) {
975 DiagList::iterator II, IE;
976 for (II = Right.begin(), IE = Right.end(); II != IE; ++II) {
977 if (!D.MatchAnyLine) {
978 unsigned LineNo2 = SourceMgr.getPresumedLineNumber(II->first);
979 if (LineNo1 != LineNo2)
980 continue;
981 }
982
983 if (!D.DiagnosticLoc.isInvalid() && !D.MatchAnyFileAndLine &&
984 !IsFromSameFile(SourceMgr, D.DiagnosticLoc, II->first))
985 continue;
986
987 const std::string &RightText = II->second;
988 if (D.match(RightText))
989 break;
990 }
991 if (II == IE) {
992 // Not found.
993 if (i >= D.Min) break;
994 LeftOnly.push_back(&D);
995 } else {
996 // Found. The same cannot be found twice.
997 Right.erase(II);
998 }
999 }
1000 }
1001 // Now all that's left in Right are those that were not matched.
1002 unsigned num = PrintExpected(Diags, SourceMgr, LeftOnly, Label);
1003 if (!IgnoreUnexpected)
1004 num += PrintUnexpected(Diags, &SourceMgr, Right.begin(), Right.end(), Label);
1005 return num;
1006}
1007
1008/// CheckResults - This compares the expected results to those that
1009/// were actually reported. It emits any discrepencies. Return "true" if there
1010/// were problems. Return "false" otherwise.
1011static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr,
1012 const TextDiagnosticBuffer &Buffer,
1013 ExpectedData &ED) {
1014 // We want to capture the delta between what was expected and what was
1015 // seen.
1016 //
1017 // Expected \ Seen - set expected but not seen
1018 // Seen \ Expected - set seen but not expected
1019 unsigned NumProblems = 0;
1020
1021 const DiagnosticLevelMask DiagMask =
1022 Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
1023
1024 // See if there are error mismatches.
1025 NumProblems += CheckLists(Diags, SourceMgr, "error", ED.Errors,
1026 Buffer.err_begin(), Buffer.err_end(),
1027 bool(DiagnosticLevelMask::Error & DiagMask));
1028
1029 // See if there are warning mismatches.
1030 NumProblems += CheckLists(Diags, SourceMgr, "warning", ED.Warnings,
1031 Buffer.warn_begin(), Buffer.warn_end(),
1032 bool(DiagnosticLevelMask::Warning & DiagMask));
1033
1034 // See if there are remark mismatches.
1035 NumProblems += CheckLists(Diags, SourceMgr, "remark", ED.Remarks,
1036 Buffer.remark_begin(), Buffer.remark_end(),
1037 bool(DiagnosticLevelMask::Remark & DiagMask));
1038
1039 // See if there are note mismatches.
1040 NumProblems += CheckLists(Diags, SourceMgr, "note", ED.Notes,
1041 Buffer.note_begin(), Buffer.note_end(),
1042 bool(DiagnosticLevelMask::Note & DiagMask));
1043
1044 return NumProblems;
1045}
1046
1048 FileID FID,
1049 ParsedStatus PS) {
1050 // Check SourceManager hasn't changed.
1051 setSourceManager(SM);
1052
1053#ifndef NDEBUG
1054 if (FID.isInvalid())
1055 return;
1056
1057 OptionalFileEntryRef FE = SM.getFileEntryRefForID(FID);
1058
1059 if (PS == IsParsed) {
1060 // Move the FileID from the unparsed set to the parsed set.
1061 UnparsedFiles.erase(FID);
1062 ParsedFiles.insert(std::make_pair(FID, FE ? &FE->getFileEntry() : nullptr));
1063 } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) {
1064 // Add the FileID to the unparsed set if we haven't seen it before.
1065
1066 // Check for directives.
1067 bool FoundDirectives;
1068 if (PS == IsUnparsedNoDirectives)
1069 FoundDirectives = false;
1070 else
1071 FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts);
1072
1073 // Add the FileID to the unparsed set.
1074 UnparsedFiles.insert(std::make_pair(FID,
1075 UnparsedFileStatus(FE, FoundDirectives)));
1076 }
1077#endif
1078}
1079
1080void VerifyDiagnosticConsumer::CheckDiagnostics() {
1081 // Ensure any diagnostics go to the primary client.
1082 DiagnosticConsumer *CurClient = Diags.getClient();
1083 std::unique_ptr<DiagnosticConsumer> Owner = Diags.takeClient();
1084 Diags.setClient(PrimaryClient, false);
1085
1086#ifndef NDEBUG
1087 // In a debug build, scan through any files that may have been missed
1088 // during parsing and issue a fatal error if directives are contained
1089 // within these files. If a fatal error occurs, this suggests that
1090 // this file is being parsed separately from the main file, in which
1091 // case consider moving the directives to the correct place, if this
1092 // is applicable.
1093 if (!UnparsedFiles.empty()) {
1094 // Generate a cache of parsed FileEntry pointers for alias lookups.
1096 for (const auto &I : ParsedFiles)
1097 if (const FileEntry *FE = I.second)
1098 ParsedFileCache.insert(FE);
1099
1100 // Iterate through list of unparsed files.
1101 for (const auto &I : UnparsedFiles) {
1102 const UnparsedFileStatus &Status = I.second;
1103 OptionalFileEntryRef FE = Status.getFile();
1104
1105 // Skip files that have been parsed via an alias.
1106 if (FE && ParsedFileCache.count(*FE))
1107 continue;
1108
1109 // Report a fatal error if this file contained directives.
1110 if (Status.foundDirectives()) {
1111 llvm::report_fatal_error("-verify directives found after rather"
1112 " than during normal parsing of " +
1113 (FE ? FE->getName() : "(unknown)"));
1114 }
1115 }
1116
1117 // UnparsedFiles has been processed now, so clear it.
1118 UnparsedFiles.clear();
1119 }
1120#endif // !NDEBUG
1121
1122 if (SrcManager) {
1123 // Produce an error if no expected-* directives could be found in the
1124 // source file(s) processed.
1125 if (State.Status == HasNoDirectives) {
1126 Diags.Report(diag::err_verify_no_directives).setForceEmit()
1127 << DetailedErrorString(Diags);
1128 ++NumErrors;
1130 }
1131
1132 // Check that the expected diagnostics occurred.
1133 NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED);
1134 } else {
1135 const DiagnosticLevelMask DiagMask =
1136 ~Diags.getDiagnosticOptions().getVerifyIgnoreUnexpected();
1137 if (bool(DiagnosticLevelMask::Error & DiagMask))
1138 NumErrors += PrintUnexpected(Diags, nullptr, Buffer->err_begin(),
1139 Buffer->err_end(), "error");
1140 if (bool(DiagnosticLevelMask::Warning & DiagMask))
1141 NumErrors += PrintUnexpected(Diags, nullptr, Buffer->warn_begin(),
1142 Buffer->warn_end(), "warn");
1143 if (bool(DiagnosticLevelMask::Remark & DiagMask))
1144 NumErrors += PrintUnexpected(Diags, nullptr, Buffer->remark_begin(),
1145 Buffer->remark_end(), "remark");
1146 if (bool(DiagnosticLevelMask::Note & DiagMask))
1147 NumErrors += PrintUnexpected(Diags, nullptr, Buffer->note_begin(),
1148 Buffer->note_end(), "note");
1149 }
1150
1151 Diags.setClient(CurClient, Owner.release() != nullptr);
1152
1153 // Reset the buffer, we have processed all the diagnostics in it.
1154 Buffer.reset(new TextDiagnosticBuffer());
1155 ED.Reset();
1156}
1157
1158std::unique_ptr<Directive>
1159Directive::create(bool RegexKind, SourceLocation DirectiveLoc,
1160 SourceLocation DiagnosticLoc, StringRef Spelling,
1161 bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text,
1162 unsigned Min, unsigned Max) {
1163 if (!RegexKind)
1164 return std::make_unique<StandardDirective>(DirectiveLoc, DiagnosticLoc,
1165 Spelling, MatchAnyFileAndLine,
1166 MatchAnyLine, Text, Min, Max);
1167
1168 // Parse the directive into a regular expression.
1169 std::string RegexStr;
1170 StringRef S = Text;
1171 while (!S.empty()) {
1172 if (S.consume_front("{{")) {
1173 size_t RegexMatchLength = S.find("}}");
1174 assert(RegexMatchLength != StringRef::npos);
1175 // Append the regex, enclosed in parentheses.
1176 RegexStr += "(";
1177 RegexStr.append(S.data(), RegexMatchLength);
1178 RegexStr += ")";
1179 S = S.drop_front(RegexMatchLength + 2);
1180 } else {
1181 size_t VerbatimMatchLength = S.find("{{");
1182 if (VerbatimMatchLength == StringRef::npos)
1183 VerbatimMatchLength = S.size();
1184 // Escape and append the fixed string.
1185 RegexStr += llvm::Regex::escape(S.substr(0, VerbatimMatchLength));
1186 S = S.drop_front(VerbatimMatchLength);
1187 }
1188 }
1189
1190 return std::make_unique<RegexDirective>(DirectiveLoc, DiagnosticLoc, Spelling,
1191 MatchAnyFileAndLine, MatchAnyLine,
1192 Text, Min, Max, RegexStr);
1193}
StringRef P
Defines the Diagnostic-related interfaces.
const Decl * D
Expr * E
static ICEDiag NoDiag()
StringRef Text
Definition: Format.cpp:3178
StringRef Filename
Definition: Format.cpp:3177
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
llvm::MachO::FileType FileType
Definition: MachO.h:46
#define SM(sm)
Definition: OffloadArch.cpp:16
Defines the PPCallbacks interface.
Defines the clang::Preprocessor interface.
SourceLocation Loc
Definition: SemaObjC.cpp:754
Defines the clang::SourceLocation class and associated facilities.
Defines the SourceManager interface.
Defines the clang::TokenKind enum and support functions.
SourceLocation Begin
std::string Label
static unsigned CheckLists(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const char *Label, DirectiveList &Left, const_diag_iterator d2_begin, const_diag_iterator d2_end, bool IgnoreUnexpected)
CheckLists - Compare expected to seen diagnostic lists and return the the difference between them.
static bool findDirectives(SourceManager &SM, FileID FID, const LangOptions &LangOpts)
Lex the specified source file to determine whether it contains any expected-* directives.
TextDiagnosticBuffer::const_iterator const_diag_iterator
TextDiagnosticBuffer::DiagList DiagList
static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc)
Determine whether two source locations come from the same file.
VerifyDiagnosticConsumer::DirectiveList DirectiveList
static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, const TextDiagnosticBuffer &Buffer, ExpectedData &ED)
CheckResults - This compares the expected results to those that were actually reported.
static unsigned PrintUnexpected(DiagnosticsEngine &Diags, SourceManager *SourceMgr, const_diag_iterator diag_begin, const_diag_iterator diag_end, const char *Kind)
Takes a list of diagnostics that have been generated but not matched by an expected-* directive and p...
static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, Preprocessor *PP, SourceLocation Pos, VerifyDiagnosticConsumer::ParsingState &State, VerifyDiagnosticConsumer::MarkerTracker &Markers)
ParseDirective - Go through the comment and see if it indicates expected diagnostics.
VerifyDiagnosticConsumer::Directive Directive
static std::string DetailedErrorString(const DiagnosticsEngine &Diags)
static unsigned PrintExpected(DiagnosticsEngine &Diags, SourceManager &SourceMgr, std::vector< Directive * > &DL, const char *Kind)
Takes a list of diagnostics that were expected to have been generated but were not and produces a dia...
void addDirective(StringRef MarkerName, const UnattachedDirective &UD)
void addMarker(StringRef MarkerName, SourceLocation Pos)
const DiagnosticBuilder & setForceEmit() const
Forces the diagnostic to be emitted.
Definition: Diagnostic.h:1332
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
Definition: Diagnostic.h:1722
virtual void EndSourceFile()
Callback to inform the diagnostic client that processing of a source file has ended.
Definition: Diagnostic.h:1754
unsigned NumErrors
Number of errors reported.
Definition: Diagnostic.h:1725
virtual void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP=nullptr)
Callback to inform the diagnostic client that processing of a source file is beginning.
Definition: Diagnostic.h:1746
std::vector< std::string > VerifyPrefixes
The prefixes for comment directives sought by -verify ("expected" by default).
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
Definition: Diagnostic.h:1548
const SourceLocation & getLocation() const
Definition: Diagnostic.h:1564
SourceManager & getSourceManager() const
Definition: Diagnostic.h:1566
bool hasSourceManager() const
Definition: Diagnostic.h:1565
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:231
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1529
DiagnosticOptions & getDiagnosticOptions() const
Retrieve the diagnostic options.
Definition: Diagnostic.h:596
void setClient(DiagnosticConsumer *client, bool ShouldOwnClient=true)
Set the diagnostic client associated with this diagnostic object.
Definition: Diagnostic.cpp:100
std::unique_ptr< DiagnosticConsumer > takeClient()
Return the current diagnostic client along with ownership of that client.
Definition: Diagnostic.h:614
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:236
DiagnosticConsumer * getClient()
Definition: Diagnostic.h:606
bool ownsClient() const
Determine whether this DiagnosticsEngine object own its client.
Definition: Diagnostic.h:610
const FileEntry & getFileEntry() const
Definition: FileEntry.h:70
StringRef getName() const
The name of this FileEntry.
Definition: FileEntry.h:61
Cached information about one file (either on disk or in the virtual file system).
Definition: FileEntry.h:306
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
bool isInvalid() const
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
Definition: HeaderSearch.h:237
ModuleMap::KnownHeader findModuleForHeader(FileEntryRef File, bool AllowTextual=false, bool AllowExcluded=false) const
Retrieve the module that corresponds to the given file, if any.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:434
Lexer - This provides a simple interface that turns a text buffer into a stream of tokens.
Definition: Lexer.h:78
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
Definition: Lexer.h:236
void SetCommentRetentionState(bool Mode)
SetCommentRetentionMode - Change the comment retention mode of the lexer to the specified mode.
Definition: Lexer.h:269
static unsigned getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid=nullptr)
getSpelling - This method is used to get the spelling of a token into a preallocated buffer,...
Definition: Lexer.cpp:451
This interface provides a way to observe the actions of the preprocessor as it does its thing.
Definition: PPCallbacks.h:37
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID=FileID())
Callback invoked whenever a source file is entered or exited.
Definition: PPCallbacks.h:50
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:145
SourceManager & getSourceManager() const
HeaderSearch & getHeaderSearchInfo() const
OptionalFileEntryRef LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, ConstSearchDirIterator FromDir, const FileEntry *FromFile, ConstSearchDirIterator *CurDir, SmallVectorImpl< char > *SearchPath, SmallVectorImpl< char > *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool *IsFrameworkFound, bool SkipCache=false, bool OpenFile=true, bool CacheFailures=true)
Given a "foo" or <foo> reference, look up the indicated file.
DiagnosticsEngine & getDiagnostics() const
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
This class handles loading and caching of source files into memory.
unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
bool isLoadedFileID(FileID FID) const
Returns true if FID came from a PCH/Module.
StringRef getFilename(SourceLocation SpellingLoc) const
Return the filename of the file containing a SourceLocation.
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
DiagList::const_iterator const_iterator
std::vector< std::pair< SourceLocation, std::string > > DiagList
const_iterator warn_end() const
const_iterator note_begin() const
const_iterator err_begin() const
const_iterator note_end() const
const_iterator warn_begin() const
const_iterator remark_begin() const
const_iterator remark_end() const
const_iterator err_end() const
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
Definition: Token.h:134
void setKind(tok::TokenKind K)
Definition: Token.h:98
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....
Definition: Token.h:102
bool isNot(tok::TokenKind K) const
Definition: Token.h:103
Directive - Abstract class representing a parsed verify directive.
virtual bool isValid(std::string &Error)=0
static std::unique_ptr< Directive > create(bool RegexKind, SourceLocation DirectiveLoc, SourceLocation DiagnosticLoc, StringRef Spelling, bool MatchAnyFileAndLine, bool MatchAnyLine, StringRef Text, unsigned Min, unsigned Max)
static const unsigned MaxCount
Constant representing n or more matches.
virtual bool match(StringRef S)=0
VerifyDiagnosticConsumer - Create a diagnostic client which will use markers in the input source to c...
void UpdateParsedFileStatus(SourceManager &SM, FileID FID, ParsedStatus PS)
Update lists of parsed and unparsed files.
VerifyDiagnosticConsumer(DiagnosticsEngine &Diags)
Create a new verifying diagnostic client, which will issue errors to the currently-attached diagnosti...
@ IsUnparsed
File has diagnostics and may have directives.
@ IsUnparsedNoDirectives
File has diagnostics but guaranteed no directives.
@ IsParsed
File has been processed via HandleComment.
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP) override
Callback to inform the diagnostic client that processing of a source file is beginning.
std::vector< std::unique_ptr< Directive > > DirectiveList
bool HandleComment(Preprocessor &PP, SourceRange Comment) override
HandleComment - Hook into the preprocessor and extract comments containing expected errors and warnin...
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
Definition: SourceManager.h:81
The JSON file list parser is used to communicate input to InstallAPI.
@ Match
This is not an overload because the signature exactly matches an existing declaration.
DiagnosticLevelMask
A bitmask representing the diagnostic levels used by VerifyDiagnosticConsumer.
@ DType
'dtype' clause, an alias for 'device_type', stored separately for diagnostic purposes.
LLVM_READONLY bool isLetter(unsigned char c)
Return true if this character is an ASCII letter: [a-zA-Z].
Definition: CharInfo.h:132
LLVM_READONLY bool isAlphanumeric(unsigned char c)
Return true if this character is an ASCII letter or digit: [a-zA-Z0-9].
Definition: CharInfo.h:138
LLVM_READONLY bool isDigit(unsigned char c)
Return true if this character is an ASCII digit: [0-9].
Definition: CharInfo.h:114
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
Definition: CharInfo.h:108
ExpectedData - owns directive objects and deletes on destructor.