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