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